[Webkit-unassigned] [Bug 24872] Pasting from one bulleted list to another adds an extra level of outdent
bugzilla-daemon at webkit.org
bugzilla-daemon at webkit.org
Wed Feb 3 19:26:13 PST 2010
https://bugs.webkit.org/show_bug.cgi?id=24872
--- Comment #6 from Enrica Casucci <enrica at apple.com> 2010-02-03 19:26:11 PST ---
(From update of attachment 48083)
> diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
> index a660e4b..a6c6fe6 100644
> --- a/LayoutTests/ChangeLog
> +++ b/LayoutTests/ChangeLog
> @@ -1,3 +1,14 @@
> +2010-02-03 Tony Chang <tony at chromium.org>
> +
> + Reviewed by NOBODY (OOPS!).
> +
> + https://bugs.webkit.org/show_bug.cgi?id=24872
> + Add a test to make sure copying from a list and pasting into a list
> + keeps the list at the same indention level rather than nesting.
> +
> + * editing/pasteboard/paste-list-002-expected.txt: Added.
> + * editing/pasteboard/paste-list-002.html: Added.
> +
> 2010-02-03 Csaba Osztrogonác <ossy at webkit.org>
>
> Rubber-stamped by Ariya Hidayat.
> diff --git a/LayoutTests/editing/pasteboard/paste-list-002-expected.txt b/LayoutTests/editing/pasteboard/paste-list-002-expected.txt
> new file mode 100644
> index 0000000..5ff1cb6
> --- /dev/null
> +++ b/LayoutTests/editing/pasteboard/paste-list-002-expected.txt
> @@ -0,0 +1,13 @@
> +Copy/pasting list items in a list. This test should be run with DRT for pasteboard access.
> +
> +PASS: <li>alpha</li><ul><li>beta</li><li>gamma</li></ul><li>beta</li><li>gamma</li><li id="delta">delta</li><li>beta</li><li>gamma</li><li></li>
> +
> +alpha
> +beta
> +gamma
> +beta
> +gamma
> +delta
> +beta
> +gamma
> +
> diff --git a/LayoutTests/editing/pasteboard/paste-list-002.html b/LayoutTests/editing/pasteboard/paste-list-002.html
> new file mode 100644
> index 0000000..ff4c97c
> --- /dev/null
> +++ b/LayoutTests/editing/pasteboard/paste-list-002.html
> @@ -0,0 +1,63 @@
> +<html>
> +<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
> +<script>
> +
> +function editingTest() {
> + // Select "beta" and "gamma".
> + moveSelectionForwardByLineCommand();
> + for (i = 0; i < 2; i++)
> + extendSelectionForwardByLineCommand();
> + copyCommand();
> +
> + // Paste with the cursor right before "delta".
> + moveSelectionForwardByLineCommand();
> + pasteCommand();
> +
> + // Verify that the cursor is in the right place (still before delta).
> + var selection = window.getSelection();
> + if (selection.baseNode.parentNode != document.getElementById("delta") ||
> + selection.baseOffset != 0 || !selection.isCollapsed)
> + throw "Wrong selection position on before paste.";
> +
> + // Paste with the cursor at the end of "delta".
> + moveSelectionForwardByWordCommand();
> + pasteCommand();
> +
> + // Verify that the cursor is in the right place (new list item after delta).
> + var selection = window.getSelection();
> + if (!selection.isCollapsed || selection.baseNode.value != "")
> + throw "Wrong selection position on after paste.";
> +}
> +
> +</script>
> +<body>
> +<div contentEditable="true">
> +<p>Copy/pasting list items in a list. This test should be run with DRT for pasteboard access.</p>
> +<p id="results">FAIL</p>
> +<ul id="test">
> + <li>alpha</li>
> + <li>beta</li>
> + <li>gamma</li>
> + <li id="delta">delta</li>
> +</ul>
> +</div>
> +
> +<script>
> +if (window.layoutTestController)
> + layoutTestController.dumpAsText();
> +
> +var elem = document.getElementById("test");
> +var selection = window.getSelection();
> +selection.setPosition(elem, 0);
> +editingTest();
> +
> +// Rerun the test but have the source list be indented.
> +document.getElementById("test").innerHTML = "<li>alpha</li><ul><li>beta</li><li>gamma</li></ul><li id='delta'>delta</li>";
> +selection.setPosition(elem, 0);
> +editingTest();
> +
> +document.getElementById("results").innerText = "PASS: " + document.getElementById("test").innerHTML;
> +</script>
> +
> +</body>
> +</html>
> diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
> index dc9a30a..0e88eb1 100644
> --- a/WebCore/ChangeLog
> +++ b/WebCore/ChangeLog
> @@ -1,3 +1,29 @@
> +2010-02-03 Tony Chang <tony at chromium.org>
> +
> + Reviewed by NOBODY (OOPS!).
> +
> + https://bugs.webkit.org/show_bug.cgi?id=24872
> + When pasting a list into another list should not indent another level.
> + If the cursor is at the beginning of the line, it should insert the
> + list items before the current list item. If the cursor is at the end
> + of the line, it should insert the list items after the current list item.
> +
> + This matches Firefox and IE and makes the common activity of reordering a list
> + work as expected.
> +
> + This also adds a small helper method (isListItem) to htmlediting.h.
> +
> + Test: editing/pasteboard/paste-list-002.html
> +
> + * editing/ReplaceSelectionCommand.cpp:
> + (WebCore::ReplaceSelectionCommand::doApply):
> + (WebCore::ReplaceSelectionCommand::insertAsListItems):
> + * editing/ReplaceSelectionCommand.h:
> + * editing/htmlediting.cpp:
> + (WebCore::isListItem):
> + (WebCore::appendedSublist):
> + * editing/htmlediting.h:
> +
> 2010-02-03 Adele Peterson <adele at apple.com>
>
> Reviewed by Brady Eidson.
> diff --git a/WebCore/editing/ReplaceSelectionCommand.cpp b/WebCore/editing/ReplaceSelectionCommand.cpp
> index 85a4471..f26757e 100644
> --- a/WebCore/editing/ReplaceSelectionCommand.cpp
> +++ b/WebCore/editing/ReplaceSelectionCommand.cpp
> @@ -752,9 +752,7 @@ void ReplaceSelectionCommand::doApply()
> bool startIsInsideMailBlockquote = nearestMailBlockquote(insertionPos.node());
>
> if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && !startIsInsideMailBlockquote) ||
> - startBlock == currentRoot ||
> - (startBlock && startBlock->renderer() && startBlock->renderer()->isListItem()) ||
> - selectionIsPlainText)
> + startBlock == currentRoot || isListItem(startBlock) || selectionIsPlainText)
> m_preventNesting = false;
>
> if (selection.isRange()) {
> @@ -871,7 +869,12 @@ void ReplaceSelectionCommand::doApply()
> RefPtr<Node> node = refNode->nextSibling();
>
> fragment.removeNode(refNode);
> - insertNodeAtAndUpdateNodesInserted(refNode, insertionPos);
> +
> + Node* blockStart = enclosingBlock(insertionPos.node());
> + if (isListElement(refNode.get()) && blockStart->renderer()->isListItem())
> + refNode = insertAsListItems(refNode, blockStart, insertionPos);
> + else
> + insertNodeAtAndUpdateNodesInserted(refNode, insertionPos);
>
> // Mutation events (bug 22634) may have already removed the inserted content
> if (!refNode->inDocument())
> @@ -960,9 +963,15 @@ void ReplaceSelectionCommand::doApply()
> if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedContent) || next.isNull()) {
> if (!isStartOfParagraph(endOfInsertedContent)) {
> setEndingSelection(endOfInsertedContent);
> - // Use a default paragraph element (a plain div) for the empty paragraph, using the last paragraph
> - // block's style seems to annoy users.
> - insertParagraphSeparator(true);
> + Node* enclosingNode = enclosingBlock(endOfInsertedContent.deepEquivalent().node());
> + if (isListItem(enclosingNode)) {
> + RefPtr<Node> newListItem = createListItemElement(document());
> + insertNodeAfter(newListItem, enclosingNode);
> + setEndingSelection(VisiblePosition(Position(newListItem, 0)));
> + } else
> + // Use a default paragraph element (a plain div) for the empty paragraph, using the last paragraph
> + // block's style seems to annoy users.
> + insertParagraphSeparator(true);
>
> // Select up to the paragraph separator that was added.
> lastPositionToSelect = endingSelection().visibleStart().deepEquivalent();
> @@ -1111,6 +1120,39 @@ void ReplaceSelectionCommand::insertNodeBeforeAndUpdateNodesInserted(PassRefPtr<
> updateNodesInserted(nodeToUpdate);
> }
>
> +// If the user is inserting a list into an existing list, instead of nesting the list,
> +// we put the list items into the existing list.
> +Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtr<Node> listElement, Node* insertionNode, const Position& p)
> +{
> + while (listElement->hasChildNodes() && isListElement(listElement->firstChild()) && listElement->childNodeCount() == 1)
> + listElement = listElement->firstChild();
> +
> + bool isStart = isStartOfParagraph(p);
> + bool isEnd = isEndOfParagraph(p);
> +
> + Node* lastNode = insertionNode;
> + while (RefPtr<Node> listItem = listElement->firstChild()) {
> + ExceptionCode ec = 0;
> + listElement->removeChild(listItem.get(), ec);
> + ASSERT(!ec);
> + if (isStart)
> + insertNodeBefore(listItem, lastNode);
> + else if (isEnd) {
> + insertNodeAfter(listItem, lastNode);
> + lastNode = listItem.get();
> + } else {
> + // FIXME: If we're in the middle of a list item, we should split it into two separate
> + // list items and insert these nodes between them. For now, just append the nodes.
> + insertNodeAfter(listItem, lastNode);
> + lastNode = listItem.get();
> + }
> + }
> + if (isStart)
> + lastNode = lastNode->previousSibling();
> + updateNodesInserted(lastNode);
> + return lastNode;
> +}
> +
> void ReplaceSelectionCommand::updateNodesInserted(Node *node)
> {
> if (!node)
> diff --git a/WebCore/editing/ReplaceSelectionCommand.h b/WebCore/editing/ReplaceSelectionCommand.h
> index 1cb93c3..19f63bb 100644
> --- a/WebCore/editing/ReplaceSelectionCommand.h
> +++ b/WebCore/editing/ReplaceSelectionCommand.h
> @@ -54,6 +54,7 @@ private:
> void insertNodeAfterAndUpdateNodesInserted(PassRefPtr<Node> insertChild, Node* refChild);
> void insertNodeAtAndUpdateNodesInserted(PassRefPtr<Node>, const Position&);
> void insertNodeBeforeAndUpdateNodesInserted(PassRefPtr<Node> insertChild, Node* refChild);
> + Node* insertAsListItems(PassRefPtr<Node>, Node* insertionNode, const Position&);
>
> void updateNodesInserted(Node*);
> bool shouldRemoveEndBR(Node*, const VisiblePosition&);
> diff --git a/WebCore/editing/htmlediting.cpp b/WebCore/editing/htmlediting.cpp
> index b58dff3..4981f63 100644
> --- a/WebCore/editing/htmlediting.cpp
> +++ b/WebCore/editing/htmlediting.cpp
> @@ -658,6 +658,11 @@ bool isListElement(Node *n)
> return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag)));
> }
>
> +bool isListItem(Node *n)
> +{
> + return n && n->renderer() && n->renderer()->isListItem();
> +}
> +
> Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName)
> {
> if (p.isNull())
> @@ -779,7 +784,7 @@ static Node* appendedSublist(Node* listItem)
> for (Node* n = listItem->nextSibling(); n; n = n->nextSibling()) {
> if (isListElement(n))
> return static_cast<HTMLElement*>(n);
> - if (n->renderer() && n->renderer()->isListItem())
> + if (isListItem(listItem))
> return 0;
> }
>
> diff --git a/WebCore/editing/htmlediting.h b/WebCore/editing/htmlediting.h
> index c5a44ac..ef3db35 100644
> --- a/WebCore/editing/htmlediting.h
> +++ b/WebCore/editing/htmlediting.h
> @@ -90,6 +90,7 @@ bool isTableCell(const Node*);
> bool isEmptyTableCell(const Node*);
> bool isTableStructureNode(const Node*);
> bool isListElement(Node*);
> +bool isListItem(Node*);
> bool isNodeRendered(const Node*);
> bool isNodeVisiblyContainedWithin(Node*, const Range*);
> bool isRenderedAsNonInlineTableImageOrHR(const Node*);
It looks good to me.
--
Configure bugmail: https://bugs.webkit.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.
More information about the webkit-unassigned
mailing list