OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2006, 2010 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2010 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 using namespace HTMLNames; | 43 using namespace HTMLNames; |
44 | 44 |
45 static Node* enclosingListChild(Node* node, Node* listNode) | 45 static Node* enclosingListChild(Node* node, Node* listNode) |
46 { | 46 { |
47 Node* listChild = enclosingListChild(node); | 47 Node* listChild = enclosingListChild(node); |
48 while (listChild && enclosingList(listChild) != listNode) | 48 while (listChild && enclosingList(listChild) != listNode) |
49 listChild = enclosingListChild(listChild->parentNode()); | 49 listChild = enclosingListChild(listChild->parentNode()); |
50 return listChild; | 50 return listChild; |
51 } | 51 } |
52 | 52 |
53 HTMLUListElement* InsertListCommand::fixOrphanedListChild(Node* node) | 53 HTMLUListElement* InsertListCommand::fixOrphanedListChild(Node* node, EditingSta
te* editingState) |
54 { | 54 { |
55 RefPtrWillBeRawPtr<HTMLUListElement> listElement = HTMLUListElement::create(
document()); | 55 RefPtrWillBeRawPtr<HTMLUListElement> listElement = HTMLUListElement::create(
document()); |
56 insertNodeBefore(listElement, node); | 56 insertNodeBefore(listElement, node, editingState); |
57 removeNode(node); | 57 if (editingState->isAborted()) |
58 appendNode(node, listElement); | 58 return nullptr; |
| 59 removeNode(node, editingState); |
| 60 if (editingState->isAborted()) |
| 61 return nullptr; |
| 62 appendNode(node, listElement, editingState); |
| 63 if (editingState->isAborted()) |
| 64 return nullptr; |
59 return listElement.get(); | 65 return listElement.get(); |
60 } | 66 } |
61 | 67 |
62 PassRefPtrWillBeRawPtr<HTMLElement> InsertListCommand::mergeWithNeighboringLists
(PassRefPtrWillBeRawPtr<HTMLElement> passedList) | 68 PassRefPtrWillBeRawPtr<HTMLElement> InsertListCommand::mergeWithNeighboringLists
(PassRefPtrWillBeRawPtr<HTMLElement> passedList, EditingState* editingState) |
63 { | 69 { |
64 RefPtrWillBeRawPtr<HTMLElement> list = passedList; | 70 RefPtrWillBeRawPtr<HTMLElement> list = passedList; |
65 Element* previousList = ElementTraversal::previousSibling(*list); | 71 Element* previousList = ElementTraversal::previousSibling(*list); |
66 if (canMergeLists(previousList, list.get())) | 72 if (canMergeLists(previousList, list.get())) { |
67 mergeIdenticalElements(previousList, list); | 73 mergeIdenticalElements(previousList, list, editingState); |
| 74 if (editingState->isAborted()) |
| 75 return nullptr; |
| 76 } |
68 | 77 |
69 if (!list) | 78 if (!list) |
70 return nullptr; | 79 return nullptr; |
71 | 80 |
72 Element* nextSibling = ElementTraversal::nextSibling(*list); | 81 Element* nextSibling = ElementTraversal::nextSibling(*list); |
73 if (!nextSibling || !nextSibling->isHTMLElement()) | 82 if (!nextSibling || !nextSibling->isHTMLElement()) |
74 return list.release(); | 83 return list.release(); |
75 | 84 |
76 RefPtrWillBeRawPtr<HTMLElement> nextList = toHTMLElement(nextSibling); | 85 RefPtrWillBeRawPtr<HTMLElement> nextList = toHTMLElement(nextSibling); |
77 if (canMergeLists(list.get(), nextList.get())) { | 86 if (canMergeLists(list.get(), nextList.get())) { |
78 mergeIdenticalElements(list, nextList); | 87 mergeIdenticalElements(list, nextList, editingState); |
| 88 if (editingState->isAborted()) |
| 89 return nullptr; |
79 return nextList.release(); | 90 return nextList.release(); |
80 } | 91 } |
81 return list.release(); | 92 return list.release(); |
82 } | 93 } |
83 | 94 |
84 bool InsertListCommand::selectionHasListOfType(const VisibleSelection& selection
, const HTMLQualifiedName& listTag) | 95 bool InsertListCommand::selectionHasListOfType(const VisibleSelection& selection
, const HTMLQualifiedName& listTag) |
85 { | 96 { |
86 VisiblePosition start = selection.visibleStart(); | 97 VisiblePosition start = selection.visibleStart(); |
87 | 98 |
88 if (!enclosingList(start.deepEquivalent().anchorNode())) | 99 if (!enclosingList(start.deepEquivalent().anchorNode())) |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 // out from |listElement|. | 241 // out from |listElement|. |
231 return false; | 242 return false; |
232 } | 243 } |
233 if (!listElement->parentNode()->hasEditableStyle()) { | 244 if (!listElement->parentNode()->hasEditableStyle()) { |
234 // Since parent of |listElement| is uneditable, we can not remov
e | 245 // Since parent of |listElement| is uneditable, we can not remov
e |
235 // |listElement| for switching list type neither unlistify. | 246 // |listElement| for switching list type neither unlistify. |
236 return false; | 247 return false; |
237 } | 248 } |
238 } | 249 } |
239 if (!listElement) { | 250 if (!listElement) { |
240 listElement = fixOrphanedListChild(listChildNode); | 251 listElement = fixOrphanedListChild(listChildNode, editingState); |
241 listElement = mergeWithNeighboringLists(listElement); | 252 if (editingState->isAborted()) |
| 253 return false; |
| 254 listElement = mergeWithNeighboringLists(listElement, editingState); |
| 255 if (editingState->isAborted()) |
| 256 return false; |
242 } | 257 } |
243 ASSERT(listElement->hasEditableStyle()); | 258 ASSERT(listElement->hasEditableStyle()); |
244 ASSERT(listElement->parentNode()->hasEditableStyle()); | 259 ASSERT(listElement->parentNode()->hasEditableStyle()); |
245 if (!listElement->hasTagName(listTag)) { | 260 if (!listElement->hasTagName(listTag)) { |
246 // |listChildNode| will be removed from the list and a list of type | 261 // |listChildNode| will be removed from the list and a list of type |
247 // |m_type| will be created. | 262 // |m_type| will be created. |
248 switchListType = true; | 263 switchListType = true; |
249 } | 264 } |
250 | 265 |
251 // If the list is of the desired type, and we are not removing the list, | 266 // If the list is of the desired type, and we are not removing the list, |
252 // then exit early. | 267 // then exit early. |
253 if (!switchListType && forceCreateList) | 268 if (!switchListType && forceCreateList) |
254 return true; | 269 return true; |
255 | 270 |
256 // If the entire list is selected, then convert the whole list. | 271 // If the entire list is selected, then convert the whole list. |
257 if (switchListType && isNodeVisiblyContainedWithin(*listElement, current
Selection)) { | 272 if (switchListType && isNodeVisiblyContainedWithin(*listElement, current
Selection)) { |
258 bool rangeStartIsInList = visiblePositionBeforeNode(*listElement).de
epEquivalent() == createVisiblePosition(currentSelection.startPosition()).deepEq
uivalent(); | 273 bool rangeStartIsInList = visiblePositionBeforeNode(*listElement).de
epEquivalent() == createVisiblePosition(currentSelection.startPosition()).deepEq
uivalent(); |
259 bool rangeEndIsInList = visiblePositionAfterNode(*listElement).deepE
quivalent() == createVisiblePosition(currentSelection.endPosition()).deepEquival
ent(); | 274 bool rangeEndIsInList = visiblePositionAfterNode(*listElement).deepE
quivalent() == createVisiblePosition(currentSelection.endPosition()).deepEquival
ent(); |
260 | 275 |
261 RefPtrWillBeRawPtr<HTMLElement> newList = createHTMLElement(document
(), listTag); | 276 RefPtrWillBeRawPtr<HTMLElement> newList = createHTMLElement(document
(), listTag); |
262 insertNodeBefore(newList, listElement); | 277 insertNodeBefore(newList, listElement, editingState); |
| 278 if (editingState->isAborted()) |
| 279 return false; |
263 | 280 |
264 Node* firstChildInList = enclosingListChild(createVisiblePosition(fi
rstPositionInNode(listElement.get())).deepEquivalent().anchorNode(), listElement
.get()); | 281 Node* firstChildInList = enclosingListChild(createVisiblePosition(fi
rstPositionInNode(listElement.get())).deepEquivalent().anchorNode(), listElement
.get()); |
265 Element* outerBlock = firstChildInList && isBlockFlowElement(*firstC
hildInList) ? toElement(firstChildInList) : listElement.get(); | 282 Element* outerBlock = firstChildInList && isBlockFlowElement(*firstC
hildInList) ? toElement(firstChildInList) : listElement.get(); |
266 | 283 |
267 moveParagraphWithClones(createVisiblePosition(firstPositionInNode(li
stElement.get())), createVisiblePosition(lastPositionInNode(listElement.get())),
newList.get(), outerBlock); | 284 moveParagraphWithClones(createVisiblePosition(firstPositionInNode(li
stElement.get())), createVisiblePosition(lastPositionInNode(listElement.get())),
newList.get(), outerBlock, editingState); |
| 285 if (editingState->isAborted()) |
| 286 return false; |
268 | 287 |
269 // Manually remove listNode because moveParagraphWithClones sometime
s leaves it behind in the document. | 288 // Manually remove listNode because moveParagraphWithClones sometime
s leaves it behind in the document. |
270 // See the bug 33668 and editing/execCommand/insert-list-orphaned-it
em-with-nested-lists.html. | 289 // See the bug 33668 and editing/execCommand/insert-list-orphaned-it
em-with-nested-lists.html. |
271 // FIXME: This might be a bug in moveParagraphWithClones or deleteSe
lection. | 290 // FIXME: This might be a bug in moveParagraphWithClones or deleteSe
lection. |
272 if (listElement && listElement->inDocument()) | 291 if (listElement && listElement->inDocument()) { |
273 removeNode(listElement); | 292 removeNode(listElement, editingState); |
| 293 if (editingState->isAborted()) |
| 294 return false; |
| 295 } |
274 | 296 |
275 newList = mergeWithNeighboringLists(newList); | 297 newList = mergeWithNeighboringLists(newList, editingState); |
| 298 if (editingState->isAborted()) |
| 299 return false; |
276 | 300 |
277 // Restore the start and the end of current selection if they starte
d inside listNode | 301 // Restore the start and the end of current selection if they starte
d inside listNode |
278 // because moveParagraphWithClones could have removed them. | 302 // because moveParagraphWithClones could have removed them. |
279 if (rangeStartIsInList && newList) | 303 if (rangeStartIsInList && newList) |
280 currentSelection.setStart(newList, 0, IGNORE_EXCEPTION); | 304 currentSelection.setStart(newList, 0, IGNORE_EXCEPTION); |
281 if (rangeEndIsInList && newList) | 305 if (rangeEndIsInList && newList) |
282 currentSelection.setEnd(newList, lastOffsetInNode(newList.get())
, IGNORE_EXCEPTION); | 306 currentSelection.setEnd(newList, lastOffsetInNode(newList.get())
, IGNORE_EXCEPTION); |
283 | 307 |
284 setEndingSelection(createVisiblePosition(firstPositionInNode(newList
.get()))); | 308 setEndingSelection(createVisiblePosition(firstPositionInNode(newList
.get()))); |
285 | 309 |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 else | 418 else |
395 insertNodeAt(listItemElement, Position::beforeNode(nextList), editin
gState); | 419 insertNodeAt(listItemElement, Position::beforeNode(nextList), editin
gState); |
396 if (editingState->isAborted()) | 420 if (editingState->isAborted()) |
397 return; | 421 return; |
398 | 422 |
399 moveParagraphOverPositionIntoEmptyListItem(start, listItemElement, editi
ngState); | 423 moveParagraphOverPositionIntoEmptyListItem(start, listItemElement, editi
ngState); |
400 if (editingState->isAborted()) | 424 if (editingState->isAborted()) |
401 return; | 425 return; |
402 | 426 |
403 if (canMergeLists(previousList, nextList)) | 427 if (canMergeLists(previousList, nextList)) |
404 mergeIdenticalElements(previousList, nextList); | 428 mergeIdenticalElements(previousList, nextList, editingState); |
405 | 429 |
406 return; | 430 return; |
407 } | 431 } |
408 | 432 |
409 // Create new list element. | 433 // Create new list element. |
410 | 434 |
411 // Inserting the list into an empty paragraph that isn't held open | 435 // Inserting the list into an empty paragraph that isn't held open |
412 // by a br or a '\n', will invalidate start and end. Insert | 436 // by a br or a '\n', will invalidate start and end. Insert |
413 // a placeholder and then recompute start and end. | 437 // a placeholder and then recompute start and end. |
414 Position startPos = start.deepEquivalent(); | 438 Position startPos = start.deepEquivalent(); |
(...skipping 26 matching lines...) Expand all Loading... |
441 // Update the start of content, so we don't try to move the list into itself
. bug 19066 | 465 // Update the start of content, so we don't try to move the list into itself
. bug 19066 |
442 // Layout is necessary since start's node's inline layoutObjects may have be
en destroyed by the insertion | 466 // Layout is necessary since start's node's inline layoutObjects may have be
en destroyed by the insertion |
443 // The end of the content may have changed after the insertion and layout so
update it as well. | 467 // The end of the content may have changed after the insertion and layout so
update it as well. |
444 if (insertionPos == startPos) | 468 if (insertionPos == startPos) |
445 moveParagraphOverPositionIntoEmptyListItem(originalStart, listItemElemen
t, editingState); | 469 moveParagraphOverPositionIntoEmptyListItem(originalStart, listItemElemen
t, editingState); |
446 else | 470 else |
447 moveParagraphOverPositionIntoEmptyListItem(createVisiblePosition(startPo
s), listItemElement, editingState); | 471 moveParagraphOverPositionIntoEmptyListItem(createVisiblePosition(startPo
s), listItemElement, editingState); |
448 if (editingState->isAborted()) | 472 if (editingState->isAborted()) |
449 return; | 473 return; |
450 | 474 |
451 mergeWithNeighboringLists(listElement); | 475 mergeWithNeighboringLists(listElement, editingState); |
452 } | 476 } |
453 | 477 |
454 void InsertListCommand::moveParagraphOverPositionIntoEmptyListItem(const Visible
Position& pos, PassRefPtrWillBeRawPtr<HTMLLIElement> listItemElement, EditingSta
te* editingState) | 478 void InsertListCommand::moveParagraphOverPositionIntoEmptyListItem(const Visible
Position& pos, PassRefPtrWillBeRawPtr<HTMLLIElement> listItemElement, EditingSta
te* editingState) |
455 { | 479 { |
456 ASSERT(!listItemElement->hasChildren()); | 480 ASSERT(!listItemElement->hasChildren()); |
457 const RefPtrWillBeRawPtr<HTMLBRElement> placeholder = HTMLBRElement::create(
document()); | 481 const RefPtrWillBeRawPtr<HTMLBRElement> placeholder = HTMLBRElement::create(
document()); |
458 appendNode(placeholder, listItemElement, editingState); | 482 appendNode(placeholder, listItemElement, editingState); |
459 if (editingState->isAborted()) | 483 if (editingState->isAborted()) |
460 return; | 484 return; |
461 // Inserting list element and list item list may change start of pargraph | 485 // Inserting list element and list item list may change start of pargraph |
462 // to move. We calculate start of paragraph again. | 486 // to move. We calculate start of paragraph again. |
463 document().updateLayoutIgnorePendingStylesheets(); | 487 document().updateLayoutIgnorePendingStylesheets(); |
464 const VisiblePosition& start = startOfParagraph(pos, CanSkipOverEditingBound
ary); | 488 const VisiblePosition& start = startOfParagraph(pos, CanSkipOverEditingBound
ary); |
465 const VisiblePosition& end = endOfParagraph(pos, CanSkipOverEditingBoundary)
; | 489 const VisiblePosition& end = endOfParagraph(pos, CanSkipOverEditingBoundary)
; |
466 moveParagraph(start, end, createVisiblePosition(positionBeforeNode(placehold
er.get())), editingState, true); | 490 moveParagraph(start, end, createVisiblePosition(positionBeforeNode(placehold
er.get())), editingState, true); |
467 } | 491 } |
468 | 492 |
469 DEFINE_TRACE(InsertListCommand) | 493 DEFINE_TRACE(InsertListCommand) |
470 { | 494 { |
471 CompositeEditCommand::trace(visitor); | 495 CompositeEditCommand::trace(visitor); |
472 } | 496 } |
473 | 497 |
474 } // namespace blink | 498 } // namespace blink |
OLD | NEW |