summaryrefslogtreecommitdiffstats
path: root/WebCore/editing/InsertListCommand.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/editing/InsertListCommand.cpp')
-rw-r--r--WebCore/editing/InsertListCommand.cpp63
1 files changed, 51 insertions, 12 deletions
diff --git a/WebCore/editing/InsertListCommand.cpp b/WebCore/editing/InsertListCommand.cpp
index 59a8bce..f90d5d3 100644
--- a/WebCore/editing/InsertListCommand.cpp
+++ b/WebCore/editing/InsertListCommand.cpp
@@ -37,6 +37,14 @@ namespace WebCore {
using namespace HTMLNames;
+static Node* enclosingListChild(Node* node, Node* listNode)
+{
+ Node* listChild = enclosingListChild(node);
+ while (listChild && enclosingList(listChild) != listNode)
+ listChild = enclosingListChild(listChild->parentNode());
+ return listChild;
+}
+
PassRefPtr<HTMLElement> InsertListCommand::insertList(Document* document, Type type)
{
RefPtr<InsertListCommand> insertCommand = create(document, type);
@@ -97,9 +105,9 @@ InsertListCommand::InsertListCommand(Document* document, Type type)
void InsertListCommand::doApply()
{
- if (endingSelection().isNone())
+ if (!endingSelection().isNonOrphanedCaretOrRange())
return;
-
+
if (!endingSelection().rootEditableElement())
return;
@@ -138,7 +146,19 @@ void InsertListCommand::doApply()
if (!startOfLastParagraph.deepEquivalent().node()->inDocument())
return;
setEndingSelection(startOfCurrentParagraph);
+
+ // Save and restore endOfSelection and startOfLastParagraph when necessary
+ // since moveParagraph and movePragraphWithClones can remove nodes.
+ // FIXME: This is an inefficient way to keep selection alive because indexForVisiblePosition walks from
+ // the beginning of the document to the endOfSelection everytime this code is executed.
+ // But not using index is hard because there are so many ways we can lose selection inside doApplyForSingleParagraph.
+ int indexForEndOfSelection = indexForVisiblePosition(endOfSelection);
doApplyForSingleParagraph(forceCreateList, listTag, currentSelection.get());
+ if (endOfSelection.isNull() || endOfSelection.isOrphan() || startOfLastParagraph.isNull() || startOfLastParagraph.isOrphan()) {
+ RefPtr<Range> lastSelectionRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), indexForEndOfSelection, 0, true);
+ endOfSelection = lastSelectionRange->startPosition();
+ startOfLastParagraph = startOfParagraph(endOfSelection);
+ }
// Fetch the start of the selection after moving the first paragraph,
// because moving the paragraph will invalidate the original start.
@@ -186,12 +206,35 @@ void InsertListCommand::doApplyForSingleParagraph(bool forceCreateList, const Qu
// If the entire list is selected, then convert the whole list.
if (switchListType && isNodeVisiblyContainedWithin(listNode.get(), currentSelection)) {
+ bool rangeStartIsInList = visiblePositionBeforeNode(listNode.get()) == currentSelection->startPosition();
+ bool rangeEndIsInList = visiblePositionAfterNode(listNode.get()) == currentSelection->endPosition();
+
RefPtr<HTMLElement> newList = createHTMLElement(document(), listTag);
insertNodeBefore(newList, listNode);
- Node* outerBlock = listChildNode->isBlockFlow() ? listChildNode : listNode.get();
+
+ Node* firstChildInList = enclosingListChild(VisiblePosition(Position(listNode, 0)).deepEquivalent().node(), listNode.get());
+ Node* outerBlock = firstChildInList->isBlockFlow() ? firstChildInList : listNode.get();
+
moveParagraphWithClones(firstPositionInNode(listNode.get()), lastPositionInNode(listNode.get()), newList.get(), outerBlock);
+
+ // Manually remove listNode because moveParagraphWithClones sometimes leaves it behind in the document.
+ // See the bug 33668 and editing/execCommand/insert-list-orphaned-item-with-nested-lists.html.
+ // FIXME: This might be a bug in moveParagraphWithClones or deleteSelection.
+ if (listNode && listNode->inDocument())
+ removeNode(listNode);
+
newList = mergeWithNeighboringLists(newList);
+
+ // Restore the start and the end of current selection if they started inside listNode
+ // because moveParagraphWithClones could have removed them.
+ ExceptionCode ec;
+ if (rangeStartIsInList && newList)
+ currentSelection->setStart(newList, 0, ec);
+ if (rangeEndIsInList && newList)
+ currentSelection->setEnd(newList, lastOffsetInNode(newList.get()), ec);
+
setEndingSelection(VisiblePosition(firstPositionInNode(newList.get())));
+
return;
}
@@ -202,14 +245,6 @@ void InsertListCommand::doApplyForSingleParagraph(bool forceCreateList, const Qu
m_listElement = listifyParagraph(endingSelection().visibleStart(), listTag);
}
-static Node* enclosingListChild(Node* node, Node* listNode)
-{
- Node* listChild = enclosingListChild(node);
- if (enclosingList(listChild) != listNode)
- return 0;
- return listChild;
-}
-
void InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart, HTMLElement* listNode, Node* listChildNode)
{
Node* nextListChild;
@@ -278,7 +313,8 @@ static Element* adjacentEnclosingList(const VisiblePosition& pos, const VisibleP
if (!listNode->hasTagName(listTag)
|| listNode->contains(pos.deepEquivalent().node())
- || previousCell != currentCell)
+ || previousCell != currentCell
+ || enclosingList(listNode) != enclosingList(pos.deepEquivalent().node()))
return 0;
return listNode;
@@ -288,6 +324,9 @@ PassRefPtr<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePositio
{
VisiblePosition start = startOfParagraph(originalStart);
VisiblePosition end = endOfParagraph(start);
+
+ if (start.isNull() || end.isNull())
+ return 0;
// Check for adjoining lists.
RefPtr<HTMLElement> listItemElement = createListItemElement(document());