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 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
270 applyCommandToComposite(ApplyStyleCommand::create(element, true)); | 270 applyCommandToComposite(ApplyStyleCommand::create(element, true)); |
271 } | 271 } |
272 | 272 |
273 void CompositeEditCommand::insertParagraphSeparator(bool useDefaultParagraphElem
ent, bool pasteBlockqutoeIntoUnquotedArea) | 273 void CompositeEditCommand::insertParagraphSeparator(bool useDefaultParagraphElem
ent, bool pasteBlockqutoeIntoUnquotedArea) |
274 { | 274 { |
275 applyCommandToComposite(InsertParagraphSeparatorCommand::create(document(),
useDefaultParagraphElement, pasteBlockqutoeIntoUnquotedArea)); | 275 applyCommandToComposite(InsertParagraphSeparatorCommand::create(document(),
useDefaultParagraphElement, pasteBlockqutoeIntoUnquotedArea)); |
276 } | 276 } |
277 | 277 |
278 bool CompositeEditCommand::isRemovableBlock(const Node* node) | 278 bool CompositeEditCommand::isRemovableBlock(const Node* node) |
279 { | 279 { |
280 if (!node->hasTagName(divTag)) | 280 ASSERT(node); |
| 281 if (!isHTMLDivElement(*node)) |
281 return false; | 282 return false; |
282 | 283 |
283 Node* parentNode = node->parentNode(); | 284 Node* parentNode = node->parentNode(); |
284 if (parentNode && parentNode->firstChild() != parentNode->lastChild()) | 285 if (parentNode && parentNode->firstChild() != parentNode->lastChild()) |
285 return false; | 286 return false; |
286 | 287 |
287 if (!toElement(node)->hasAttributes()) | 288 if (!toElement(node)->hasAttributes()) |
288 return true; | 289 return true; |
289 | 290 |
290 return false; | 291 return false; |
291 } | 292 } |
292 | 293 |
293 void CompositeEditCommand::insertNodeBefore(PassRefPtr<Node> insertChild, PassRe
fPtr<Node> refChild, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIsAl
waysEditable) | 294 void CompositeEditCommand::insertNodeBefore(PassRefPtr<Node> insertChild, PassRe
fPtr<Node> refChild, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIsAl
waysEditable) |
294 { | 295 { |
295 ASSERT(!refChild->hasTagName(bodyTag)); | 296 ASSERT(!isHTMLBodyElement(*refChild)); |
296 applyCommandToComposite(InsertNodeBeforeCommand::create(insertChild, refChil
d, shouldAssumeContentIsAlwaysEditable)); | 297 applyCommandToComposite(InsertNodeBeforeCommand::create(insertChild, refChil
d, shouldAssumeContentIsAlwaysEditable)); |
297 } | 298 } |
298 | 299 |
299 void CompositeEditCommand::insertNodeAfter(PassRefPtr<Node> insertChild, PassRef
Ptr<Node> refChild) | 300 void CompositeEditCommand::insertNodeAfter(PassRefPtr<Node> insertChild, PassRef
Ptr<Node> refChild) |
300 { | 301 { |
301 ASSERT(insertChild); | 302 ASSERT(insertChild); |
302 ASSERT(refChild); | 303 ASSERT(refChild); |
303 ASSERT(!refChild->hasTagName(bodyTag)); | 304 ASSERT(!isHTMLBodyElement(*refChild)); |
304 ContainerNode* parent = refChild->parentNode(); | 305 ContainerNode* parent = refChild->parentNode(); |
305 ASSERT(parent); | 306 ASSERT(parent); |
306 ASSERT(!parent->isShadowRoot()); | 307 ASSERT(!parent->isShadowRoot()); |
307 if (parent->lastChild() == refChild) | 308 if (parent->lastChild() == refChild) |
308 appendNode(insertChild, parent); | 309 appendNode(insertChild, parent); |
309 else { | 310 else { |
310 ASSERT(refChild->nextSibling()); | 311 ASSERT(refChild->nextSibling()); |
311 insertNodeBefore(insertChild, refChild->nextSibling()); | 312 insertNodeBefore(insertChild, refChild->nextSibling()); |
312 } | 313 } |
313 } | 314 } |
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
677 VisiblePosition previousVisiblePos(visiblePos.previous()); | 678 VisiblePosition previousVisiblePos(visiblePos.previous()); |
678 replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(previousVisiblePos)
; | 679 replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(previousVisiblePos)
; |
679 replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(visiblePos); | 680 replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(visiblePos); |
680 } | 681 } |
681 | 682 |
682 void CompositeEditCommand::replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNee
ded(const VisiblePosition& visiblePosition) | 683 void CompositeEditCommand::replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNee
ded(const VisiblePosition& visiblePosition) |
683 { | 684 { |
684 if (!isCollapsibleWhitespace(visiblePosition.characterAfter())) | 685 if (!isCollapsibleWhitespace(visiblePosition.characterAfter())) |
685 return; | 686 return; |
686 Position pos = visiblePosition.deepEquivalent().downstream(); | 687 Position pos = visiblePosition.deepEquivalent().downstream(); |
687 if (!pos.containerNode() || !pos.containerNode()->isTextNode() || pos.contai
nerNode()->hasTagName(brTag)) | 688 if (!pos.containerNode() || !pos.containerNode()->isTextNode()) |
688 return; | 689 return; |
689 replaceTextInNodePreservingMarkers(pos.containerText(), pos.offsetInContaine
rNode(), 1, nonBreakingSpaceString()); | 690 replaceTextInNodePreservingMarkers(pos.containerText(), pos.offsetInContaine
rNode(), 1, nonBreakingSpaceString()); |
690 } | 691 } |
691 | 692 |
692 void CompositeEditCommand::rebalanceWhitespace() | 693 void CompositeEditCommand::rebalanceWhitespace() |
693 { | 694 { |
694 VisibleSelection selection = endingSelection(); | 695 VisibleSelection selection = endingSelection(); |
695 if (selection.isNone()) | 696 if (selection.isNone()) |
696 return; | 697 return; |
697 | 698 |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
857 | 858 |
858 return nullptr; | 859 return nullptr; |
859 } | 860 } |
860 | 861 |
861 // Assumes that the position is at a placeholder and does the removal without mu
ch checking. | 862 // Assumes that the position is at a placeholder and does the removal without mu
ch checking. |
862 void CompositeEditCommand::removePlaceholderAt(const Position& p) | 863 void CompositeEditCommand::removePlaceholderAt(const Position& p) |
863 { | 864 { |
864 ASSERT(lineBreakExistsAtPosition(p)); | 865 ASSERT(lineBreakExistsAtPosition(p)); |
865 | 866 |
866 // We are certain that the position is at a line break, but it may be a br o
r a preserved newline. | 867 // We are certain that the position is at a line break, but it may be a br o
r a preserved newline. |
867 if (p.anchorNode()->hasTagName(brTag)) { | 868 if (isHTMLBRElement(*p.anchorNode())) { |
868 removeNode(p.anchorNode()); | 869 removeNode(p.anchorNode()); |
869 return; | 870 return; |
870 } | 871 } |
871 | 872 |
872 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); | 873 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); |
873 } | 874 } |
874 | 875 |
875 PassRefPtr<Node> CompositeEditCommand::insertNewDefaultParagraphElementAt(const
Position& position) | 876 PassRefPtr<Node> CompositeEditCommand::insertNewDefaultParagraphElementAt(const
Position& position) |
876 { | 877 { |
877 RefPtr<Element> paragraphElement = createDefaultParagraphElement(document())
; | 878 RefPtr<Element> paragraphElement = createDefaultParagraphElement(document())
; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
926 ASSERT(upstreamStart.deprecatedNode()->isDescendantOf(enclosingBlock
(upstreamEnd.deprecatedNode()))); | 927 ASSERT(upstreamStart.deprecatedNode()->isDescendantOf(enclosingBlock
(upstreamEnd.deprecatedNode()))); |
927 return nullptr; | 928 return nullptr; |
928 } else if (isEndOfEditableOrNonEditableContent(visibleEnd)) { | 929 } else if (isEndOfEditableOrNonEditableContent(visibleEnd)) { |
929 // At the end of the editable region. We can bail here as well. | 930 // At the end of the editable region. We can bail here as well. |
930 return nullptr; | 931 return nullptr; |
931 } | 932 } |
932 } | 933 } |
933 | 934 |
934 RefPtr<Node> newBlock = insertNewDefaultParagraphElementAt(upstreamStart); | 935 RefPtr<Node> newBlock = insertNewDefaultParagraphElementAt(upstreamStart); |
935 | 936 |
936 bool endWasBr = visibleParagraphEnd.deepEquivalent().deprecatedNode()->hasTa
gName(brTag); | 937 bool endWasBr = isHTMLBRElement(*visibleParagraphEnd.deepEquivalent().deprec
atedNode()); |
937 | 938 |
938 moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(f
irstPositionInNode(newBlock.get()))); | 939 moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(f
irstPositionInNode(newBlock.get()))); |
939 | 940 |
940 if (newBlock->lastChild() && newBlock->lastChild()->hasTagName(brTag) && !en
dWasBr) | 941 if (newBlock->lastChild() && isHTMLBRElement(*newBlock->lastChild()) && !end
WasBr) |
941 removeNode(newBlock->lastChild()); | 942 removeNode(newBlock->lastChild()); |
942 | 943 |
943 return newBlock.release(); | 944 return newBlock.release(); |
944 } | 945 } |
945 | 946 |
946 void CompositeEditCommand::pushAnchorElementDown(Node* anchorNode) | 947 void CompositeEditCommand::pushAnchorElementDown(Node* anchorNode) |
947 { | 948 { |
948 if (!anchorNode) | 949 if (!anchorNode) |
949 return; | 950 return; |
950 | 951 |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1041 if (caretAfterDelete != destination && isStartOfParagraph(caretAfterDelete)
&& isEndOfParagraph(caretAfterDelete)) { | 1042 if (caretAfterDelete != destination && isStartOfParagraph(caretAfterDelete)
&& isEndOfParagraph(caretAfterDelete)) { |
1042 // Note: We want the rightmost candidate. | 1043 // Note: We want the rightmost candidate. |
1043 Position position = caretAfterDelete.deepEquivalent().downstream(); | 1044 Position position = caretAfterDelete.deepEquivalent().downstream(); |
1044 Node* node = position.deprecatedNode(); | 1045 Node* node = position.deprecatedNode(); |
1045 | 1046 |
1046 // Bail if we'd remove an ancestor of our destination. | 1047 // Bail if we'd remove an ancestor of our destination. |
1047 if (destinationNode && destinationNode->isDescendantOf(node)) | 1048 if (destinationNode && destinationNode->isDescendantOf(node)) |
1048 return; | 1049 return; |
1049 | 1050 |
1050 // Normally deletion will leave a br as a placeholder. | 1051 // Normally deletion will leave a br as a placeholder. |
1051 if (node->hasTagName(brTag)) { | 1052 if (isHTMLBRElement(*node)) { |
1052 removeNodeAndPruneAncestors(node, destinationNode); | 1053 removeNodeAndPruneAncestors(node, destinationNode); |
1053 | 1054 |
1054 // If the selection to move was empty and in an empty block that | 1055 // If the selection to move was empty and in an empty block that |
1055 // doesn't require a placeholder to prop itself open (like a bordere
d | 1056 // doesn't require a placeholder to prop itself open (like a bordere
d |
1056 // div or an li), remove it during the move (the list removal code | 1057 // div or an li), remove it during the move (the list removal code |
1057 // expects this behavior). | 1058 // expects this behavior). |
1058 } else if (isBlock(node)) { | 1059 } else if (isBlock(node)) { |
1059 // If caret position after deletion and destination position coincid
es, | 1060 // If caret position after deletion and destination position coincid
es, |
1060 // node should not be removed. | 1061 // node should not be removed. |
1061 if (!position.rendersInDifferentPosition(destination.deepEquivalent(
))) { | 1062 if (!position.rendersInDifferentPosition(destination.deepEquivalent(
))) { |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1257 RefPtr<Node> emptyListItem = enclosingEmptyListItem(endingSelection().visibl
eStart()); | 1258 RefPtr<Node> emptyListItem = enclosingEmptyListItem(endingSelection().visibl
eStart()); |
1258 if (!emptyListItem) | 1259 if (!emptyListItem) |
1259 return false; | 1260 return false; |
1260 | 1261 |
1261 RefPtr<EditingStyle> style = EditingStyle::create(endingSelection().start())
; | 1262 RefPtr<EditingStyle> style = EditingStyle::create(endingSelection().start())
; |
1262 style->mergeTypingStyle(&document()); | 1263 style->mergeTypingStyle(&document()); |
1263 | 1264 |
1264 RefPtr<ContainerNode> listNode = emptyListItem->parentNode(); | 1265 RefPtr<ContainerNode> listNode = emptyListItem->parentNode(); |
1265 // FIXME: Can't we do something better when the immediate parent wasn't a li
st node? | 1266 // FIXME: Can't we do something better when the immediate parent wasn't a li
st node? |
1266 if (!listNode | 1267 if (!listNode |
1267 || (!listNode->hasTagName(ulTag) && !listNode->hasTagName(olTag)) | 1268 || (!isHTMLUListElement(*listNode) && !isHTMLOListElement(*listNode)) |
1268 || !listNode->rendererIsEditable() | 1269 || !listNode->rendererIsEditable() |
1269 || listNode == emptyListItem->rootEditableElement()) | 1270 || listNode == emptyListItem->rootEditableElement()) |
1270 return false; | 1271 return false; |
1271 | 1272 |
1272 RefPtr<Element> newBlock = nullptr; | 1273 RefPtr<Element> newBlock = nullptr; |
1273 if (ContainerNode* blockEnclosingList = listNode->parentNode()) { | 1274 if (ContainerNode* blockEnclosingList = listNode->parentNode()) { |
1274 if (blockEnclosingList->hasTagName(liTag)) { // listNode is inside anoth
er list item | 1275 if (isHTMLLIElement(*blockEnclosingList)) { // listNode is inside anothe
r list item |
1275 if (visiblePositionAfterNode(*blockEnclosingList) == visiblePosition
AfterNode(*listNode)) { | 1276 if (visiblePositionAfterNode(*blockEnclosingList) == visiblePosition
AfterNode(*listNode)) { |
1276 // If listNode appears at the end of the outer list item, then m
ove listNode outside of this list item | 1277 // If listNode appears at the end of the outer list item, then m
ove listNode outside of this list item |
1277 // 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 | 1278 // 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 |
1278 // If listNode does NOT appear at the end, then we should consid
er it as a regular paragraph. | 1279 // If listNode does NOT appear at the end, then we should consid
er it as a regular paragraph. |
1279 // 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 | 1280 // 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 |
1280 splitElement(toElement(blockEnclosingList), listNode); | 1281 splitElement(toElement(blockEnclosingList), listNode); |
1281 removeNodePreservingChildren(listNode->parentNode()); | 1282 removeNodePreservingChildren(listNode->parentNode()); |
1282 newBlock = createListItemElement(document()); | 1283 newBlock = createListItemElement(document()); |
1283 } | 1284 } |
1284 // If listNode does NOT appear at the end of the outer list item, th
en behave as if in a regular paragraph. | 1285 // If listNode does NOT appear at the end of the outer list item, th
en behave as if in a regular paragraph. |
1285 } else if (blockEnclosingList->hasTagName(olTag) || blockEnclosingList->
hasTagName(ulTag)) { | 1286 } else if (isHTMLOListElement(*blockEnclosingList) || isHTMLUListElement
(*blockEnclosingList)) { |
1286 newBlock = createListItemElement(document()); | 1287 newBlock = createListItemElement(document()); |
1287 } | 1288 } |
1288 } | 1289 } |
1289 if (!newBlock) | 1290 if (!newBlock) |
1290 newBlock = createDefaultParagraphElement(document()); | 1291 newBlock = createDefaultParagraphElement(document()); |
1291 | 1292 |
1292 RefPtr<Node> previousListNode = emptyListItem->isElementNode() ? ElementTrav
ersal::previousSibling(*emptyListItem): emptyListItem->previousSibling(); | 1293 RefPtr<Node> previousListNode = emptyListItem->isElementNode() ? ElementTrav
ersal::previousSibling(*emptyListItem): emptyListItem->previousSibling(); |
1293 RefPtr<Node> nextListNode = emptyListItem->isElementNode() ? ElementTraversa
l::nextSibling(*emptyListItem): emptyListItem->nextSibling(); | 1294 RefPtr<Node> nextListNode = emptyListItem->isElementNode() ? ElementTraversa
l::nextSibling(*emptyListItem): emptyListItem->nextSibling(); |
1294 if (isListItem(nextListNode.get()) || isListElement(nextListNode.get())) { | 1295 if (isListItem(nextListNode.get()) || isListElement(nextListNode.get())) { |
1295 // If emptyListItem follows another list item or nested list, split the
list node. | 1296 // If emptyListItem follows another list item or nested list, split the
list node. |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1348 if (!isStartOfParagraph(atBR)) | 1349 if (!isStartOfParagraph(atBR)) |
1349 insertNodeBefore(createBreakElement(document()), br); | 1350 insertNodeBefore(createBreakElement(document()), br); |
1350 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); | 1351 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); |
1351 | 1352 |
1352 // If this is an empty paragraph there must be a line break here. | 1353 // If this is an empty paragraph there must be a line break here. |
1353 if (!lineBreakExistsAtVisiblePosition(caret)) | 1354 if (!lineBreakExistsAtVisiblePosition(caret)) |
1354 return false; | 1355 return false; |
1355 | 1356 |
1356 Position caretPos(caret.deepEquivalent().downstream()); | 1357 Position caretPos(caret.deepEquivalent().downstream()); |
1357 // A line break is either a br or a preserved newline. | 1358 // A line break is either a br or a preserved newline. |
1358 ASSERT(caretPos.deprecatedNode()->hasTagName(brTag) || (caretPos.deprecatedN
ode()->isTextNode() && caretPos.deprecatedNode()->renderer()->style()->preserveN
ewline())); | 1359 ASSERT(isHTMLBRElement(caretPos.deprecatedNode()) || (caretPos.deprecatedNod
e()->isTextNode() && caretPos.deprecatedNode()->renderer()->style()->preserveNew
line())); |
1359 | 1360 |
1360 if (caretPos.deprecatedNode()->hasTagName(brTag)) | 1361 if (isHTMLBRElement(*caretPos.deprecatedNode())) |
1361 removeNodeAndPruneAncestors(caretPos.deprecatedNode()); | 1362 removeNodeAndPruneAncestors(caretPos.deprecatedNode()); |
1362 else if (caretPos.deprecatedNode()->isTextNode()) { | 1363 else if (caretPos.deprecatedNode()->isTextNode()) { |
1363 ASSERT(caretPos.deprecatedEditingOffset() == 0); | 1364 ASSERT(caretPos.deprecatedEditingOffset() == 0); |
1364 Text* textNode = toText(caretPos.deprecatedNode()); | 1365 Text* textNode = toText(caretPos.deprecatedNode()); |
1365 ContainerNode* parentNode = textNode->parentNode(); | 1366 ContainerNode* parentNode = textNode->parentNode(); |
1366 // The preserved newline must be the first thing in the node, since othe
rwise the previous | 1367 // The preserved newline must be the first thing in the node, since othe
rwise the previous |
1367 // paragraph would be quoted, and we verified that it wasn't above. | 1368 // paragraph would be quoted, and we verified that it wasn't above. |
1368 deleteTextFromNode(textNode, 0, 1); | 1369 deleteTextFromNode(textNode, 0, 1); |
1369 prune(parentNode); | 1370 prune(parentNode); |
1370 } | 1371 } |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1459 return node.release(); | 1460 return node.release(); |
1460 } | 1461 } |
1461 | 1462 |
1462 PassRefPtr<Element> createBlockPlaceholderElement(Document& document) | 1463 PassRefPtr<Element> createBlockPlaceholderElement(Document& document) |
1463 { | 1464 { |
1464 RefPtr<Element> breakNode = document.createElement(brTag, false); | 1465 RefPtr<Element> breakNode = document.createElement(brTag, false); |
1465 return breakNode.release(); | 1466 return breakNode.release(); |
1466 } | 1467 } |
1467 | 1468 |
1468 } // namespace WebCore | 1469 } // namespace WebCore |
OLD | NEW |