diff options
Diffstat (limited to 'src/3rdparty/webkit/WebCore/editing/IndentOutdentCommand.cpp')
-rw-r--r-- | src/3rdparty/webkit/WebCore/editing/IndentOutdentCommand.cpp | 117 |
1 files changed, 68 insertions, 49 deletions
diff --git a/src/3rdparty/webkit/WebCore/editing/IndentOutdentCommand.cpp b/src/3rdparty/webkit/WebCore/editing/IndentOutdentCommand.cpp index 0f9b106..3922367 100644 --- a/src/3rdparty/webkit/WebCore/editing/IndentOutdentCommand.cpp +++ b/src/3rdparty/webkit/WebCore/editing/IndentOutdentCommand.cpp @@ -78,7 +78,7 @@ IndentOutdentCommand::IndentOutdentCommand(Document* document, EIndentType typeO // This function is a workaround for moveParagraph's tendency to strip blockquotes. It updates lastBlockquote to point to the // correct level for the current paragraph, and returns a pointer to a placeholder br where the insertion should be performed. -PassRefPtr<Element> IndentOutdentCommand::prepareBlockquoteLevelForInsertion(VisiblePosition& currentParagraph, RefPtr<Element>& lastBlockquote) +PassRefPtr<Element> IndentOutdentCommand::prepareBlockquoteLevelForInsertion(const VisiblePosition& currentParagraph, RefPtr<Element>& lastBlockquote) { int currentBlockquoteLevel = 0; int lastBlockquoteLevel = 0; @@ -107,6 +107,62 @@ PassRefPtr<Element> IndentOutdentCommand::prepareBlockquoteLevelForInsertion(Vis return placeholder.release(); } +bool IndentOutdentCommand::tryIndentingAsListItem(const VisiblePosition& endOfCurrentParagraph) +{ + // If our selection is not inside a list, bail out. + Node* lastNodeInSelectedParagraph = endOfCurrentParagraph.deepEquivalent().node(); + RefPtr<Element> listNode = enclosingList(lastNodeInSelectedParagraph); + if (!listNode) + return false; + + HTMLElement* selectedListItem = enclosingListChild(lastNodeInSelectedParagraph); + + // FIXME: previousElementSibling does not ignore non-rendered content like <span></span>. Should we? + Element* previousList = selectedListItem->previousElementSibling(); + Element* nextList = selectedListItem->nextElementSibling(); + + RefPtr<Element> newList = document()->createElement(listNode->tagQName(), false); + RefPtr<Element> newListItem = selectedListItem->cloneElementWithoutChildren(); + RefPtr<Element> placeholder = createBreakElement(document()); + insertNodeBefore(newList, selectedListItem); + appendNode(newListItem, newList); + appendNode(placeholder, newListItem); + + moveParagraph(startOfParagraph(endOfCurrentParagraph), endOfCurrentParagraph, VisiblePosition(Position(placeholder, 0)), true); + + if (canMergeLists(previousList, newList.get())) + mergeIdenticalElements(previousList, newList); + if (canMergeLists(newList.get(), nextList)) + mergeIdenticalElements(newList, nextList); + + return true; +} + +void IndentOutdentCommand::indentIntoBlockquote(const VisiblePosition& endOfCurrentParagraph, const VisiblePosition& endOfNextParagraph, RefPtr<Element>& targetBlockquote) +{ + Node* enclosingCell = 0; + + if (!targetBlockquote) { + // Create a new blockquote and insert it as a child of the root editable element. We accomplish + // this by splitting all parents of the current paragraph up to that point. + targetBlockquote = createIndentBlockquoteElement(document()); + Position start = startOfParagraph(endOfCurrentParagraph).deepEquivalent(); + enclosingCell = enclosingNodeOfType(start, &isTableCell); + Node* nodeToSplitTo = enclosingCell ? enclosingCell : editableRootForPosition(start); + RefPtr<Node> startOfNewBlock = splitTreeToNode(start.node(), nodeToSplitTo); + insertNodeBefore(targetBlockquote, startOfNewBlock); + } + + RefPtr<Element> insertionPoint = prepareBlockquoteLevelForInsertion(endOfCurrentParagraph, targetBlockquote); + + // Don't put the next paragraph in the blockquote we just created for this paragraph unless + // the next paragraph is in the same cell. + if (enclosingCell && enclosingCell != enclosingNodeOfType(endOfNextParagraph.deepEquivalent(), &isTableCell)) + targetBlockquote = 0; + + moveParagraph(startOfParagraph(endOfCurrentParagraph), endOfCurrentParagraph, VisiblePosition(Position(insertionPoint, 0)), true); +} + void IndentOutdentCommand::indentRegion() { VisibleSelection selection = selectionForParagraphIteration(endingSelection()); @@ -117,7 +173,7 @@ void IndentOutdentCommand::indentRegion() ASSERT(!startOfSelection.isNull()); ASSERT(!endOfSelection.isNull()); - + // Special case empty root editable elements because there's nothing to split // and there's nothing to move. Position start = startOfSelection.deepEquivalent().downstream(); @@ -129,58 +185,21 @@ void IndentOutdentCommand::indentRegion() setEndingSelection(VisibleSelection(Position(placeholder.get(), 0), DOWNSTREAM)); return; } - - RefPtr<Element> previousListNode; - RefPtr<Element> newListNode; - RefPtr<Element> newBlockquote; + + RefPtr<Element> blockquoteForNextIndent; VisiblePosition endOfCurrentParagraph = endOfParagraph(startOfSelection); VisiblePosition endAfterSelection = endOfParagraph(endOfParagraph(endOfSelection).next()); while (endOfCurrentParagraph != endAfterSelection) { // Iterate across the selected paragraphs... VisiblePosition endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next()); - RefPtr<Element> listNode = enclosingList(endOfCurrentParagraph.deepEquivalent().node()); - RefPtr<Element> insertionPoint; - if (listNode) { - RefPtr<Element> placeholder = createBreakElement(document()); - insertionPoint = placeholder; - newBlockquote = 0; - RefPtr<Element> listItem = createListItemElement(document()); - if (listNode == previousListNode) { - // The previous paragraph was inside the same list, so add this list item to the list we already created - appendNode(listItem, newListNode); - appendNode(placeholder, listItem); - } else { - // Clone the list element, insert it before the current paragraph, and move the paragraph into it. - RefPtr<Element> clonedList = listNode->cloneElementWithoutChildren(); - insertNodeBefore(clonedList, enclosingListChild(endOfCurrentParagraph.deepEquivalent().node())); - appendNode(listItem, clonedList); - appendNode(placeholder, listItem); - newListNode = clonedList; - previousListNode = listNode; - } - } else if (newBlockquote) - // The previous paragraph was put into a new blockquote, so move this paragraph there as well - insertionPoint = prepareBlockquoteLevelForInsertion(endOfCurrentParagraph, newBlockquote); - else { - // Create a new blockquote and insert it as a child of the root editable element. We accomplish - // this by splitting all parents of the current paragraph up to that point. - RefPtr<Element> blockquote = createIndentBlockquoteElement(document()); - Position start = startOfParagraph(endOfCurrentParagraph).deepEquivalent(); - - Node* enclosingCell = enclosingNodeOfType(start, &isTableCell); - Node* nodeToSplitTo = enclosingCell ? enclosingCell : editableRootForPosition(start); - RefPtr<Node> startOfNewBlock = splitTreeToNode(start.node(), nodeToSplitTo); - insertNodeBefore(blockquote, startOfNewBlock); - newBlockquote = blockquote; - insertionPoint = prepareBlockquoteLevelForInsertion(endOfCurrentParagraph, newBlockquote); - // Don't put the next paragraph in the blockquote we just created for this paragraph unless - // the next paragraph is in the same cell. - if (enclosingCell && enclosingCell != enclosingNodeOfType(endOfNextParagraph.deepEquivalent(), &isTableCell)) - newBlockquote = 0; - } - moveParagraph(startOfParagraph(endOfCurrentParagraph), endOfCurrentParagraph, VisiblePosition(Position(insertionPoint, 0)), true); - // moveParagraph should not destroy content that contains endOfNextParagraph, but if it does, return here - // to avoid a crash. + if (tryIndentingAsListItem(endOfCurrentParagraph)) + blockquoteForNextIndent = 0; + else + indentIntoBlockquote(endOfCurrentParagraph, endOfNextParagraph, blockquoteForNextIndent); + // blockquoteForNextIndent maybe updated + // this is due to the way prepareBlockquoteLevelForInsertion was designed. + // Sanity check: Make sure our moveParagraph calls didn't remove endOfNextParagraph.deepEquivalent().node() + // If somehow we did, return to prevent crashes. if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().node()->inDocument()) { ASSERT_NOT_REACHED(); return; |