OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006, 2007, 2008 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 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 // |AppendNodeCommand|. | 381 // |AppendNodeCommand|. |
382 // TODO(yosin): We should get rid of |canHaveChildrenForEditing()|, since | 382 // TODO(yosin): We should get rid of |canHaveChildrenForEditing()|, since |
383 // |cloneParagraphUnderNewElement()| attempt to clone non-well-formed HTML, | 383 // |cloneParagraphUnderNewElement()| attempt to clone non-well-formed HTML, |
384 // produced by JavaScript. | 384 // produced by JavaScript. |
385 ASSERT_IN_EDITING_COMMAND(canHaveChildrenForEditing(parent.get()) | 385 ASSERT_IN_EDITING_COMMAND(canHaveChildrenForEditing(parent.get()) |
386 || (parent->isElementNode() && toElement(parent.get())->tagQName() == ob
jectTag)); | 386 || (parent->isElementNode() && toElement(parent.get())->tagQName() == ob
jectTag)); |
387 ASSERT_IN_EDITING_COMMAND(parent->hasEditableStyle() || !parent->inActiveDoc
ument()); | 387 ASSERT_IN_EDITING_COMMAND(parent->hasEditableStyle() || !parent->inActiveDoc
ument()); |
388 applyCommandToComposite(AppendNodeCommand::create(parent, node)); | 388 applyCommandToComposite(AppendNodeCommand::create(parent, node)); |
389 } | 389 } |
390 | 390 |
391 void CompositeEditCommand::removeChildrenInRange(PassRefPtrWillBeRawPtr<Node> no
de, unsigned from, unsigned to) | 391 void CompositeEditCommand::removeChildrenInRange(PassRefPtrWillBeRawPtr<Node> no
de, unsigned from, unsigned to, EditingState* editingState) |
392 { | 392 { |
393 WillBeHeapVector<RefPtrWillBeMember<Node>> children; | 393 WillBeHeapVector<RefPtrWillBeMember<Node>> children; |
394 Node* child = NodeTraversal::childAt(*node, from); | 394 Node* child = NodeTraversal::childAt(*node, from); |
395 for (unsigned i = from; child && i < to; i++, child = child->nextSibling()) | 395 for (unsigned i = from; child && i < to; i++, child = child->nextSibling()) |
396 children.append(child); | 396 children.append(child); |
397 | 397 |
398 size_t size = children.size(); | 398 size_t size = children.size(); |
399 for (size_t i = 0; i < size; ++i) | 399 for (size_t i = 0; i < size; ++i) { |
400 removeNode(children[i].release()); | 400 removeNode(children[i].release(), editingState); |
| 401 if (editingState->isAborted()) |
| 402 return; |
| 403 } |
401 } | 404 } |
402 | 405 |
403 void CompositeEditCommand::removeNode(PassRefPtrWillBeRawPtr<Node> node, Editing
State* editingState, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIsAl
waysEditable) | 406 void CompositeEditCommand::removeNode(PassRefPtrWillBeRawPtr<Node> node, Editing
State* editingState, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIsAl
waysEditable) |
404 { | 407 { |
405 if (!node || !node->nonShadowBoundaryParentNode()) | 408 if (!node || !node->nonShadowBoundaryParentNode()) |
406 return; | 409 return; |
407 ASSERT_IN_EDITING_COMMAND(node->document().frame()); | 410 ASSERT_IN_EDITING_COMMAND(node->document().frame()); |
408 applyCommandToComposite(RemoveNodeCommand::create(node, shouldAssumeContentI
sAlwaysEditable), editingState); | 411 applyCommandToComposite(RemoveNodeCommand::create(node, shouldAssumeContentI
sAlwaysEditable), editingState); |
409 } | 412 } |
410 | 413 |
411 void CompositeEditCommand::removeNodePreservingChildren(PassRefPtrWillBeRawPtr<N
ode> node, EditingState* editingState, ShouldAssumeContentIsAlwaysEditable shoul
dAssumeContentIsAlwaysEditable) | 414 void CompositeEditCommand::removeNodePreservingChildren(PassRefPtrWillBeRawPtr<N
ode> node, EditingState* editingState, ShouldAssumeContentIsAlwaysEditable shoul
dAssumeContentIsAlwaysEditable) |
412 { | 415 { |
413 ASSERT_IN_EDITING_COMMAND(node->document().frame()); | 416 ASSERT_IN_EDITING_COMMAND(node->document().frame()); |
414 applyCommandToComposite(RemoveNodePreservingChildrenCommand::create(node, sh
ouldAssumeContentIsAlwaysEditable), editingState); | 417 applyCommandToComposite(RemoveNodePreservingChildrenCommand::create(node, sh
ouldAssumeContentIsAlwaysEditable), editingState); |
415 } | 418 } |
416 | 419 |
417 void CompositeEditCommand::removeNodeAndPruneAncestors(PassRefPtrWillBeRawPtr<No
de> node, Node* excludeNode) | 420 void CompositeEditCommand::removeNodeAndPruneAncestors(PassRefPtrWillBeRawPtr<No
de> node, EditingState* editingState, Node* excludeNode) |
418 { | 421 { |
419 ASSERT(node.get() != excludeNode); | 422 ASSERT(node.get() != excludeNode); |
420 RefPtrWillBeRawPtr<ContainerNode> parent = node->parentNode(); | 423 RefPtrWillBeRawPtr<ContainerNode> parent = node->parentNode(); |
421 removeNode(node); | 424 removeNode(node, editingState); |
422 prune(parent.release(), excludeNode); | 425 if (editingState->isAborted()) |
| 426 return; |
| 427 prune(parent.release(), editingState, excludeNode); |
423 } | 428 } |
424 | 429 |
425 void CompositeEditCommand::moveRemainingSiblingsToNewParent(Node* node, Node* pa
stLastNodeToMove, PassRefPtrWillBeRawPtr<Element> prpNewParent) | 430 void CompositeEditCommand::moveRemainingSiblingsToNewParent(Node* node, Node* pa
stLastNodeToMove, PassRefPtrWillBeRawPtr<Element> prpNewParent, EditingState* ed
itingState) |
426 { | 431 { |
427 NodeVector nodesToRemove; | 432 NodeVector nodesToRemove; |
428 RefPtrWillBeRawPtr<Element> newParent = prpNewParent; | 433 RefPtrWillBeRawPtr<Element> newParent = prpNewParent; |
429 | 434 |
430 for (; node && node != pastLastNodeToMove; node = node->nextSibling()) | 435 for (; node && node != pastLastNodeToMove; node = node->nextSibling()) |
431 nodesToRemove.append(node); | 436 nodesToRemove.append(node); |
432 | 437 |
433 for (unsigned i = 0; i < nodesToRemove.size(); i++) { | 438 for (unsigned i = 0; i < nodesToRemove.size(); i++) { |
434 removeNode(nodesToRemove[i]); | 439 removeNode(nodesToRemove[i], editingState); |
435 appendNode(nodesToRemove[i], newParent); | 440 if (editingState->isAborted()) |
| 441 return; |
| 442 appendNode(nodesToRemove[i], newParent, editingState); |
| 443 if (editingState->isAborted()) |
| 444 return; |
436 } | 445 } |
437 } | 446 } |
438 | 447 |
439 void CompositeEditCommand::updatePositionForNodeRemovalPreservingChildren(Positi
on& position, Node& node) | 448 void CompositeEditCommand::updatePositionForNodeRemovalPreservingChildren(Positi
on& position, Node& node) |
440 { | 449 { |
441 int offset = position.isOffsetInAnchor() ? position.offsetInContainerNode()
: 0; | 450 int offset = position.isOffsetInAnchor() ? position.offsetInContainerNode()
: 0; |
442 updatePositionForNodeRemoval(position, node); | 451 updatePositionForNodeRemoval(position, node); |
443 if (offset == 0) | 452 if (offset == 0) |
444 return; | 453 return; |
445 position = Position(position.computeContainerNode(), offset); | 454 position = Position(position.computeContainerNode(), offset); |
446 } | 455 } |
447 | 456 |
448 HTMLSpanElement* CompositeEditCommand::replaceElementWithSpanPreservingChildrenA
ndAttributes(PassRefPtrWillBeRawPtr<HTMLElement> node) | 457 HTMLSpanElement* CompositeEditCommand::replaceElementWithSpanPreservingChildrenA
ndAttributes(PassRefPtrWillBeRawPtr<HTMLElement> node) |
449 { | 458 { |
450 // It would also be possible to implement all of ReplaceNodeWithSpanCommand | 459 // It would also be possible to implement all of ReplaceNodeWithSpanCommand |
451 // as a series of existing smaller edit commands. Someone who wanted to | 460 // as a series of existing smaller edit commands. Someone who wanted to |
452 // reduce the number of edit commands could do so here. | 461 // reduce the number of edit commands could do so here. |
453 RefPtrWillBeRawPtr<ReplaceNodeWithSpanCommand> command = ReplaceNodeWithSpan
Command::create(node); | 462 RefPtrWillBeRawPtr<ReplaceNodeWithSpanCommand> command = ReplaceNodeWithSpan
Command::create(node); |
454 applyCommandToComposite(command); | 463 applyCommandToComposite(command); |
455 // Returning a raw pointer here is OK because the command is retained by | 464 // Returning a raw pointer here is OK because the command is retained by |
456 // applyCommandToComposite (thus retaining the span), and the span is also | 465 // applyCommandToComposite (thus retaining the span), and the span is also |
457 // in the DOM tree, and thus alive whie it has a parent. | 466 // in the DOM tree, and thus alive whie it has a parent. |
458 ASSERT(command->spanElement()->inDocument()); | 467 ASSERT(command->spanElement()->inDocument()); |
459 return command->spanElement(); | 468 return command->spanElement(); |
460 } | 469 } |
461 | 470 |
462 void CompositeEditCommand::prune(PassRefPtrWillBeRawPtr<Node> node, Node* exclud
eNode) | 471 void CompositeEditCommand::prune(PassRefPtrWillBeRawPtr<Node> node, EditingState
* editingState, Node* excludeNode) |
463 { | 472 { |
464 if (RefPtrWillBeRawPtr<Node> highestNodeToRemove = highestNodeToRemoveInPrun
ing(node.get(), excludeNode)) | 473 if (RefPtrWillBeRawPtr<Node> highestNodeToRemove = highestNodeToRemoveInPrun
ing(node.get(), excludeNode)) |
465 removeNode(highestNodeToRemove.release()); | 474 removeNode(highestNodeToRemove.release(), editingState); |
466 } | 475 } |
467 | 476 |
468 void CompositeEditCommand::splitTextNode(PassRefPtrWillBeRawPtr<Text> node, unsi
gned offset) | 477 void CompositeEditCommand::splitTextNode(PassRefPtrWillBeRawPtr<Text> node, unsi
gned offset) |
469 { | 478 { |
470 applyCommandToComposite(SplitTextNodeCommand::create(node, offset)); | 479 applyCommandToComposite(SplitTextNodeCommand::create(node, offset)); |
471 } | 480 } |
472 | 481 |
473 void CompositeEditCommand::splitElement(PassRefPtrWillBeRawPtr<Element> element,
PassRefPtrWillBeRawPtr<Node> atChild) | 482 void CompositeEditCommand::splitElement(PassRefPtrWillBeRawPtr<Element> element,
PassRefPtrWillBeRawPtr<Node> atChild) |
474 { | 483 { |
475 applyCommandToComposite(SplitElementCommand::create(element, atChild)); | 484 applyCommandToComposite(SplitElementCommand::create(element, atChild)); |
476 } | 485 } |
477 | 486 |
478 void CompositeEditCommand::mergeIdenticalElements(PassRefPtrWillBeRawPtr<Element
> prpFirst, PassRefPtrWillBeRawPtr<Element> prpSecond) | 487 void CompositeEditCommand::mergeIdenticalElements(PassRefPtrWillBeRawPtr<Element
> prpFirst, PassRefPtrWillBeRawPtr<Element> prpSecond, EditingState* editingStat
e) |
479 { | 488 { |
480 RefPtrWillBeRawPtr<Element> first = prpFirst; | 489 RefPtrWillBeRawPtr<Element> first = prpFirst; |
481 RefPtrWillBeRawPtr<Element> second = prpSecond; | 490 RefPtrWillBeRawPtr<Element> second = prpSecond; |
482 ASSERT(!first->isDescendantOf(second.get()) && second != first); | 491 ASSERT(!first->isDescendantOf(second.get()) && second != first); |
483 if (first->nextSibling() != second) { | 492 if (first->nextSibling() != second) { |
484 removeNode(second); | 493 removeNode(second, editingState); |
| 494 if (editingState->isAborted()) |
| 495 return; |
485 insertNodeAfter(second, first); | 496 insertNodeAfter(second, first); |
486 } | 497 } |
487 applyCommandToComposite(MergeIdenticalElementsCommand::create(first, second)
); | 498 applyCommandToComposite(MergeIdenticalElementsCommand::create(first, second)
, editingState); |
488 } | 499 } |
489 | 500 |
490 void CompositeEditCommand::wrapContentsInDummySpan(PassRefPtrWillBeRawPtr<Elemen
t> element) | 501 void CompositeEditCommand::wrapContentsInDummySpan(PassRefPtrWillBeRawPtr<Elemen
t> element) |
491 { | 502 { |
492 applyCommandToComposite(WrapContentsInDummySpanCommand::create(element)); | 503 applyCommandToComposite(WrapContentsInDummySpanCommand::create(element)); |
493 } | 504 } |
494 | 505 |
495 void CompositeEditCommand::splitTextNodeContainingElement(PassRefPtrWillBeRawPtr
<Text> text, unsigned offset) | 506 void CompositeEditCommand::splitTextNodeContainingElement(PassRefPtrWillBeRawPtr
<Text> text, unsigned offset) |
496 { | 507 { |
497 applyCommandToComposite(SplitTextNodeContainingElementCommand::create(text,
offset)); | 508 applyCommandToComposite(SplitTextNodeContainingElementCommand::create(text,
offset)); |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 sortedTextBoxes.append(textBox); | 780 sortedTextBoxes.append(textBox); |
770 | 781 |
771 // If there is mixed directionality text, the boxes can be out of order, | 782 // If there is mixed directionality text, the boxes can be out of order, |
772 // (like Arabic with embedded LTR), so sort them first. | 783 // (like Arabic with embedded LTR), so sort them first. |
773 if (textLayoutObject->containsReversedText()) | 784 if (textLayoutObject->containsReversedText()) |
774 std::sort(sortedTextBoxes.begin(), sortedTextBoxes.end(), InlineTextBox:
:compareByStart); | 785 std::sort(sortedTextBoxes.begin(), sortedTextBoxes.end(), InlineTextBox:
:compareByStart); |
775 InlineTextBox* box = sortedTextBoxes.isEmpty() ? 0 : sortedTextBoxes[sortedT
extBoxesPosition]; | 786 InlineTextBox* box = sortedTextBoxes.isEmpty() ? 0 : sortedTextBoxes[sortedT
extBoxesPosition]; |
776 | 787 |
777 if (!box) { | 788 if (!box) { |
778 // whole text node is empty | 789 // whole text node is empty |
779 removeNode(textNode); | 790 // Removing a Text node won't dispatch synchronous events. |
| 791 removeNode(textNode, ASSERT_NO_EDITING_ABORT); |
780 return; | 792 return; |
781 } | 793 } |
782 | 794 |
783 unsigned length = textNode->length(); | 795 unsigned length = textNode->length(); |
784 if (start >= length || end > length) | 796 if (start >= length || end > length) |
785 return; | 797 return; |
786 | 798 |
787 unsigned removed = 0; | 799 unsigned removed = 0; |
788 InlineTextBox* prevBox = nullptr; | 800 InlineTextBox* prevBox = nullptr; |
789 String str; | 801 String str; |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
910 return nullptr; | 922 return nullptr; |
911 } | 923 } |
912 | 924 |
913 // Assumes that the position is at a placeholder and does the removal without mu
ch checking. | 925 // Assumes that the position is at a placeholder and does the removal without mu
ch checking. |
914 void CompositeEditCommand::removePlaceholderAt(const Position& p) | 926 void CompositeEditCommand::removePlaceholderAt(const Position& p) |
915 { | 927 { |
916 ASSERT(lineBreakExistsAtPosition(p)); | 928 ASSERT(lineBreakExistsAtPosition(p)); |
917 | 929 |
918 // We are certain that the position is at a line break, but it may be a br o
r a preserved newline. | 930 // We are certain that the position is at a line break, but it may be a br o
r a preserved newline. |
919 if (isHTMLBRElement(*p.anchorNode())) { | 931 if (isHTMLBRElement(*p.anchorNode())) { |
920 removeNode(p.anchorNode()); | 932 // Removing a BR element won't dispatch synchronous events. |
| 933 removeNode(p.anchorNode(), ASSERT_NO_EDITING_ABORT); |
921 return; | 934 return; |
922 } | 935 } |
923 | 936 |
924 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); | 937 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); |
925 } | 938 } |
926 | 939 |
927 PassRefPtrWillBeRawPtr<HTMLElement> CompositeEditCommand::insertNewDefaultParagr
aphElementAt(const Position& position) | 940 PassRefPtrWillBeRawPtr<HTMLElement> CompositeEditCommand::insertNewDefaultParagr
aphElementAt(const Position& position) |
928 { | 941 { |
929 RefPtrWillBeRawPtr<HTMLElement> paragraphElement = createDefaultParagraphEle
ment(document()); | 942 RefPtrWillBeRawPtr<HTMLElement> paragraphElement = createDefaultParagraphEle
ment(document()); |
930 paragraphElement->appendChild(HTMLBRElement::create(document())); | 943 paragraphElement->appendChild(HTMLBRElement::create(document())); |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1100 } | 1113 } |
1101 } | 1114 } |
1102 | 1115 |
1103 | 1116 |
1104 // There are bugs in deletion when it removes a fully selected table/list. | 1117 // There are bugs in deletion when it removes a fully selected table/list. |
1105 // It expands and removes the entire table/list, but will let content | 1118 // It expands and removes the entire table/list, but will let content |
1106 // before and after the table/list collapse onto one line. | 1119 // before and after the table/list collapse onto one line. |
1107 // Deleting a paragraph will leave a placeholder. Remove it (and prune | 1120 // Deleting a paragraph will leave a placeholder. Remove it (and prune |
1108 // empty or unrendered parents). | 1121 // empty or unrendered parents). |
1109 | 1122 |
1110 void CompositeEditCommand::cleanupAfterDeletion(VisiblePosition destination) | 1123 void CompositeEditCommand::cleanupAfterDeletion(EditingState* editingState, Visi
blePosition destination) |
1111 { | 1124 { |
1112 VisiblePosition caretAfterDelete = endingSelection().visibleStart(); | 1125 VisiblePosition caretAfterDelete = endingSelection().visibleStart(); |
1113 Node* destinationNode = destination.deepEquivalent().anchorNode(); | 1126 Node* destinationNode = destination.deepEquivalent().anchorNode(); |
1114 if (caretAfterDelete.deepEquivalent() != destination.deepEquivalent() && isS
tartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) { | 1127 if (caretAfterDelete.deepEquivalent() != destination.deepEquivalent() && isS
tartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) { |
1115 // Note: We want the rightmost candidate. | 1128 // Note: We want the rightmost candidate. |
1116 Position position = mostForwardCaretPosition(caretAfterDelete.deepEquiva
lent()); | 1129 Position position = mostForwardCaretPosition(caretAfterDelete.deepEquiva
lent()); |
1117 Node* node = position.anchorNode(); | 1130 Node* node = position.anchorNode(); |
1118 | 1131 |
1119 // Bail if we'd remove an ancestor of our destination. | 1132 // Bail if we'd remove an ancestor of our destination. |
1120 if (destinationNode && destinationNode->isDescendantOf(node)) | 1133 if (destinationNode && destinationNode->isDescendantOf(node)) |
1121 return; | 1134 return; |
1122 | 1135 |
1123 // Normally deletion will leave a br as a placeholder. | 1136 // Normally deletion will leave a br as a placeholder. |
1124 if (isHTMLBRElement(*node)) { | 1137 if (isHTMLBRElement(*node)) { |
1125 removeNodeAndPruneAncestors(node, destinationNode); | 1138 removeNodeAndPruneAncestors(node, editingState, destinationNode); |
1126 | 1139 |
1127 // If the selection to move was empty and in an empty block that | 1140 // If the selection to move was empty and in an empty block that |
1128 // doesn't require a placeholder to prop itself open (like a bordere
d | 1141 // doesn't require a placeholder to prop itself open (like a bordere
d |
1129 // div or an li), remove it during the move (the list removal code | 1142 // div or an li), remove it during the move (the list removal code |
1130 // expects this behavior). | 1143 // expects this behavior). |
1131 } else if (isEnclosingBlock(node)) { | 1144 } else if (isEnclosingBlock(node)) { |
1132 // If caret position after deletion and destination position coincid
es, | 1145 // If caret position after deletion and destination position coincid
es, |
1133 // node should not be removed. | 1146 // node should not be removed. |
1134 if (!rendersInDifferentPosition(position, destination.deepEquivalent
())) { | 1147 if (!rendersInDifferentPosition(position, destination.deepEquivalent
())) { |
1135 prune(node, destinationNode); | 1148 prune(node, editingState, destinationNode); |
1136 return; | 1149 return; |
1137 } | 1150 } |
1138 removeNodeAndPruneAncestors(node, destinationNode); | 1151 removeNodeAndPruneAncestors(node, editingState, destinationNode); |
1139 } else if (lineBreakExistsAtPosition(position)) { | 1152 } else if (lineBreakExistsAtPosition(position)) { |
1140 // There is a preserved '\n' at caretAfterDelete. | 1153 // There is a preserved '\n' at caretAfterDelete. |
1141 // We can safely assume this is a text node. | 1154 // We can safely assume this is a text node. |
1142 Text* textNode = toText(node); | 1155 Text* textNode = toText(node); |
1143 if (textNode->length() == 1) | 1156 if (textNode->length() == 1) |
1144 removeNodeAndPruneAncestors(node, destinationNode); | 1157 removeNodeAndPruneAncestors(node, editingState, destinationNode)
; |
1145 else | 1158 else |
1146 deleteTextFromNode(textNode, position.computeOffsetInContainerNo
de(), 1); | 1159 deleteTextFromNode(textNode, position.computeOffsetInContainerNo
de(), 1); |
1147 } | 1160 } |
1148 } | 1161 } |
1149 } | 1162 } |
1150 | 1163 |
1151 // This is a version of moveParagraph that preserves style by keeping the origin
al markup | 1164 // This is a version of moveParagraph that preserves style by keeping the origin
al markup |
1152 // It is currently used only by IndentOutdentCommand but it is meant to be used
in the | 1165 // It is currently used only by IndentOutdentCommand but it is meant to be used
in the |
1153 // future by several other commands such as InsertList and the align commands. | 1166 // future by several other commands such as InsertList and the align commands. |
1154 // The blockElement parameter is the element to move the paragraph to, | 1167 // The blockElement parameter is the element to move the paragraph to, |
(...skipping 18 matching lines...) Expand all Loading... |
1173 | 1186 |
1174 setEndingSelection(VisibleSelection(start, end)); | 1187 setEndingSelection(VisibleSelection(start, end)); |
1175 deleteSelection(editingState, false, false, false); | 1188 deleteSelection(editingState, false, false, false); |
1176 if (editingState->isAborted()) | 1189 if (editingState->isAborted()) |
1177 return; | 1190 return; |
1178 | 1191 |
1179 // There are bugs in deletion when it removes a fully selected table/list. | 1192 // There are bugs in deletion when it removes a fully selected table/list. |
1180 // It expands and removes the entire table/list, but will let content | 1193 // It expands and removes the entire table/list, but will let content |
1181 // before and after the table/list collapse onto one line. | 1194 // before and after the table/list collapse onto one line. |
1182 | 1195 |
1183 cleanupAfterDeletion(); | 1196 cleanupAfterDeletion(editingState); |
| 1197 if (editingState->isAborted()) |
| 1198 return; |
1184 | 1199 |
1185 // Add a br if pruning an empty block level element caused a collapse. For
example: | 1200 // Add a br if pruning an empty block level element caused a collapse. For
example: |
1186 // foo^ | 1201 // foo^ |
1187 // <div>bar</div> | 1202 // <div>bar</div> |
1188 // baz | 1203 // baz |
1189 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. Th
at would | 1204 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. Th
at would |
1190 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. | 1205 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. |
1191 // Must recononicalize these two VisiblePositions after the pruning above. | 1206 // Must recononicalize these two VisiblePositions after the pruning above. |
1192 beforeParagraph = createVisiblePosition(beforeParagraph.deepEquivalent()); | 1207 beforeParagraph = createVisiblePosition(beforeParagraph.deepEquivalent()); |
1193 afterParagraph = createVisiblePosition(afterParagraph.deepEquivalent()); | 1208 afterParagraph = createVisiblePosition(afterParagraph.deepEquivalent()); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1262 | 1277 |
1263 // FIXME (5098931): We should add a new insert action "WebViewInsertActionMo
ved" and call shouldInsertFragment here. | 1278 // FIXME (5098931): We should add a new insert action "WebViewInsertActionMo
ved" and call shouldInsertFragment here. |
1264 | 1279 |
1265 setEndingSelection(VisibleSelection(start, end)); | 1280 setEndingSelection(VisibleSelection(start, end)); |
1266 document().frame()->spellChecker().clearMisspellingsAndBadGrammar(endingSele
ction()); | 1281 document().frame()->spellChecker().clearMisspellingsAndBadGrammar(endingSele
ction()); |
1267 deleteSelection(editingState, false, false, false); | 1282 deleteSelection(editingState, false, false, false); |
1268 if (editingState->isAborted()) | 1283 if (editingState->isAborted()) |
1269 return; | 1284 return; |
1270 | 1285 |
1271 ASSERT(destination.deepEquivalent().inDocument()); | 1286 ASSERT(destination.deepEquivalent().inDocument()); |
1272 cleanupAfterDeletion(destination); | 1287 cleanupAfterDeletion(editingState, destination); |
| 1288 if (editingState->isAborted()) |
| 1289 return; |
1273 ASSERT(destination.deepEquivalent().inDocument()); | 1290 ASSERT(destination.deepEquivalent().inDocument()); |
1274 | 1291 |
1275 // Add a br if pruning an empty block level element caused a collapse. For e
xample: | 1292 // Add a br if pruning an empty block level element caused a collapse. For e
xample: |
1276 // foo^ | 1293 // foo^ |
1277 // <div>bar</div> | 1294 // <div>bar</div> |
1278 // baz | 1295 // baz |
1279 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That
would | 1296 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That
would |
1280 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. | 1297 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. |
1281 // Must recononicalize these two VisiblePositions after the pruning above. | 1298 // Must recononicalize these two VisiblePositions after the pruning above. |
1282 beforeParagraph = createVisiblePosition(beforeParagraph.deepEquivalent()); | 1299 beforeParagraph = createVisiblePosition(beforeParagraph.deepEquivalent()); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1319 EphemeralRange startRange = PlainTextRange(destinationIndex + startIndex).cr
eateRangeForSelection(*documentElement); | 1336 EphemeralRange startRange = PlainTextRange(destinationIndex + startIndex).cr
eateRangeForSelection(*documentElement); |
1320 if (startRange.isNull()) | 1337 if (startRange.isNull()) |
1321 return; | 1338 return; |
1322 EphemeralRange endRange = PlainTextRange(destinationIndex + endIndex).create
RangeForSelection(*documentElement); | 1339 EphemeralRange endRange = PlainTextRange(destinationIndex + endIndex).create
RangeForSelection(*documentElement); |
1323 if (endRange.isNull()) | 1340 if (endRange.isNull()) |
1324 return; | 1341 return; |
1325 setEndingSelection(VisibleSelection(startRange.startPosition(), endRange.sta
rtPosition(), TextAffinity::Downstream, originalIsDirectional)); | 1342 setEndingSelection(VisibleSelection(startRange.startPosition(), endRange.sta
rtPosition(), TextAffinity::Downstream, originalIsDirectional)); |
1326 } | 1343 } |
1327 | 1344 |
1328 // FIXME: Send an appropriate shouldDeleteRange call. | 1345 // FIXME: Send an appropriate shouldDeleteRange call. |
1329 bool CompositeEditCommand::breakOutOfEmptyListItem() | 1346 bool CompositeEditCommand::breakOutOfEmptyListItem(EditingState* editingState) |
1330 { | 1347 { |
1331 RefPtrWillBeRawPtr<Node> emptyListItem = enclosingEmptyListItem(endingSelect
ion().visibleStart()); | 1348 RefPtrWillBeRawPtr<Node> emptyListItem = enclosingEmptyListItem(endingSelect
ion().visibleStart()); |
1332 if (!emptyListItem) | 1349 if (!emptyListItem) |
1333 return false; | 1350 return false; |
1334 | 1351 |
1335 RefPtrWillBeRawPtr<EditingStyle> style = EditingStyle::create(endingSelectio
n().start()); | 1352 RefPtrWillBeRawPtr<EditingStyle> style = EditingStyle::create(endingSelectio
n().start()); |
1336 style->mergeTypingStyle(&document()); | 1353 style->mergeTypingStyle(&document()); |
1337 | 1354 |
1338 RefPtrWillBeRawPtr<ContainerNode> listNode = emptyListItem->parentNode(); | 1355 RefPtrWillBeRawPtr<ContainerNode> listNode = emptyListItem->parentNode(); |
1339 // FIXME: Can't we do something better when the immediate parent wasn't a li
st node? | 1356 // FIXME: Can't we do something better when the immediate parent wasn't a li
st node? |
(...skipping 26 matching lines...) Expand all Loading... |
1366 RefPtrWillBeRawPtr<Node> previousListNode = emptyListItem->isElementNode() ?
ElementTraversal::previousSibling(*emptyListItem): emptyListItem->previousSibli
ng(); | 1383 RefPtrWillBeRawPtr<Node> previousListNode = emptyListItem->isElementNode() ?
ElementTraversal::previousSibling(*emptyListItem): emptyListItem->previousSibli
ng(); |
1367 RefPtrWillBeRawPtr<Node> nextListNode = emptyListItem->isElementNode() ? Ele
mentTraversal::nextSibling(*emptyListItem): emptyListItem->nextSibling(); | 1384 RefPtrWillBeRawPtr<Node> nextListNode = emptyListItem->isElementNode() ? Ele
mentTraversal::nextSibling(*emptyListItem): emptyListItem->nextSibling(); |
1368 if (isListItem(nextListNode.get()) || isHTMLListElement(nextListNode.get()))
{ | 1385 if (isListItem(nextListNode.get()) || isHTMLListElement(nextListNode.get()))
{ |
1369 // If emptyListItem follows another list item or nested list, split the
list node. | 1386 // If emptyListItem follows another list item or nested list, split the
list node. |
1370 if (isListItem(previousListNode.get()) || isHTMLListElement(previousList
Node.get())) | 1387 if (isListItem(previousListNode.get()) || isHTMLListElement(previousList
Node.get())) |
1371 splitElement(toElement(listNode), emptyListItem); | 1388 splitElement(toElement(listNode), emptyListItem); |
1372 | 1389 |
1373 // If emptyListItem is followed by other list item or nested list, then
insert newBlock before the list node. | 1390 // If emptyListItem is followed by other list item or nested list, then
insert newBlock before the list node. |
1374 // Because we have splitted the element, emptyListItem is the first elem
ent in the list node. | 1391 // Because we have splitted the element, emptyListItem is the first elem
ent in the list node. |
1375 // i.e. insert newBlock before ul or ol whose first element is emptyList
Item | 1392 // i.e. insert newBlock before ul or ol whose first element is emptyList
Item |
1376 insertNodeBefore(newBlock, listNode); | 1393 insertNodeBefore(newBlock, listNode, editingState); |
1377 removeNode(emptyListItem); | 1394 if (editingState->isAborted()) |
| 1395 return false; |
| 1396 removeNode(emptyListItem, editingState); |
| 1397 if (editingState->isAborted()) |
| 1398 return false; |
1378 } else { | 1399 } else { |
1379 // When emptyListItem does not follow any list item or nested list, inse
rt newBlock after the enclosing list node. | 1400 // When emptyListItem does not follow any list item or nested list, inse
rt newBlock after the enclosing list node. |
1380 // Remove the enclosing node if emptyListItem is the only child; otherwi
se just remove emptyListItem. | 1401 // Remove the enclosing node if emptyListItem is the only child; otherwi
se just remove emptyListItem. |
1381 insertNodeAfter(newBlock, listNode); | 1402 insertNodeAfter(newBlock, listNode); |
1382 removeNode(isListItem(previousListNode.get()) || isHTMLListElement(previ
ousListNode.get()) ? emptyListItem.get() : listNode.get()); | 1403 removeNode(isListItem(previousListNode.get()) || isHTMLListElement(previ
ousListNode.get()) ? emptyListItem.get() : listNode.get(), editingState); |
| 1404 if (editingState->isAborted()) |
| 1405 return false; |
1383 } | 1406 } |
1384 | 1407 |
1385 appendBlockPlaceholder(newBlock); | 1408 appendBlockPlaceholder(newBlock); |
1386 setEndingSelection(VisibleSelection(firstPositionInNode(newBlock.get()), Tex
tAffinity::Downstream, endingSelection().isDirectional())); | 1409 setEndingSelection(VisibleSelection(firstPositionInNode(newBlock.get()), Tex
tAffinity::Downstream, endingSelection().isDirectional())); |
1387 | 1410 |
1388 style->prepareToApplyAt(endingSelection().start()); | 1411 style->prepareToApplyAt(endingSelection().start()); |
1389 if (!style->isEmpty()) | 1412 if (!style->isEmpty()) |
1390 applyStyle(style.get()); | 1413 applyStyle(style.get()); |
1391 | 1414 |
1392 return true; | 1415 return true; |
1393 } | 1416 } |
1394 | 1417 |
1395 // If the caret is in an empty quoted paragraph, and either there is nothing bef
ore that | 1418 // If the caret is in an empty quoted paragraph, and either there is nothing bef
ore that |
1396 // paragraph, or what is before is unquoted, and the user presses delete, unquot
e that paragraph. | 1419 // paragraph, or what is before is unquoted, and the user presses delete, unquot
e that paragraph. |
1397 bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph() | 1420 bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph(EditingState*
editingState) |
1398 { | 1421 { |
1399 if (!endingSelection().isCaret()) | 1422 if (!endingSelection().isCaret()) |
1400 return false; | 1423 return false; |
1401 | 1424 |
1402 VisiblePosition caret = endingSelection().visibleStart(); | 1425 VisiblePosition caret = endingSelection().visibleStart(); |
1403 HTMLQuoteElement* highestBlockquote = toHTMLQuoteElement(highestEnclosingNod
eOfType(caret.deepEquivalent(), &isMailHTMLBlockquoteElement)); | 1426 HTMLQuoteElement* highestBlockquote = toHTMLQuoteElement(highestEnclosingNod
eOfType(caret.deepEquivalent(), &isMailHTMLBlockquoteElement)); |
1404 if (!highestBlockquote) | 1427 if (!highestBlockquote) |
1405 return false; | 1428 return false; |
1406 | 1429 |
1407 if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret)) | 1430 if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret)) |
1408 return false; | 1431 return false; |
1409 | 1432 |
1410 VisiblePosition previous = previousPositionOf(caret, CannotCrossEditingBound
ary); | 1433 VisiblePosition previous = previousPositionOf(caret, CannotCrossEditingBound
ary); |
1411 // Only move forward if there's nothing before the caret, or if there's unqu
oted content before it. | 1434 // Only move forward if there's nothing before the caret, or if there's unqu
oted content before it. |
1412 if (enclosingNodeOfType(previous.deepEquivalent(), &isMailHTMLBlockquoteElem
ent)) | 1435 if (enclosingNodeOfType(previous.deepEquivalent(), &isMailHTMLBlockquoteElem
ent)) |
1413 return false; | 1436 return false; |
1414 | 1437 |
1415 RefPtrWillBeRawPtr<HTMLBRElement> br = HTMLBRElement::create(document()); | 1438 RefPtrWillBeRawPtr<HTMLBRElement> br = HTMLBRElement::create(document()); |
1416 // We want to replace this quoted paragraph with an unquoted one, so insert
a br | 1439 // We want to replace this quoted paragraph with an unquoted one, so insert
a br |
1417 // to hold the caret before the highest blockquote. | 1440 // to hold the caret before the highest blockquote. |
1418 insertNodeBefore(br, highestBlockquote); | 1441 insertNodeBefore(br, highestBlockquote, editingState); |
| 1442 if (editingState->isAborted()) |
| 1443 return false; |
1419 VisiblePosition atBR = createVisiblePosition(positionBeforeNode(br.get())); | 1444 VisiblePosition atBR = createVisiblePosition(positionBeforeNode(br.get())); |
1420 // If the br we inserted collapsed, for example foo<br><blockquote>...</bloc
kquote>, insert | 1445 // If the br we inserted collapsed, for example foo<br><blockquote>...</bloc
kquote>, insert |
1421 // a second one. | 1446 // a second one. |
1422 if (!isStartOfParagraph(atBR)) | 1447 if (!isStartOfParagraph(atBR)) { |
1423 insertNodeBefore(HTMLBRElement::create(document()), br); | 1448 insertNodeBefore(HTMLBRElement::create(document()), br, editingState); |
| 1449 if (editingState->isAborted()) |
| 1450 return false; |
| 1451 } |
1424 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); | 1452 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); |
1425 | 1453 |
1426 // If this is an empty paragraph there must be a line break here. | 1454 // If this is an empty paragraph there must be a line break here. |
1427 if (!lineBreakExistsAtVisiblePosition(caret)) | 1455 if (!lineBreakExistsAtVisiblePosition(caret)) |
1428 return false; | 1456 return false; |
1429 | 1457 |
1430 Position caretPos(mostForwardCaretPosition(caret.deepEquivalent())); | 1458 Position caretPos(mostForwardCaretPosition(caret.deepEquivalent())); |
1431 // A line break is either a br or a preserved newline. | 1459 // A line break is either a br or a preserved newline. |
1432 ASSERT(isHTMLBRElement(caretPos.anchorNode()) || (caretPos.anchorNode()->isT
extNode() && caretPos.anchorNode()->layoutObject()->style()->preserveNewline()))
; | 1460 ASSERT(isHTMLBRElement(caretPos.anchorNode()) || (caretPos.anchorNode()->isT
extNode() && caretPos.anchorNode()->layoutObject()->style()->preserveNewline()))
; |
1433 | 1461 |
1434 if (isHTMLBRElement(*caretPos.anchorNode())) { | 1462 if (isHTMLBRElement(*caretPos.anchorNode())) { |
1435 removeNodeAndPruneAncestors(caretPos.anchorNode()); | 1463 removeNodeAndPruneAncestors(caretPos.anchorNode(), editingState); |
| 1464 if (editingState->isAborted()) |
| 1465 return false; |
1436 } else if (caretPos.anchorNode()->isTextNode()) { | 1466 } else if (caretPos.anchorNode()->isTextNode()) { |
1437 ASSERT(caretPos.computeOffsetInContainerNode() == 0); | 1467 ASSERT(caretPos.computeOffsetInContainerNode() == 0); |
1438 Text* textNode = toText(caretPos.anchorNode()); | 1468 Text* textNode = toText(caretPos.anchorNode()); |
1439 ContainerNode* parentNode = textNode->parentNode(); | 1469 ContainerNode* parentNode = textNode->parentNode(); |
1440 // The preserved newline must be the first thing in the node, since othe
rwise the previous | 1470 // The preserved newline must be the first thing in the node, since othe
rwise the previous |
1441 // paragraph would be quoted, and we verified that it wasn't above. | 1471 // paragraph would be quoted, and we verified that it wasn't above. |
1442 deleteTextFromNode(textNode, 0, 1); | 1472 deleteTextFromNode(textNode, 0, 1); |
1443 prune(parentNode); | 1473 prune(parentNode, editingState); |
| 1474 if (editingState->isAborted()) |
| 1475 return false; |
1444 } | 1476 } |
1445 | 1477 |
1446 return true; | 1478 return true; |
1447 } | 1479 } |
1448 | 1480 |
1449 // Operations use this function to avoid inserting content into an anchor when a
t the start or the end of | 1481 // Operations use this function to avoid inserting content into an anchor when a
t the start or the end of |
1450 // that anchor, as in NSTextView. | 1482 // that anchor, as in NSTextView. |
1451 // FIXME: This is only an approximation of NSTextViews insertion behavior, which
varies depending on how | 1483 // FIXME: This is only an approximation of NSTextViews insertion behavior, which
varies depending on how |
1452 // the caret was made. | 1484 // the caret was made. |
1453 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi
tion& original, EditingState* editingState) | 1485 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi
tion& original, EditingState* editingState) |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1541 } | 1573 } |
1542 | 1574 |
1543 DEFINE_TRACE(CompositeEditCommand) | 1575 DEFINE_TRACE(CompositeEditCommand) |
1544 { | 1576 { |
1545 visitor->trace(m_commands); | 1577 visitor->trace(m_commands); |
1546 visitor->trace(m_composition); | 1578 visitor->trace(m_composition); |
1547 EditCommand::trace(visitor); | 1579 EditCommand::trace(visitor); |
1548 } | 1580 } |
1549 | 1581 |
1550 } // namespace blink | 1582 } // namespace blink |
OLD | NEW |