| 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 |