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 816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
827 PassRefPtr<Node> CompositeEditCommand::appendBlockPlaceholder(PassRefPtr<Element
> container) | 827 PassRefPtr<Node> CompositeEditCommand::appendBlockPlaceholder(PassRefPtr<Element
> container) |
828 { | 828 { |
829 if (!container) | 829 if (!container) |
830 return 0; | 830 return 0; |
831 | 831 |
832 document().updateLayoutIgnorePendingStylesheets(); | 832 document().updateLayoutIgnorePendingStylesheets(); |
833 | 833 |
834 // Should assert isBlockFlow || isInlineFlow when deletion improves. See 424
4964. | 834 // Should assert isBlockFlow || isInlineFlow when deletion improves. See 424
4964. |
835 ASSERT(container->renderer()); | 835 ASSERT(container->renderer()); |
836 | 836 |
837 RefPtr<Node> placeholder = createBlockPlaceholderElement(&document()); | 837 RefPtr<Node> placeholder = createBlockPlaceholderElement(document()); |
838 appendNode(placeholder, container); | 838 appendNode(placeholder, container); |
839 return placeholder.release(); | 839 return placeholder.release(); |
840 } | 840 } |
841 | 841 |
842 PassRefPtr<Node> CompositeEditCommand::insertBlockPlaceholder(const Position& po
s) | 842 PassRefPtr<Node> CompositeEditCommand::insertBlockPlaceholder(const Position& po
s) |
843 { | 843 { |
844 if (pos.isNull()) | 844 if (pos.isNull()) |
845 return 0; | 845 return 0; |
846 | 846 |
847 // Should assert isBlockFlow || isInlineFlow when deletion improves. See 42
44964. | 847 // Should assert isBlockFlow || isInlineFlow when deletion improves. See 42
44964. |
848 ASSERT(pos.deprecatedNode()->renderer()); | 848 ASSERT(pos.deprecatedNode()->renderer()); |
849 | 849 |
850 RefPtr<Node> placeholder = createBlockPlaceholderElement(&document()); | 850 RefPtr<Node> placeholder = createBlockPlaceholderElement(document()); |
851 insertNodeAt(placeholder, pos); | 851 insertNodeAt(placeholder, pos); |
852 return placeholder.release(); | 852 return placeholder.release(); |
853 } | 853 } |
854 | 854 |
855 PassRefPtr<Node> CompositeEditCommand::addBlockPlaceholderIfNeeded(Element* cont
ainer) | 855 PassRefPtr<Node> CompositeEditCommand::addBlockPlaceholderIfNeeded(Element* cont
ainer) |
856 { | 856 { |
857 if (!container) | 857 if (!container) |
858 return 0; | 858 return 0; |
859 | 859 |
860 document().updateLayoutIgnorePendingStylesheets(); | 860 document().updateLayoutIgnorePendingStylesheets(); |
(...skipping 20 matching lines...) Expand all Loading... |
881 if (p.anchorNode()->hasTagName(brTag)) { | 881 if (p.anchorNode()->hasTagName(brTag)) { |
882 removeNode(p.anchorNode()); | 882 removeNode(p.anchorNode()); |
883 return; | 883 return; |
884 } | 884 } |
885 | 885 |
886 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); | 886 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); |
887 } | 887 } |
888 | 888 |
889 PassRefPtr<Node> CompositeEditCommand::insertNewDefaultParagraphElementAt(const
Position& position) | 889 PassRefPtr<Node> CompositeEditCommand::insertNewDefaultParagraphElementAt(const
Position& position) |
890 { | 890 { |
891 RefPtr<Element> paragraphElement = createDefaultParagraphElement(&document()
); | 891 RefPtr<Element> paragraphElement = createDefaultParagraphElement(document())
; |
892 paragraphElement->appendChild(createBreakElement(&document())); | 892 paragraphElement->appendChild(createBreakElement(document())); |
893 insertNodeAt(paragraphElement, position); | 893 insertNodeAt(paragraphElement, position); |
894 return paragraphElement.release(); | 894 return paragraphElement.release(); |
895 } | 895 } |
896 | 896 |
897 // If the paragraph is not entirely within it's own block, create one and move t
he paragraph into | 897 // If the paragraph is not entirely within it's own block, create one and move t
he paragraph into |
898 // it, and return that block. Otherwise return 0. | 898 // it, and return that block. Otherwise return 0. |
899 PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessar
y(const Position& pos) | 899 PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessar
y(const Position& pos) |
900 { | 900 { |
901 if (pos.isNull()) | 901 if (pos.isNull()) |
902 return 0; | 902 return 0; |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1119 // baz | 1119 // baz |
1120 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. Th
at would | 1120 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. Th
at would |
1121 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. | 1121 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. |
1122 // Must recononicalize these two VisiblePositions after the pruning above. | 1122 // Must recononicalize these two VisiblePositions after the pruning above. |
1123 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); | 1123 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); |
1124 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); | 1124 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); |
1125 | 1125 |
1126 if (beforeParagraph.isNotNull() && !isTableElement(beforeParagraph.deepEquiv
alent().deprecatedNode()) | 1126 if (beforeParagraph.isNotNull() && !isTableElement(beforeParagraph.deepEquiv
alent().deprecatedNode()) |
1127 && ((!isEndOfParagraph(beforeParagraph) && !isStartOfParagraph(beforePar
agraph)) || beforeParagraph == afterParagraph)) { | 1127 && ((!isEndOfParagraph(beforeParagraph) && !isStartOfParagraph(beforePar
agraph)) || beforeParagraph == afterParagraph)) { |
1128 // FIXME: Trim text between beforeParagraph and afterParagraph if they a
ren't equal. | 1128 // FIXME: Trim text between beforeParagraph and afterParagraph if they a
ren't equal. |
1129 insertNodeAt(createBreakElement(&document()), beforeParagraph.deepEquiva
lent()); | 1129 insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquival
ent()); |
1130 } | 1130 } |
1131 } | 1131 } |
1132 | 1132 |
1133 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraph
ToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& dest
ination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor) | 1133 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraph
ToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& dest
ination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor) |
1134 { | 1134 { |
1135 ASSERT(isStartOfParagraph(startOfParagraphToMove)); | 1135 ASSERT(isStartOfParagraph(startOfParagraphToMove)); |
1136 ASSERT(isEndOfParagraph(endOfParagraphToMove)); | 1136 ASSERT(isEndOfParagraph(endOfParagraphToMove)); |
1137 moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, pr
eserveSelection, preserveStyle, constrainingAncestor); | 1137 moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, pr
eserveSelection, preserveStyle, constrainingAncestor); |
1138 } | 1138 } |
1139 | 1139 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1214 // foo^ | 1214 // foo^ |
1215 // <div>bar</div> | 1215 // <div>bar</div> |
1216 // baz | 1216 // baz |
1217 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That
would | 1217 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That
would |
1218 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. | 1218 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. |
1219 // Must recononicalize these two VisiblePositions after the pruning above. | 1219 // Must recononicalize these two VisiblePositions after the pruning above. |
1220 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); | 1220 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); |
1221 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); | 1221 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); |
1222 if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || be
foreParagraph == afterParagraph)) { | 1222 if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || be
foreParagraph == afterParagraph)) { |
1223 // FIXME: Trim text between beforeParagraph and afterParagraph if they a
ren't equal. | 1223 // FIXME: Trim text between beforeParagraph and afterParagraph if they a
ren't equal. |
1224 insertNodeAt(createBreakElement(&document()), beforeParagraph.deepEquiva
lent()); | 1224 insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquival
ent()); |
1225 // Need an updateLayout here in case inserting the br has split a text n
ode. | 1225 // Need an updateLayout here in case inserting the br has split a text n
ode. |
1226 document().updateLayoutIgnorePendingStylesheets(); | 1226 document().updateLayoutIgnorePendingStylesheets(); |
1227 } | 1227 } |
1228 | 1228 |
1229 RefPtr<Range> startToDestinationRange(Range::create(&document(), firstPositi
onInNode(document().documentElement()), destination.deepEquivalent().parentAncho
redEquivalent())); | 1229 RefPtr<Range> startToDestinationRange(Range::create(&document(), firstPositi
onInNode(document().documentElement()), destination.deepEquivalent().parentAncho
redEquivalent())); |
1230 destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(),
true); | 1230 destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(),
true); |
1231 | 1231 |
1232 setEndingSelection(VisibleSelection(destination, originalIsDirectional)); | 1232 setEndingSelection(VisibleSelection(destination, originalIsDirectional)); |
1233 ASSERT(endingSelection().isCaretOrRange()); | 1233 ASSERT(endingSelection().isCaretOrRange()); |
1234 ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::S
electReplacement | ReplaceSelectionCommand::MovingParagraph; | 1234 ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::S
electReplacement | ReplaceSelectionCommand::MovingParagraph; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1277 RefPtr<Element> newBlock = 0; | 1277 RefPtr<Element> newBlock = 0; |
1278 if (ContainerNode* blockEnclosingList = listNode->parentNode()) { | 1278 if (ContainerNode* blockEnclosingList = listNode->parentNode()) { |
1279 if (blockEnclosingList->hasTagName(liTag)) { // listNode is inside anoth
er list item | 1279 if (blockEnclosingList->hasTagName(liTag)) { // listNode is inside anoth
er list item |
1280 if (visiblePositionAfterNode(blockEnclosingList) == visiblePositionA
fterNode(listNode.get())) { | 1280 if (visiblePositionAfterNode(blockEnclosingList) == visiblePositionA
fterNode(listNode.get())) { |
1281 // If listNode appears at the end of the outer list item, then m
ove listNode outside of this list item | 1281 // If listNode appears at the end of the outer list item, then m
ove listNode outside of this list item |
1282 // e.g. <ul><li>hello <ul><li><br></li></ul> </li></ul> should b
ecome <ul><li>hello</li> <ul><li><br></li></ul> </ul> after this section | 1282 // e.g. <ul><li>hello <ul><li><br></li></ul> </li></ul> should b
ecome <ul><li>hello</li> <ul><li><br></li></ul> </ul> after this section |
1283 // If listNode does NOT appear at the end, then we should consid
er it as a regular paragraph. | 1283 // If listNode does NOT appear at the end, then we should consid
er it as a regular paragraph. |
1284 // e.g. <ul><li> <ul><li><br></li></ul> hello</li></ul> should b
ecome <ul><li> <div><br></div> hello</li></ul> at the end | 1284 // e.g. <ul><li> <ul><li><br></li></ul> hello</li></ul> should b
ecome <ul><li> <div><br></div> hello</li></ul> at the end |
1285 splitElement(toElement(blockEnclosingList), listNode); | 1285 splitElement(toElement(blockEnclosingList), listNode); |
1286 removeNodePreservingChildren(listNode->parentNode()); | 1286 removeNodePreservingChildren(listNode->parentNode()); |
1287 newBlock = createListItemElement(&document()); | 1287 newBlock = createListItemElement(document()); |
1288 } | 1288 } |
1289 // If listNode does NOT appear at the end of the outer list item, th
en behave as if in a regular paragraph. | 1289 // If listNode does NOT appear at the end of the outer list item, th
en behave as if in a regular paragraph. |
1290 } else if (blockEnclosingList->hasTagName(olTag) || blockEnclosingList->
hasTagName(ulTag)) { | 1290 } else if (blockEnclosingList->hasTagName(olTag) || blockEnclosingList->
hasTagName(ulTag)) { |
1291 newBlock = createListItemElement(&document()); | 1291 newBlock = createListItemElement(document()); |
1292 } | 1292 } |
1293 } | 1293 } |
1294 if (!newBlock) | 1294 if (!newBlock) |
1295 newBlock = createDefaultParagraphElement(&document()); | 1295 newBlock = createDefaultParagraphElement(document()); |
1296 | 1296 |
1297 RefPtr<Node> previousListNode = emptyListItem->isElementNode() ? toElement(e
mptyListItem.get())->previousElementSibling(): emptyListItem->previousSibling(); | 1297 RefPtr<Node> previousListNode = emptyListItem->isElementNode() ? toElement(e
mptyListItem.get())->previousElementSibling(): emptyListItem->previousSibling(); |
1298 RefPtr<Node> nextListNode = emptyListItem->isElementNode() ? toElement(empty
ListItem.get())->nextElementSibling(): emptyListItem->nextSibling(); | 1298 RefPtr<Node> nextListNode = emptyListItem->isElementNode() ? toElement(empty
ListItem.get())->nextElementSibling(): emptyListItem->nextSibling(); |
1299 if (isListItem(nextListNode.get()) || isListElement(nextListNode.get())) { | 1299 if (isListItem(nextListNode.get()) || isListElement(nextListNode.get())) { |
1300 // If emptyListItem follows another list item or nested list, split the
list node. | 1300 // If emptyListItem follows another list item or nested list, split the
list node. |
1301 if (isListItem(previousListNode.get()) || isListElement(previousListNode
.get())) | 1301 if (isListItem(previousListNode.get()) || isListElement(previousListNode
.get())) |
1302 splitElement(toElement(listNode.get()), emptyListItem); | 1302 splitElement(toElement(listNode.get()), emptyListItem); |
1303 | 1303 |
1304 // If emptyListItem is followed by other list item or nested list, then
insert newBlock before the list node. | 1304 // If emptyListItem is followed by other list item or nested list, then
insert newBlock before the list node. |
1305 // Because we have splitted the element, emptyListItem is the first elem
ent in the list node. | 1305 // Because we have splitted the element, emptyListItem is the first elem
ent in the list node. |
(...skipping 30 matching lines...) Expand all Loading... |
1336 return false; | 1336 return false; |
1337 | 1337 |
1338 if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret)) | 1338 if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret)) |
1339 return false; | 1339 return false; |
1340 | 1340 |
1341 VisiblePosition previous(caret.previous(CannotCrossEditingBoundary)); | 1341 VisiblePosition previous(caret.previous(CannotCrossEditingBoundary)); |
1342 // Only move forward if there's nothing before the caret, or if there's unqu
oted content before it. | 1342 // Only move forward if there's nothing before the caret, or if there's unqu
oted content before it. |
1343 if (enclosingNodeOfType(previous.deepEquivalent(), &isMailBlockquote)) | 1343 if (enclosingNodeOfType(previous.deepEquivalent(), &isMailBlockquote)) |
1344 return false; | 1344 return false; |
1345 | 1345 |
1346 RefPtr<Node> br = createBreakElement(&document()); | 1346 RefPtr<Node> br = createBreakElement(document()); |
1347 // We want to replace this quoted paragraph with an unquoted one, so insert
a br | 1347 // We want to replace this quoted paragraph with an unquoted one, so insert
a br |
1348 // to hold the caret before the highest blockquote. | 1348 // to hold the caret before the highest blockquote. |
1349 insertNodeBefore(br, highestBlockquote); | 1349 insertNodeBefore(br, highestBlockquote); |
1350 VisiblePosition atBR(positionBeforeNode(br.get())); | 1350 VisiblePosition atBR(positionBeforeNode(br.get())); |
1351 // If the br we inserted collapsed, for example foo<br><blockquote>...</bloc
kquote>, insert | 1351 // If the br we inserted collapsed, for example foo<br><blockquote>...</bloc
kquote>, insert |
1352 // a second one. | 1352 // a second one. |
1353 if (!isStartOfParagraph(atBR)) | 1353 if (!isStartOfParagraph(atBR)) |
1354 insertNodeBefore(createBreakElement(&document()), br); | 1354 insertNodeBefore(createBreakElement(document()), br); |
1355 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); | 1355 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); |
1356 | 1356 |
1357 // If this is an empty paragraph there must be a line break here. | 1357 // If this is an empty paragraph there must be a line break here. |
1358 if (!lineBreakExistsAtVisiblePosition(caret)) | 1358 if (!lineBreakExistsAtVisiblePosition(caret)) |
1359 return false; | 1359 return false; |
1360 | 1360 |
1361 Position caretPos(caret.deepEquivalent().downstream()); | 1361 Position caretPos(caret.deepEquivalent().downstream()); |
1362 // A line break is either a br or a preserved newline. | 1362 // A line break is either a br or a preserved newline. |
1363 ASSERT(caretPos.deprecatedNode()->hasTagName(brTag) || (caretPos.deprecatedN
ode()->isTextNode() && caretPos.deprecatedNode()->renderer()->style()->preserveN
ewline())); | 1363 ASSERT(caretPos.deprecatedNode()->hasTagName(brTag) || (caretPos.deprecatedN
ode()->isTextNode() && caretPos.deprecatedNode()->renderer()->style()->preserveN
ewline())); |
1364 | 1364 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1457 // Do not split a node when doing so introduces an empty node. | 1457 // Do not split a node when doing so introduces an empty node. |
1458 VisiblePosition positionInParent = firstPositionInNode(node->parentNode(
)); | 1458 VisiblePosition positionInParent = firstPositionInNode(node->parentNode(
)); |
1459 VisiblePosition positionInNode = firstPositionInOrBeforeNode(node.get())
; | 1459 VisiblePosition positionInNode = firstPositionInOrBeforeNode(node.get())
; |
1460 if (positionInParent != positionInNode) | 1460 if (positionInParent != positionInNode) |
1461 splitElement(toElement(node->parentNode()), node); | 1461 splitElement(toElement(node->parentNode()), node); |
1462 } | 1462 } |
1463 | 1463 |
1464 return node.release(); | 1464 return node.release(); |
1465 } | 1465 } |
1466 | 1466 |
1467 PassRefPtr<Element> createBlockPlaceholderElement(Document* document) | 1467 PassRefPtr<Element> createBlockPlaceholderElement(Document& document) |
1468 { | 1468 { |
1469 RefPtr<Element> breakNode = document->createElement(brTag, false); | 1469 RefPtr<Element> breakNode = document.createElement(brTag, false); |
1470 return breakNode.release(); | 1470 return breakNode.release(); |
1471 } | 1471 } |
1472 | 1472 |
1473 } // namespace WebCore | 1473 } // namespace WebCore |
OLD | NEW |