Title: [238080] trunk
Revision
238080
Author
wenson_hs...@apple.com
Date
2018-11-11 17:39:27 -0800 (Sun, 11 Nov 2018)

Log Message

Implement a new edit command to change the enclosing list type
https://bugs.webkit.org/show_bug.cgi?id=191487
<rdar://problem/45955922>

Reviewed by Ryosuke Niwa.

Source/WebCore:

Add support for a new edit command that changes the type of the enclosing list element around the selection from
unordered to ordered list and vice versa. This new edit command is exposed only to internal WebKit2 clients, via
SPI on WKWebView (`-_changeListType:`).

This is currently intended for use in Mail compose, but may also be adopted by legacy Notes in the future. As
such, the behavior of this editing command mostly matches shipping behavior in Mail compose (which is currently
implemented entirely by Mail). See below for more details.

Test:   editing/execCommand/change-list-type.html
        WKWebViewEditActions.ChangeListType

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* editing/ChangeListTypeCommand.cpp: Added.
(WebCore::listConversionTypeForSelection):
(WebCore::ChangeListTypeCommand::listConversionType):

Helper that returns a potential list conversion command that may be executed at the given document's selection,
if any exists. We also use existing logic from Mail here to determine which list to change, by walking up the
DOM from the lowest common ancestor container of the current selection until we hit the first list element.

(WebCore::ChangeListTypeCommand::createNewList):

Helper method to create a new list element to replace the given list, and then clone element data from the given
list to the new list. This addresses an existing bug in Mail, wherein changing list type for an enclosing list
which contains inline style properties drops the inline styles, because existing logic in Mail that implements
this editing command only copies the `class` attribute of the old list to the new list.

(WebCore::ChangeListTypeCommand::doApply):

Apply the edit command by running the following steps:
-   Find the enclosing list element, if any (see above).
-   Create a new list element of the opposite type as the enclosing list, and clone over element data from the
    list element being replaced.
-   Insert the new list next to the original list.
-   Move all children of the original list to the new list.
-   Remove the original list.
-   Set the selection to the end of the new list.

* editing/ChangeListTypeCommand.h: Added.
* editing/EditAction.h:

Add a pair of new edit actions for conversion from unordered list to ordered list and vice versa.

* editing/Editor.cpp:
(WebCore::Editor::changeSelectionListType):

Implement this by creating and applying a new ChangeListTypeCommand.

(WebCore::Editor::canChangeSelectionListType): Deleted.

Remove this for now, since there's no need for it until full support for edit command validation is implemented.

* editing/Editor.h:
* testing/Internals.cpp:
(WebCore::Internals::changeSelectionListType):
* testing/Internals.h:
* testing/Internals.idl:

Add internal hooks to change list type from layout tests.

Source/WebKit:

* UIProcess/WebEditCommandProxy.cpp:
(WebKit::WebEditCommandProxy::nameForEditAction):

Add undo/redo edit action strings for ConvertToOrderedList and ConvertToUnorderedList.

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::increaseListLevel):
(WebKit::WebPage::decreaseListLevel):
(WebKit::WebPage::changeListType):

Remove preflight checks for these list editing commands. These are not necessary because these commands fall
back to being noops if these checks return false. This avoids an extraneous ancestor walk to determine the
enclosing list element when changing list type.

Source/WebKitLegacy/mac:

Add undo/redo edit action strings for ConvertToOrderedList and ConvertToUnorderedList.

* WebCoreSupport/WebEditorClient.mm:
(undoNameForEditAction):

Tools:

Add a new API test to verify that `-[WKWebView _changeListType:]` is hooked up to the corresponding editing
command in WebCore. See the new layout test for a test that exercises more nuanced corner cases.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEditActions.mm:
(-[TestWKWebView setPosition:offset:]):
(-[TestWKWebView setBase:baseOffset:extent:extentOffset:]):
(TestWebKitAPI::webViewForEditActionTestingWithPageNamed):
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKitCocoa/editable-nested-lists.html: Added.

LayoutTests:

Add a new layout test to verify that the list change type editing command can be used to swap between enclosing
ordered and unordered lists. Also exercises undo, redo, changing list types under `pre` and `table` elements,
and handling selection within nested list elements.

* editing/execCommand/change-list-type-expected.txt: Added.
* editing/execCommand/change-list-type.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (238079 => 238080)


--- trunk/LayoutTests/ChangeLog	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/LayoutTests/ChangeLog	2018-11-12 01:39:27 UTC (rev 238080)
@@ -1,3 +1,18 @@
+2018-11-11  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Implement a new edit command to change the enclosing list type
+        https://bugs.webkit.org/show_bug.cgi?id=191487
+        <rdar://problem/45955922>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add a new layout test to verify that the list change type editing command can be used to swap between enclosing
+        ordered and unordered lists. Also exercises undo, redo, changing list types under `pre` and `table` elements,
+        and handling selection within nested list elements.
+
+        * editing/execCommand/change-list-type-expected.txt: Added.
+        * editing/execCommand/change-list-type.html: Added.
+
 2018-11-11  Javier Fernandez  <jfernan...@igalia.com>
 
         [css-grid] Import additional grid layout test from the WPT suite

Added: trunk/LayoutTests/editing/execCommand/change-list-type-expected.txt (0 => 238080)


--- trunk/LayoutTests/editing/execCommand/change-list-type-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/execCommand/change-list-type-expected.txt	2018-11-12 01:39:27 UTC (rev 238080)
@@ -0,0 +1,721 @@
+Verifies that the 'list type change' editing command works as expected. This test requires WebKitTestRunner or DumpRenderTree.
+
+After making the outer list ordered:
+| "
+        "
+| <ol>
+|   class="list"
+|   "
+            "
+|   <li>
+|     id="one"
+|     "one"
+|   "
+            "
+|   <ol>
+|     class="list"
+|     style="color: red"
+|     "
+                "
+|     <li>
+|       id="two"
+|       "two"
+|     "
+                "
+|     <li>
+|       id="three"
+|       "three"
+|     "
+            "
+|   "
+            "
+|   <li>
+|     id="four"
+|     "four"
+|   "
+            "
+|   <pre>
+|     "                "
+|     <ol>
+|       class="list"
+|       "
+                    "
+|       <li>
+|         id="five"
+|         "five"
+|       "
+                    "
+|       <li>
+|         id="six"
+|         "six"
+|       "
+                "
+|     "
+            <#selection-caret>"
+|   "
+        "
+| "
+    "
+
+After an undo:
+| "
+        "
+| <ul>
+|   class="list"
+|   "
+            "
+|   <li>
+|     id="one"
+|     "one<#selection-caret>"
+|   "
+            "
+|   <ol>
+|     class="list"
+|     style="color: red"
+|     "
+                "
+|     <li>
+|       id="two"
+|       "two"
+|     "
+                "
+|     <li>
+|       id="three"
+|       "three"
+|     "
+            "
+|   "
+            "
+|   <li>
+|     id="four"
+|     "four"
+|   "
+            "
+|   <pre>
+|     "                "
+|     <ol>
+|       class="list"
+|       "
+                    "
+|       <li>
+|         id="five"
+|         "five"
+|       "
+                    "
+|       <li>
+|         id="six"
+|         "six"
+|       "
+                "
+|     "
+            "
+|   "
+        "
+| "
+    "
+
+After a redo:
+| "
+        "
+| <ol>
+|   class="list"
+|   "
+            "
+|   <li>
+|     id="one"
+|     "one"
+|   "
+            "
+|   <ol>
+|     class="list"
+|     style="color: red"
+|     "
+                "
+|     <li>
+|       id="two"
+|       "two"
+|     "
+                "
+|     <li>
+|       id="three"
+|       "three"
+|     "
+            "
+|   "
+            "
+|   <li>
+|     id="four"
+|     "four"
+|   "
+            "
+|   <pre>
+|     "                "
+|     <ol>
+|       class="list"
+|       "
+                    "
+|       <li>
+|         id="five"
+|         "five"
+|       "
+                    "
+|       <li>
+|         id="six"
+|         "six"
+|       "
+                "
+|     "
+            <#selection-caret>"
+|   "
+        "
+| "
+    "
+
+After making the first sublist unordered:
+| "
+        "
+| <ol>
+|   class="list"
+|   "
+            "
+|   <li>
+|     id="one"
+|     "one"
+|   "
+            "
+|   <ul>
+|     class="list"
+|     style="color: red"
+|     "
+                "
+|     <li>
+|       id="two"
+|       "two"
+|     "
+                "
+|     <li>
+|       id="three"
+|       "three<#selection-caret>"
+|     "
+            "
+|   "
+            "
+|   <li>
+|     id="four"
+|     "four"
+|   "
+            "
+|   <pre>
+|     "                "
+|     <ol>
+|       class="list"
+|       "
+                    "
+|       <li>
+|         id="five"
+|         "five"
+|       "
+                    "
+|       <li>
+|         id="six"
+|         "six"
+|       "
+                "
+|     "
+            "
+|   "
+        "
+| "
+    "
+
+After changing the first sublist back to ordered:
+| "
+        "
+| <ol>
+|   class="list"
+|   "
+            "
+|   <li>
+|     id="one"
+|     "one"
+|   "
+            "
+|   <ol>
+|     class="list"
+|     style="color: red"
+|     "
+                "
+|     <li>
+|       id="two"
+|       "two"
+|     "
+                "
+|     <li>
+|       id="three"
+|       "three<#selection-caret>"
+|     "
+            "
+|   "
+            "
+|   <li>
+|     id="four"
+|     "four"
+|   "
+            "
+|   <pre>
+|     "                "
+|     <ol>
+|       class="list"
+|       "
+                    "
+|       <li>
+|         id="five"
+|         "five"
+|       "
+                    "
+|       <li>
+|         id="six"
+|         "six"
+|       "
+                "
+|     "
+            "
+|   "
+        "
+| "
+    "
+
+After making the second sublist unordered:
+| "
+        "
+| <ol>
+|   class="list"
+|   "
+            "
+|   <li>
+|     id="one"
+|     "one"
+|   "
+            "
+|   <ol>
+|     class="list"
+|     style="color: red"
+|     "
+                "
+|     <li>
+|       id="two"
+|       "two"
+|     "
+                "
+|     <li>
+|       id="three"
+|       "three"
+|     "
+            "
+|   "
+            "
+|   <li>
+|     id="four"
+|     "four"
+|   "
+            "
+|   <pre>
+|     "                "
+|     <ul>
+|       class="list"
+|       "
+                    "
+|       <li>
+|         id="five"
+|         "five"
+|       "
+                    "
+|       <li>
+|         id="six"
+|         "six"
+|       "
+                <#selection-caret>"
+|     "
+            "
+|   "
+        "
+| "
+    "
+
+After an undo:
+| "
+        "
+| <ol>
+|   class="list"
+|   "
+            "
+|   <li>
+|     id="one"
+|     "one"
+|   "
+            "
+|   <ol>
+|     class="list"
+|     style="color: red"
+|     "
+                "
+|     <li>
+|       id="two"
+|       "two"
+|     "
+                "
+|     <li>
+|       id="three"
+|       "three"
+|     "
+            "
+|   "
+            "
+|   <li>
+|     id="four"
+|     "four"
+|   "
+            "
+|   <pre>
+|     "                "
+|     <ol>
+|       class="list"
+|       "
+                    "
+|       <li>
+|         id="five"
+|         "<#selection-anchor>five"
+|       "
+                    "
+|       <li>
+|         id="six"
+|         "six<#selection-focus>"
+|       "
+                "
+|     "
+            "
+|   "
+        "
+| "
+    "
+
+After making the outer list unordered:
+| "
+        "
+| <ul>
+|   class="list"
+|   "
+            "
+|   <li>
+|     id="one"
+|     "one"
+|   "
+            "
+|   <ol>
+|     class="list"
+|     style="color: red"
+|     "
+                "
+|     <li>
+|       id="two"
+|       "two"
+|     "
+                "
+|     <li>
+|       id="three"
+|       "three"
+|     "
+            "
+|   "
+            "
+|   <li>
+|     id="four"
+|     "four"
+|   "
+            "
+|   <pre>
+|     "                "
+|     <ol>
+|       class="list"
+|       "
+                    "
+|       <li>
+|         id="five"
+|         "five"
+|       "
+                    "
+|       <li>
+|         id="six"
+|         "six"
+|       "
+                "
+|     "
+            <#selection-caret>"
+|   "
+        "
+| "
+    "
+
+After making the outer list ordered again:
+| "
+        "
+| <ol>
+|   class="list"
+|   "
+            "
+|   <li>
+|     id="one"
+|     "one"
+|   "
+            "
+|   <ol>
+|     class="list"
+|     style="color: red"
+|     "
+                "
+|     <li>
+|       id="two"
+|       "two"
+|     "
+                "
+|     <li>
+|       id="three"
+|       "three"
+|     "
+            "
+|   "
+            "
+|   <li>
+|     id="four"
+|     "four"
+|   "
+            "
+|   <pre>
+|     "                "
+|     <ol>
+|       class="list"
+|       "
+                    "
+|       <li>
+|         id="five"
+|         "five"
+|       "
+                    "
+|       <li>
+|         id="six"
+|         "six"
+|       "
+                "
+|     "
+            <#selection-caret>"
+|   "
+        "
+| "
+    "
+
+After making the left list unordered:
+| "
+        "
+| <table>
+|   "
+            "
+|   <tbody>
+|     "
+                "
+|     <tr>
+|       "
+                    "
+|       <td>
+|         "
+                        "
+|         <div>
+|           "foo"
+|         "
+                        "
+|         <ul>
+|           class="list"
+|           "
+                            "
+|           <li>
+|             id="seven"
+|             "seven"
+|           "
+                            "
+|           <li>
+|             id="eight"
+|             "eight<#selection-caret>"
+|           "
+                        "
+|         "
+                    "
+|       "
+                    "
+|       <td>
+|         "
+                        "
+|         <div>
+|           "bar"
+|         "
+                        "
+|         <ul>
+|           class="list"
+|           "
+                            "
+|           <li>
+|             id="nine"
+|             "nine"
+|           "
+                            "
+|           <li>
+|             id="ten"
+|             "ten"
+|           "
+                        "
+|         "
+                    "
+|       "
+                "
+|     "
+            "
+|   "
+        "
+| "
+    "
+
+After making the right list ordered:
+| "
+        "
+| <table>
+|   "
+            "
+|   <tbody>
+|     "
+                "
+|     <tr>
+|       "
+                    "
+|       <td>
+|         "
+                        "
+|         <div>
+|           "foo"
+|         "
+                        "
+|         <ul>
+|           class="list"
+|           "
+                            "
+|           <li>
+|             id="seven"
+|             "seven"
+|           "
+                            "
+|           <li>
+|             id="eight"
+|             "eight"
+|           "
+                        "
+|         "
+                    "
+|       "
+                    "
+|       <td>
+|         "
+                        "
+|         <div>
+|           "bar"
+|         "
+                        "
+|         <ol>
+|           class="list"
+|           "
+                            "
+|           <li>
+|             id="nine"
+|             "nine"
+|           "
+                            "
+|           <li>
+|             id="ten"
+|             "ten<#selection-caret>"
+|           "
+                        "
+|         "
+                    "
+|       "
+                "
+|     "
+            "
+|   "
+        "
+| "
+    "
+
+After selecting both lists and changing list type (this should be a no-op):
+| "
+        "
+| <table>
+|   "
+            "
+|   <tbody>
+|     "
+                "
+|     <tr>
+|       "
+                    "
+|       <td>
+|         "
+                        "
+|         <div>
+|           "foo"
+|         "
+                        "
+|         <ul>
+|           class="list"
+|           "
+                            "
+|           <li>
+|             id="seven"
+|             "<#selection-anchor>seven"
+|           "
+                            "
+|           <li>
+|             id="eight"
+|             "eight"
+|           "
+                        "
+|         "
+                    "
+|       "
+                    "
+|       <td>
+|         "
+                        "
+|         <div>
+|           "bar"
+|         "
+                        "
+|         <ol>
+|           class="list"
+|           "
+                            "
+|           <li>
+|             id="nine"
+|             "nine"
+|           "
+                            "
+|           <li>
+|             id="ten"
+|             "ten<#selection-focus>"
+|           "
+                        "
+|         "
+                    "
+|       "
+                "
+|     "
+            "
+|   "
+        "
+| "
+    "

Added: trunk/LayoutTests/editing/execCommand/change-list-type.html (0 => 238080)


--- trunk/LayoutTests/editing/execCommand/change-list-type.html	                        (rev 0)
+++ trunk/LayoutTests/editing/execCommand/change-list-type.html	2018-11-12 01:39:27 UTC (rev 238080)
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+    <div contenteditable id="top">
+        <ul class="list">
+            <li id="one">one</li>
+            <ol class="list" style="color: red">
+                <li id="two">two</li>
+                <li id="three">three</li>
+            </ol>
+            <li id="four">four</li>
+            <pre>
+                <ol class="list">
+                    <li id="five">five</li>
+                    <li id="six">six</li>
+                </ol>
+            </pre>
+        </ul>
+    </div>
+    <div contenteditable id="bottom">
+        <table>
+            <tbody>
+                <tr>
+                    <td>
+                        <div>foo</div>
+                        <ol class="list">
+                            <li id="seven">seven</li>
+                            <li id="eight">eight</li>
+                        </ol>
+                    </td>
+                    <td>
+                        <div>bar</div>
+                        <ul class="list">
+                            <li id="nine">nine</li>
+                            <li id="ten">ten</li>
+                        </ul>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+    <script>
+    (async () => {
+        Markup.description("Verifies that the 'list type change' editing command works as expected. This test requires WebKitTestRunner or DumpRenderTree.");
+        if (!window.internals)
+            return;
+
+        Markup.waitUntilDone();
+
+        top.focus();
+        getSelection().setPosition(one, 1);
+        internals.changeSelectionListType();
+        Markup.dump("top", "After making the outer list ordered");
+
+        undoCommand();
+        Markup.dump("top", "After an undo");
+
+        redoCommand();
+        Markup.dump("top", "After a redo");
+
+        getSelection().setBaseAndExtent(two, 0, two, 1);
+        internals.changeSelectionListType();
+        Markup.dump("top", "After making the first sublist unordered");
+
+        internals.changeSelectionListType();
+        Markup.dump("top", "After changing the first sublist back to ordered");
+
+        await new Promise(requestAnimationFrame);
+        getSelection().setBaseAndExtent(five, 0, six, 1);
+        internals.changeSelectionListType();
+        Markup.dump("top", "After making the second sublist unordered");
+
+        undoCommand();
+        Markup.dump("top", "After an undo");
+
+        getSelection().setBaseAndExtent(three, 0, five, 1);
+        internals.changeSelectionListType();
+        Markup.dump("top", "After making the outer list unordered");
+
+        internals.changeSelectionListType();
+        Markup.dump("top", "After making the outer list ordered again");
+
+        bottom.focus();
+        getSelection().setPosition(seven, 0);
+        internals.changeSelectionListType();
+        Markup.dump("bottom", "After making the left list unordered");
+
+        getSelection().setBaseAndExtent(nine, 0, ten, 1);
+        internals.changeSelectionListType();
+        Markup.dump("bottom", "After making the right list ordered");
+
+        getSelection().setBaseAndExtent(seven, 0, ten, 1);
+        internals.changeSelectionListType();
+        Markup.dump("bottom", "After selecting both lists and changing list type (this should be a no-op)");
+
+        Markup.notifyDone();
+    })();
+    </script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (238079 => 238080)


--- trunk/Source/WebCore/ChangeLog	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebCore/ChangeLog	2018-11-12 01:39:27 UTC (rev 238080)
@@ -1,3 +1,72 @@
+2018-11-11  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Implement a new edit command to change the enclosing list type
+        https://bugs.webkit.org/show_bug.cgi?id=191487
+        <rdar://problem/45955922>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add support for a new edit command that changes the type of the enclosing list element around the selection from
+        unordered to ordered list and vice versa. This new edit command is exposed only to internal WebKit2 clients, via
+        SPI on WKWebView (`-_changeListType:`).
+
+        This is currently intended for use in Mail compose, but may also be adopted by legacy Notes in the future. As
+        such, the behavior of this editing command mostly matches shipping behavior in Mail compose (which is currently
+        implemented entirely by Mail). See below for more details.
+
+        Test:   editing/execCommand/change-list-type.html
+                WKWebViewEditActions.ChangeListType
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * editing/ChangeListTypeCommand.cpp: Added.
+        (WebCore::listConversionTypeForSelection):
+        (WebCore::ChangeListTypeCommand::listConversionType):
+
+        Helper that returns a potential list conversion command that may be executed at the given document's selection,
+        if any exists. We also use existing logic from Mail here to determine which list to change, by walking up the
+        DOM from the lowest common ancestor container of the current selection until we hit the first list element.
+
+        (WebCore::ChangeListTypeCommand::createNewList):
+
+        Helper method to create a new list element to replace the given list, and then clone element data from the given
+        list to the new list. This addresses an existing bug in Mail, wherein changing list type for an enclosing list
+        which contains inline style properties drops the inline styles, because existing logic in Mail that implements
+        this editing command only copies the `class` attribute of the old list to the new list.
+
+        (WebCore::ChangeListTypeCommand::doApply):
+
+        Apply the edit command by running the following steps:
+        -   Find the enclosing list element, if any (see above).
+        -   Create a new list element of the opposite type as the enclosing list, and clone over element data from the
+            list element being replaced.
+        -   Insert the new list next to the original list.
+        -   Move all children of the original list to the new list.
+        -   Remove the original list.
+        -   Set the selection to the end of the new list.
+
+        * editing/ChangeListTypeCommand.h: Added.
+        * editing/EditAction.h:
+
+        Add a pair of new edit actions for conversion from unordered list to ordered list and vice versa.
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::changeSelectionListType):
+
+        Implement this by creating and applying a new ChangeListTypeCommand.
+
+        (WebCore::Editor::canChangeSelectionListType): Deleted.
+
+        Remove this for now, since there's no need for it until full support for edit command validation is implemented.
+
+        * editing/Editor.h:
+        * testing/Internals.cpp:
+        (WebCore::Internals::changeSelectionListType):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
+        Add internal hooks to change list type from layout tests.
+
 2018-11-11  Daniel Bates  <daba...@apple.com>
 
         [iOS] Draw caps lock indicator in password fields

Modified: trunk/Source/WebCore/Sources.txt (238079 => 238080)


--- trunk/Source/WebCore/Sources.txt	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebCore/Sources.txt	2018-11-12 01:39:27 UTC (rev 238080)
@@ -893,6 +893,7 @@
 editing/ApplyBlockElementCommand.cpp
 editing/ApplyStyleCommand.cpp
 editing/BreakBlockquoteCommand.cpp
+editing/ChangeListTypeCommand.cpp
 editing/CompositeEditCommand.cpp
 editing/CreateLinkCommand.cpp
 editing/DeleteFromTextNodeCommand.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (238079 => 238080)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-11-12 01:39:27 UTC (rev 238080)
@@ -14887,6 +14887,8 @@
 		F48D2AA42159740D00C6752B /* ColorCocoa.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ColorCocoa.mm; sourceTree = "<group>"; };
 		F49786871FF45FA500E060AB /* PasteboardItemInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PasteboardItemInfo.h; sourceTree = "<group>"; };
 		F4D43D64218802E600ECECAC /* SerializedAttachmentData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SerializedAttachmentData.h; sourceTree = "<group>"; };
+		F4D9817D2195FBF6008230FC /* ChangeListTypeCommand.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ChangeListTypeCommand.h; sourceTree = "<group>"; };
+		F4D9817E2195FBF6008230FC /* ChangeListTypeCommand.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ChangeListTypeCommand.cpp; sourceTree = "<group>"; };
 		F4E57EDA213F3F5F004EA98E /* FontAttributeChanges.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FontAttributeChanges.h; sourceTree = "<group>"; };
 		F4E57EDF213F434A004EA98E /* WebCoreNSFontManagerExtras.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebCoreNSFontManagerExtras.h; sourceTree = "<group>"; };
 		F4E57EE0213F434A004EA98E /* WebCoreNSFontManagerExtras.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WebCoreNSFontManagerExtras.mm; sourceTree = "<group>"; };
@@ -20683,6 +20685,8 @@
 				93309D8A099E64910056E581 /* ApplyStyleCommand.h */,
 				93309D8B099E64910056E581 /* BreakBlockquoteCommand.cpp */,
 				93309D8C099E64910056E581 /* BreakBlockquoteCommand.h */,
+				F4D9817E2195FBF6008230FC /* ChangeListTypeCommand.cpp */,
+				F4D9817D2195FBF6008230FC /* ChangeListTypeCommand.h */,
 				7C3A91E51C963B8800D1A7E3 /* ClipboardAccessPolicy.h */,
 				93309D8D099E64910056E581 /* CompositeEditCommand.cpp */,
 				93309D8E099E64910056E581 /* CompositeEditCommand.h */,

Added: trunk/Source/WebCore/editing/ChangeListTypeCommand.cpp (0 => 238080)


--- trunk/Source/WebCore/editing/ChangeListTypeCommand.cpp	                        (rev 0)
+++ trunk/Source/WebCore/editing/ChangeListTypeCommand.cpp	2018-11-12 01:39:27 UTC (rev 238080)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ChangeListTypeCommand.h"
+
+#include "ElementAncestorIterator.h"
+#include "HTMLElement.h"
+#include "HTMLOListElement.h"
+#include "HTMLUListElement.h"
+#include <wtf/Ref.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+static std::optional<std::pair<ChangeListTypeCommand::Type, Ref<HTMLElement>>> listConversionTypeForSelection(const VisibleSelection& selection)
+{
+    RefPtr<HTMLElement> listToReplace;
+    auto commonAncestor = makeRefPtr(Range::commonAncestorContainer(selection.start().containerNode(), selection.end().containerNode()));
+    if (is<HTMLUListElement>(commonAncestor) || is<HTMLOListElement>(commonAncestor))
+        listToReplace = downcast<HTMLElement>(commonAncestor.get());
+    else
+        listToReplace = enclosingList(commonAncestor.get());
+
+    if (is<HTMLUListElement>(listToReplace))
+        return {{ ChangeListTypeCommand::Type::ConvertToOrderedList, listToReplace.releaseNonNull() }};
+
+    if (is<HTMLOListElement>(listToReplace))
+        return {{ ChangeListTypeCommand::Type::ConvertToUnorderedList, listToReplace.releaseNonNull() }};
+
+    return std::nullopt;
+}
+
+std::optional<ChangeListTypeCommand::Type> ChangeListTypeCommand::listConversionType(Document& document)
+{
+    if (auto frame = makeRefPtr(document.frame())) {
+        if (auto typeAndElement = listConversionTypeForSelection(frame->selection().selection()))
+            return typeAndElement->first;
+    }
+    return std::nullopt;
+}
+
+Ref<HTMLElement> ChangeListTypeCommand::createNewList(const HTMLElement& listToReplace)
+{
+    RefPtr<HTMLElement> list;
+    if (m_type == Type::ConvertToOrderedList)
+        list = HTMLOListElement::create(document());
+    else
+        list = HTMLUListElement::create(document());
+    list->cloneDataFromElement(listToReplace);
+    return list.releaseNonNull();
+}
+
+void ChangeListTypeCommand::doApply()
+{
+    auto typeAndElement = listConversionTypeForSelection(endingSelection());
+    if (!typeAndElement || typeAndElement->first != m_type)
+        return;
+
+    auto listToReplace = WTFMove(typeAndElement->second);
+    auto newList = createNewList(listToReplace);
+    insertNodeBefore(newList.copyRef(), listToReplace);
+    moveRemainingSiblingsToNewParent(listToReplace->firstChild(), nullptr, newList);
+    removeNode(listToReplace);
+    setEndingSelection({ Position { newList.ptr(), Position::PositionIsAfterChildren }});
+}
+
+} // namespace WebCore

Added: trunk/Source/WebCore/editing/ChangeListTypeCommand.h (0 => 238080)


--- trunk/Source/WebCore/editing/ChangeListTypeCommand.h	                        (rev 0)
+++ trunk/Source/WebCore/editing/ChangeListTypeCommand.h	2018-11-12 01:39:27 UTC (rev 238080)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "CompositeEditCommand.h"
+#include "EditAction.h"
+#include <wtf/Optional.h>
+#include <wtf/Ref.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Document;
+class HTMLElement;
+
+class ChangeListTypeCommand final : public CompositeEditCommand {
+public:
+    enum class Type : uint8_t { ConvertToOrderedList, ConvertToUnorderedList };
+    static std::optional<Type> listConversionType(Document&);
+    static Ref<ChangeListTypeCommand> create(Document& document, Type type)
+    {
+        return adoptRef(*new ChangeListTypeCommand(document, type));
+    }
+
+private:
+    ChangeListTypeCommand(Document& document, Type type)
+        : CompositeEditCommand(document)
+        , m_type(type)
+    {
+    }
+
+    EditAction editingAction() const final
+    {
+        if (m_type == Type::ConvertToOrderedList)
+            return EditAction::ConvertToOrderedList;
+
+        return EditAction::ConvertToUnorderedList;
+    }
+
+    bool preservesTypingStyle() const final { return true; }
+    void doApply() final;
+
+    Ref<HTMLElement> createNewList(const HTMLElement& listToReplace);
+
+    Type m_type;
+};
+
+} // namespace WebCore

Modified: trunk/Source/WebCore/editing/EditAction.h (238079 => 238080)


--- trunk/Source/WebCore/editing/EditAction.h	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebCore/editing/EditAction.h	2018-11-12 01:39:27 UTC (rev 238080)
@@ -84,6 +84,8 @@
     FormatBlock,
     InsertOrderedList,
     InsertUnorderedList,
+    ConvertToOrderedList,
+    ConvertToUnorderedList,
     Indent,
     Outdent
 };

Modified: trunk/Source/WebCore/editing/Editor.cpp (238079 => 238080)


--- trunk/Source/WebCore/editing/Editor.cpp	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebCore/editing/Editor.cpp	2018-11-12 01:39:27 UTC (rev 238080)
@@ -33,6 +33,7 @@
 #include "CSSComputedStyleDeclaration.h"
 #include "CSSPropertyNames.h"
 #include "CachedResourceLoader.h"
+#include "ChangeListTypeCommand.h"
 #include "ClipboardEvent.h"
 #include "CompositionEvent.h"
 #include "CreateLinkCommand.h"
@@ -1476,15 +1477,10 @@
     setStartNewKillRingSequence(false);
 }
 
-bool Editor::canChangeSelectionListType()
-{
-    // FIXME: Not implemented.
-    return false;
-}
-
 void Editor::changeSelectionListType()
 {
-    // FIXME: Not implemented.
+    if (auto type = ChangeListTypeCommand::listConversionType(document()))
+        ChangeListTypeCommand::create(document(), *type)->apply();
 }
 
 void Editor::simplifyMarkup(Node* startNode, Node* endNode)

Modified: trunk/Source/WebCore/editing/Editor.h (238079 => 238080)


--- trunk/Source/WebCore/editing/Editor.h	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebCore/editing/Editor.h	2018-11-12 01:39:27 UTC (rev 238080)
@@ -206,7 +206,6 @@
     WEBCORE_EXPORT RefPtr<Node> increaseSelectionListLevelOrdered();
     WEBCORE_EXPORT RefPtr<Node> increaseSelectionListLevelUnordered();
     WEBCORE_EXPORT void decreaseSelectionListLevel();
-    WEBCORE_EXPORT bool canChangeSelectionListType();
     WEBCORE_EXPORT void changeSelectionListType();
    
     void removeFormattingAndStyle();

Modified: trunk/Source/WebCore/testing/Internals.cpp (238079 => 238080)


--- trunk/Source/WebCore/testing/Internals.cpp	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebCore/testing/Internals.cpp	2018-11-12 01:39:27 UTC (rev 238080)
@@ -2227,6 +2227,12 @@
     contextDocument()->frame()->editor().handleAcceptedCandidate(result);
 }
 
+void Internals::changeSelectionListType()
+{
+    if (auto frame = makeRefPtr(this->frame()))
+        frame->editor().changeSelectionListType();
+}
+
 bool Internals::isOverwriteModeEnabled()
 {
     Document* document = contextDocument();

Modified: trunk/Source/WebCore/testing/Internals.h (238079 => 238080)


--- trunk/Source/WebCore/testing/Internals.h	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebCore/testing/Internals.h	2018-11-12 01:39:27 UTC (rev 238080)
@@ -314,6 +314,7 @@
     void setAutomaticSpellingCorrectionEnabled(bool);
 
     void handleAcceptedCandidate(const String& candidate, unsigned location, unsigned length);
+    void changeSelectionListType();
 
     bool isOverwriteModeEnabled();
     void toggleOverwriteModeEnabled();

Modified: trunk/Source/WebCore/testing/Internals.idl (238079 => 238080)


--- trunk/Source/WebCore/testing/Internals.idl	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebCore/testing/Internals.idl	2018-11-12 01:39:27 UTC (rev 238080)
@@ -333,6 +333,7 @@
     void setAutomaticSpellingCorrectionEnabled(boolean enabled);
 
     void handleAcceptedCandidate(DOMString candidate, unsigned long location, unsigned long length);
+    void changeSelectionListType();
 
     boolean isOverwriteModeEnabled();
     void toggleOverwriteModeEnabled();

Modified: trunk/Source/WebKit/ChangeLog (238079 => 238080)


--- trunk/Source/WebKit/ChangeLog	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebKit/ChangeLog	2018-11-12 01:39:27 UTC (rev 238080)
@@ -1,3 +1,25 @@
+2018-11-11  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Implement a new edit command to change the enclosing list type
+        https://bugs.webkit.org/show_bug.cgi?id=191487
+        <rdar://problem/45955922>
+
+        Reviewed by Ryosuke Niwa.
+
+        * UIProcess/WebEditCommandProxy.cpp:
+        (WebKit::WebEditCommandProxy::nameForEditAction):
+
+        Add undo/redo edit action strings for ConvertToOrderedList and ConvertToUnorderedList.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::increaseListLevel):
+        (WebKit::WebPage::decreaseListLevel):
+        (WebKit::WebPage::changeListType):
+
+        Remove preflight checks for these list editing commands. These are not necessary because these commands fall
+        back to being noops if these checks return false. This avoids an extraneous ancestor walk to determine the
+        enclosing list element when changing list type.
+
 2018-11-11  Daniel Bates  <daba...@apple.com>
 
         [iOS] Draw caps lock indicator in password fields

Modified: trunk/Source/WebKit/UIProcess/WebEditCommandProxy.cpp (238079 => 238080)


--- trunk/Source/WebKit/UIProcess/WebEditCommandProxy.cpp	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebKit/UIProcess/WebEditCommandProxy.cpp	2018-11-12 01:39:27 UTC (rev 238080)
@@ -171,6 +171,12 @@
         return WEB_UI_STRING_KEY("Indent", "Indent (Undo action name)", "Undo action name");
     case EditAction::Outdent:
         return WEB_UI_STRING_KEY("Outdent", "Outdent (Undo action name)", "Undo action name");
+    // FIXME: We should give internal clients a way to override these undo names. For instance, Mail refers to ordered and unordered lists as "numbered" and "bulleted" lists, respectively,
+    // despite the fact that ordered and unordered lists are not necessarily displayed using bullets and numerals.
+    case EditAction::ConvertToOrderedList:
+        return WEB_UI_STRING_KEY("Convert to Ordered List", "Convert to Ordered List (Undo action name)", "Convert to ordered list action name");
+    case EditAction::ConvertToUnorderedList:
+        return WEB_UI_STRING_KEY("Convert to Unordered List", "Convert to Unordered List (Undo action name)", "Convert to unordered list action name");
     }
     return String();
 }

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (238079 => 238080)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-11-12 01:39:27 UTC (rev 238080)
@@ -1152,23 +1152,17 @@
 
 void WebPage::increaseListLevel()
 {
-    auto& editor = m_page->focusController().focusedOrMainFrame().editor();
-    if (editor.canIncreaseSelectionListLevel())
-        editor.increaseSelectionListLevel();
+    m_page->focusController().focusedOrMainFrame().editor().increaseSelectionListLevel();
 }
 
 void WebPage::decreaseListLevel()
 {
-    auto& editor = m_page->focusController().focusedOrMainFrame().editor();
-    if (editor.canDecreaseSelectionListLevel())
-        editor.decreaseSelectionListLevel();
+    m_page->focusController().focusedOrMainFrame().editor().decreaseSelectionListLevel();
 }
 
 void WebPage::changeListType()
 {
-    auto& editor = m_page->focusController().focusedOrMainFrame().editor();
-    if (editor.canChangeSelectionListType())
-        editor.changeSelectionListType();
+    m_page->focusController().focusedOrMainFrame().editor().changeSelectionListType();
 }
 
 bool WebPage::isEditingCommandEnabled(const String& commandName)

Modified: trunk/Source/WebKitLegacy/mac/ChangeLog (238079 => 238080)


--- trunk/Source/WebKitLegacy/mac/ChangeLog	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebKitLegacy/mac/ChangeLog	2018-11-12 01:39:27 UTC (rev 238080)
@@ -1,3 +1,16 @@
+2018-11-11  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Implement a new edit command to change the enclosing list type
+        https://bugs.webkit.org/show_bug.cgi?id=191487
+        <rdar://problem/45955922>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add undo/redo edit action strings for ConvertToOrderedList and ConvertToUnorderedList.
+
+        * WebCoreSupport/WebEditorClient.mm:
+        (undoNameForEditAction):
+
 2018-11-11  Daniel Bates  <daba...@apple.com>
 
         [iOS] Draw caps lock indicator in password fields

Modified: trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm (238079 => 238080)


--- trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm	2018-11-12 01:39:27 UTC (rev 238080)
@@ -653,6 +653,8 @@
     case EditAction::Italics: return UI_STRING_KEY_INTERNAL("Italics", "Italics (Undo action name)", "Undo action name");
     case EditAction::Delete: return UI_STRING_KEY_INTERNAL("Delete", "Delete (Undo action name)", "Undo action name");
     case EditAction::Dictation: return UI_STRING_KEY_INTERNAL("Dictation", "Dictation (Undo action name)", "Undo action name");
+    case EditAction::ConvertToOrderedList: return UI_STRING_KEY_INTERNAL("Convert to Ordered List", "Convert to Ordered List (Undo action name)", "Convert to ordered list action name");
+    case EditAction::ConvertToUnorderedList: return UI_STRING_KEY_INTERNAL("Convert to Unordered List", "Convert to Unordered List (Undo action name)", "Convert to unordered list action name");
     }
     return nil;
 }

Modified: trunk/Tools/ChangeLog (238079 => 238080)


--- trunk/Tools/ChangeLog	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Tools/ChangeLog	2018-11-12 01:39:27 UTC (rev 238080)
@@ -1,3 +1,22 @@
+2018-11-11  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Implement a new edit command to change the enclosing list type
+        https://bugs.webkit.org/show_bug.cgi?id=191487
+        <rdar://problem/45955922>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add a new API test to verify that `-[WKWebView _changeListType:]` is hooked up to the corresponding editing
+        command in WebCore. See the new layout test for a test that exercises more nuanced corner cases.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEditActions.mm:
+        (-[TestWKWebView setPosition:offset:]):
+        (-[TestWKWebView setBase:baseOffset:extent:extentOffset:]):
+        (TestWebKitAPI::webViewForEditActionTestingWithPageNamed):
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WebKitCocoa/editable-nested-lists.html: Added.
+
 2018-11-11  Dan Bernstein  <m...@apple.com>
 
         ProcessPoolConfiguration::copy() doesn’t copy m_customWebContentServiceBundleIdentifier

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (238079 => 238080)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2018-11-12 01:39:27 UTC (rev 238080)
@@ -867,6 +867,7 @@
 		F4D4F3B91E4E36E400BB2767 /* DragAndDropTestsIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4D4F3B71E4E36E400BB2767 /* DragAndDropTestsIOS.mm */; };
 		F4D5E4E81F0C5D38008C1A49 /* dragstart-clear-selection.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4D5E4E71F0C5D27008C1A49 /* dragstart-clear-selection.html */; };
 		F4D65DA81F5E4704009D8C27 /* selected-text-image-link-and-editable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4D65DA71F5E46C0009D8C27 /* selected-text-image-link-and-editable.html */; };
+		F4D9818F2196B920008230FC /* editable-nested-lists.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4D9818E2196B911008230FC /* editable-nested-lists.html */; };
 		F4DEF6ED1E9B4DB60048EF61 /* image-in-link-and-input.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4DEF6EC1E9B4D950048EF61 /* image-in-link-and-input.html */; };
 		F4E0A28B211E4A2B00AF7C7F /* full-page-dropzone.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F46128D8211E496300D9FADB /* full-page-dropzone.html */; };
 		F4E0A28F211E5D5B00AF7C7F /* DragAndDropTestsMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4E0A28E211E5D5B00AF7C7F /* DragAndDropTestsMac.mm */; };
@@ -1032,6 +1033,7 @@
 				2EB29D5E1F762DB90023A5F1 /* dump-datatransfer-types.html in Copy Resources */,
 				A155022C1E050D0300A24C57 /* duplicate-completion-handler-calls.html in Copy Resources */,
 				9984FACE1CFFB090008D198C /* editable-body.html in Copy Resources */,
+				F4D9818F2196B920008230FC /* editable-nested-lists.html in Copy Resources */,
 				F44D06451F395C26001A0E29 /* editor-state-test-harness.html in Copy Resources */,
 				51C8E1A91F27F49600BF731B /* EmptyGrandfatheredResourceLoadStatistics.plist in Copy Resources */,
 				A14AAB651E78DC5400C1ADC2 /* encrypted.pdf in Copy Resources */,
@@ -2155,6 +2157,7 @@
 		F4D4F3B71E4E36E400BB2767 /* DragAndDropTestsIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DragAndDropTestsIOS.mm; sourceTree = "<group>"; };
 		F4D5E4E71F0C5D27008C1A49 /* dragstart-clear-selection.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "dragstart-clear-selection.html"; sourceTree = "<group>"; };
 		F4D65DA71F5E46C0009D8C27 /* selected-text-image-link-and-editable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "selected-text-image-link-and-editable.html"; sourceTree = "<group>"; };
+		F4D9818E2196B911008230FC /* editable-nested-lists.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "editable-nested-lists.html"; sourceTree = "<group>"; };
 		F4DEF6EC1E9B4D950048EF61 /* image-in-link-and-input.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "image-in-link-and-input.html"; sourceTree = "<group>"; };
 		F4E0A28E211E5D5B00AF7C7F /* DragAndDropTestsMac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DragAndDropTestsMac.mm; sourceTree = "<group>"; };
 		F4E0A295211FC5A300AF7C7F /* selected-text-and-textarea.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "selected-text-and-textarea.html"; sourceTree = "<group>"; };
@@ -2737,6 +2740,7 @@
 				2EB29D5D1F762DA50023A5F1 /* dump-datatransfer-types.html */,
 				A155022B1E050BC500A24C57 /* duplicate-completion-handler-calls.html */,
 				9984FACD1CFFB038008D198C /* editable-body.html */,
+				F4D9818E2196B911008230FC /* editable-nested-lists.html */,
 				F44D06441F395C0D001A0E29 /* editor-state-test-harness.html */,
 				51C8E1A81F27F47300BF731B /* EmptyGrandfatheredResourceLoadStatistics.plist */,
 				F4C2AB211DD6D94100E06D5B /* enormous-video-with-sound.html */,

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEditActions.mm (238079 => 238080)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEditActions.mm	2018-11-11 22:22:33 UTC (rev 238079)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEditActions.mm	2018-11-12 01:39:27 UTC (rev 238080)
@@ -39,6 +39,8 @@
 @interface TestWKWebView (EditActionTesting)
 - (BOOL)querySelectorExists:(NSString *)querySelector;
 - (void)insertString:(NSString *)string;
+- (void)setPosition:(NSString *)container offset:(NSUInteger)offset;
+- (void)setBase:(NSString *)base baseOffset:(NSUInteger)baseOffset extent:(NSString *)extent extentOffset:(NSUInteger)extentOffset;
 @end
 
 @implementation TestWKWebView (EditActionTesting)
@@ -57,6 +59,16 @@
 #endif
 }
 
+- (void)setPosition:(NSString *)container offset:(NSUInteger)offset
+{
+    [self evaluateJavaScript:[NSString stringWithFormat:@"getSelection().setPosition(%@, %tu)", container, offset] completionHandler:nil];
+}
+
+- (void)setBase:(NSString *)base baseOffset:(NSUInteger)baseOffset extent:(NSString *)extent extentOffset:(NSUInteger)extentOffset
+{
+    [self evaluateJavaScript:[NSString stringWithFormat:@"getSelection().setBaseAndExtent(%@, %tu, %@, %tu)", base, baseOffset, extent, extentOffset] completionHandler:nil];
+}
+
 @end
 
 namespace TestWebKitAPI {
@@ -70,6 +82,15 @@
     return webView;
 }
 
+static RetainPtr<TestWKWebView> webViewForEditActionTestingWithPageNamed(NSString *testPageName)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+    [webView synchronouslyLoadTestPageNamed:testPageName];
+    [webView _setEditable:YES];
+    [webView stringByEvaluatingJavaScript:@"getSelection().setPosition(document.body, 1)"];
+    return webView;
+}
+
 static RetainPtr<TestWKWebView> webViewForEditActionTesting()
 {
     return webViewForEditActionTesting(@"<div>WebKit</div>");
@@ -79,17 +100,17 @@
 {
     auto webView = webViewForEditActionTesting(@"<ol><li>Foo</li><ol><li id='bar'>Bar</li></ol><ul><li id='baz'>Baz</li></ul></ol>");
 
-    [webView evaluateJavaScript:@"getSelection().setPosition(bar, 0)" completionHandler:nil];
+    [webView setPosition:@"bar" offset:0];
     [webView _decreaseListLevel:nil];
     EXPECT_TRUE([webView querySelectorExists:@"ol > li#bar"]);
     EXPECT_TRUE([webView querySelectorExists:@"ol > ul > li#baz"]);
 
-    [webView evaluateJavaScript:@"getSelection().setPosition(baz, 0)" completionHandler:nil];
+    [webView setPosition:@"baz" offset:0];
     [webView _decreaseListLevel:nil];
     EXPECT_TRUE([webView querySelectorExists:@"ol > li#bar"]);
     EXPECT_TRUE([webView querySelectorExists:@"ol > li#baz"]);
 
-    [webView evaluateJavaScript:@"getSelection().setBaseAndExtent(bar, 0, baz, 1)" completionHandler:nil];
+    [webView setBase:@"bar" baseOffset:0 extent:@"baz" extentOffset:1];
     [webView _increaseListLevel:nil];
     EXPECT_TRUE([webView querySelectorExists:@"ol > ol > li#bar"]);
     EXPECT_TRUE([webView querySelectorExists:@"ol > ol > li#baz"]);
@@ -99,6 +120,23 @@
     EXPECT_TRUE([webView querySelectorExists:@"ol > li#baz"]);
 }
 
+TEST(WKWebViewEditActions, ChangeListType)
+{
+    auto webView = webViewForEditActionTestingWithPageNamed(@"editable-nested-lists");
+
+    [webView setPosition:@"one" offset:1];
+    [webView _changeListType:nil];
+    EXPECT_TRUE([webView querySelectorExists:@"ol.list > li#one"]);
+    EXPECT_TRUE([webView querySelectorExists:@"ol.list > li#four"]);
+
+    [webView setBase:@"two" baseOffset:0 extent:@"two" extentOffset:1];
+    [webView _changeListType:nil];
+    EXPECT_TRUE([webView querySelectorExists:@"ul.list > li#two"]);
+    EXPECT_TRUE([webView querySelectorExists:@"ul.list > li#three"]);
+    EXPECT_WK_STREQ("rgb(255, 0, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(document.querySelector('#two')).color"]);
+    EXPECT_WK_STREQ("rgb(255, 0, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(document.querySelector('#three')).color"]);
+}
+
 TEST(WKWebViewEditActions, NestedListInsertion)
 {
     auto webView = webViewForEditActionTesting();

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/editable-nested-lists.html (0 => 238080)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/editable-nested-lists.html	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/editable-nested-lists.html	2018-11-12 01:39:27 UTC (rev 238080)
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<body contenteditable>
+<ul class="list">
+    <li id="one">one</li>
+    <ol class="list" style="color: red">
+        <li id="two">two</li>
+        <li id="three">three</li>
+    </ol>
+    <li id="four">four</li>
+    <pre>
+        <ol class="list">
+            <li id="five">five</li>
+            <li id="six">six</li>
+        </ol>
+    </pre>
+</ul>
+</body>
+<script>
+    document.body.focus();
+</script>
+</html>
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to