Web Inspector: support undo/redo of insertAdjacentHTML
authorwebkit@devinrousso.com <webkit@devinrousso.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Nov 2017 23:12:01 +0000 (23:12 +0000)
committerwebkit@devinrousso.com <webkit@devinrousso.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Nov 2017 23:12:01 +0000 (23:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179283

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

* inspector/protocol/DOM.json:
Add `insertAdjacentHTML` command that executes an undoable version of `insertAdjacentHTML`
on the given node.

Source/WebCore:

Test: inspector/dom/insertAdjacentHTML.html

Create another version of Element::insertAdjacentHTML that keeps track of the nodes that are
added. This is necessary because the children of a DocumentFragment are removed when it is
added to a ContainerNode. In this way, it is possible to remove those nodes during an undo.

* dom/Element.h:
* dom/Element.cpp:
(WebCore::Element::insertAdjacentHTML):

* inspector/DOMEditor.h:
* inspector/DOMEditor.cpp:
(WebCore::DOMEditor::insertAdjacentHTML):
Drive-by fix: sort functions and class declarations.

* inspector/agents/InspectorDOMAgent.h:
* inspector/agents/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::insertAdjacentHTML):

Source/WebInspectorUI:

* UserInterface/Models/DOMNode.js:
(WI.DOMNode.prototype.insertAdjacentHTML):

* UserInterface/Views/DOMTreeElement.js:
(WI.DOMTreeElement.prototype._startEditingAsHTML):
Drive-by: only attempt to update the cursor if an initialValue is supplied.
LayoutTests:

* inspector/dom/insertAdjacentHTML-expected.txt: Added.
* inspector/dom/insertAdjacentHTML.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@224648 268f45cc-cd09-0410-ab3c-d52691b4dbfc

18 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/dom/insertAdjacentHTML-expected.txt [new file with mode: 0644]
LayoutTests/inspector/dom/insertAdjacentHTML.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/protocol/DOM.json
Source/WebCore/ChangeLog
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Element.h
Source/WebCore/inspector/DOMEditor.cpp
Source/WebCore/inspector/DOMEditor.h
Source/WebCore/inspector/InspectorHistory.cpp
Source/WebCore/inspector/InspectorHistory.h
Source/WebCore/inspector/agents/InspectorCSSAgent.cpp
Source/WebCore/inspector/agents/InspectorDOMAgent.cpp
Source/WebCore/inspector/agents/InspectorDOMAgent.h
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Models/DOMNode.js
Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js

index ba605bf..49fca39 100644 (file)
@@ -1,3 +1,13 @@
+2017-11-09  Devin Rousso  <webkit@devinrousso.com>
+
+        Web Inspector: support undo/redo of insertAdjacentHTML
+        https://bugs.webkit.org/show_bug.cgi?id=179283
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/dom/insertAdjacentHTML-expected.txt: Added.
+        * inspector/dom/insertAdjacentHTML.html: Added.
+
 2017-11-09  Maciej Stachowiak  <mjs@apple.com>
 
         Remove support for iOS-only softbank-sjis encoding if possible
diff --git a/LayoutTests/inspector/dom/insertAdjacentHTML-expected.txt b/LayoutTests/inspector/dom/insertAdjacentHTML-expected.txt
new file mode 100644 (file)
index 0000000..0fa4ca3
--- /dev/null
@@ -0,0 +1,32 @@
+Test for DOM.insertAdjacentHTML.
+
+
+== Running test suite: DOM.insertAdjacentHTML
+-- Running test case: DOM.insertAdjacentHTML.beforebegin
+PASS: The given HTML should have been added to the DOM tree.
+PASS: The given HTML should have been removed from the DOM tree.
+PASS: The given HTML should have been added back to the DOM tree.
+
+-- Running test case: DOM.insertAdjacentHTML.afterbegin
+PASS: The given HTML should have been added to the DOM tree.
+PASS: The given HTML should have been removed from the DOM tree.
+PASS: The given HTML should have been added back to the DOM tree.
+
+-- Running test case: DOM.insertAdjacentHTML.beforeend
+PASS: The given HTML should have been added to the DOM tree.
+PASS: The given HTML should have been removed from the DOM tree.
+PASS: The given HTML should have been added back to the DOM tree.
+
+-- Running test case: DOM.insertAdjacentHTML.afterend
+PASS: The given HTML should have been added to the DOM tree.
+PASS: The given HTML should have been removed from the DOM tree.
+PASS: The given HTML should have been added back to the DOM tree.
+
+-- Running test case: DOM.insertAdjacentHTML.InvalidNodeId
+PASS: Should produce an error.
+PASS: Error: Could not find node with given id
+
+-- Running test case: DOM.insertAdjacentHTML.InvalidPosition
+PASS: Should produce an error.
+PASS: Error: SyntaxError
+
diff --git a/LayoutTests/inspector/dom/insertAdjacentHTML.html b/LayoutTests/inspector/dom/insertAdjacentHTML.html
new file mode 100644 (file)
index 0000000..64b648c
--- /dev/null
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script>
+function test()
+{
+    let domNode;
+
+    let suite = InspectorTest.createAsyncSuite("DOM.insertAdjacentHTML");
+
+    const positions = [
+        "beforebegin",
+        "afterbegin",
+        "beforeend",
+        "afterend",
+    ];
+
+    for (let position of positions) {
+        suite.addTestCase({
+            name: `DOM.insertAdjacentHTML.${position}`,
+            async test() {
+                let html = `<div id="${position}"></div>`;
+                await DOMAgent.insertAdjacentHTML(domNode.id, position, html);
+
+                let insertAdjacentHTMLResult = await DOMAgent.getOuterHTML(domNode.parentNode.id);
+                InspectorTest.expectThat(insertAdjacentHTMLResult.outerHTML.includes(html), "The given HTML should have been added to the DOM tree.")
+
+                await DOMAgent.undo();
+
+                let undoResult = await DOMAgent.getOuterHTML(domNode.parentNode.id);
+                InspectorTest.expectThat(!undoResult.outerHTML.includes(html), "The given HTML should have been removed from the DOM tree.")
+
+                await DOMAgent.redo();
+
+                let redoResult = await DOMAgent.getOuterHTML(domNode.parentNode.id);
+                InspectorTest.expectThat(redoResult.outerHTML.includes(html), "The given HTML should have been added back to the DOM tree.")
+            }
+        });
+    }
+
+    suite.addTestCase({
+        name: "DOM.insertAdjacentHTML.InvalidNodeId",
+        async test() {
+            try {
+                const nodeId = 9999999;
+                const position = "afterbegin";
+                const html = "";
+                await DOMAgent.insertAdjacentHTML(nodeId, position, html);
+            } catch (error) {
+                InspectorTest.expectThat(error, "Should produce an error.");
+                InspectorTest.pass("Error: " + error.message);
+            }
+        }
+    });
+
+    suite.addTestCase({
+        name: "DOM.insertAdjacentHTML.InvalidPosition",
+        async test() {
+            try {
+                const position = "INVALID_POSITION";
+                const html = "";
+                await DOMAgent.insertAdjacentHTML(domNode.id, position, html);
+            } catch (error) {
+                InspectorTest.expectThat(error, "Should produce an error.");
+                InspectorTest.pass("Error: " + error.message);
+            }
+        }
+    });
+
+    WI.domTreeManager.requestDocument((documentNode) => {
+        WI.domTreeManager.querySelector(documentNode.id, "#reference", (nodeId) => {
+            domNode = WI.domTreeManager.nodeForId(nodeId);
+            InspectorTest.assert(domNode, `Node with id "reference" should exist.`);
+
+            suite.runTestCasesAndFinish();
+        });
+    });
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Test for DOM.insertAdjacentHTML.</p>
+
+    <div id="container"><div id="reference"></div></div>
+</body>
+</html>
index 284de35..283f32f 100644 (file)
@@ -1,3 +1,14 @@
+2017-11-09  Devin Rousso  <webkit@devinrousso.com>
+
+        Web Inspector: support undo/redo of insertAdjacentHTML
+        https://bugs.webkit.org/show_bug.cgi?id=179283
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/protocol/DOM.json:
+        Add `insertAdjacentHTML` command that executes an undoable version of `insertAdjacentHTML`
+        on the given node.
+
 2017-11-09  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Make domain availability a list of types instead of a single type
index f691722..bdd988d 100644 (file)
             ]
         },
         {
+            "name": "insertAdjacentHTML",
+            "parameters": [
+                { "name": "nodeId", "$ref": "NodeId" },
+                { "name": "position", "type": "string" },
+                { "name": "html", "type": "string" }
+            ]
+        },
+        {
             "name": "performSearch",
             "description": "Searches for a given string in the DOM tree. Use <code>getSearchResults</code> to access search results or <code>cancelSearch</code> to end this search session.",
             "parameters": [
index 5dc03d9..a21161a 100644 (file)
@@ -1,3 +1,29 @@
+2017-11-09  Devin Rousso  <webkit@devinrousso.com>
+
+        Web Inspector: support undo/redo of insertAdjacentHTML
+        https://bugs.webkit.org/show_bug.cgi?id=179283
+
+        Reviewed by Joseph Pecoraro.
+
+        Test: inspector/dom/insertAdjacentHTML.html
+
+        Create another version of Element::insertAdjacentHTML that keeps track of the nodes that are
+        added. This is necessary because the children of a DocumentFragment are removed when it is
+        added to a ContainerNode. In this way, it is possible to remove those nodes during an undo.
+
+        * dom/Element.h:
+        * dom/Element.cpp:
+        (WebCore::Element::insertAdjacentHTML):
+
+        * inspector/DOMEditor.h:
+        * inspector/DOMEditor.cpp:
+        (WebCore::DOMEditor::insertAdjacentHTML):
+        Drive-by fix: sort functions and class declarations.
+
+        * inspector/agents/InspectorDOMAgent.h:
+        * inspector/agents/InspectorDOMAgent.cpp:
+        (WebCore::InspectorDOMAgent::insertAdjacentHTML):
+
 2017-11-09  Zalan Bujtas  <zalan@apple.com>
 
         [LayoutState cleanup] Remove redundant LayoutState c'tor
index 904cfb0..a71d88e 100644 (file)
@@ -3641,7 +3641,7 @@ static ExceptionOr<Ref<Element>> contextElementForInsertion(const String& where,
 }
 
 // https://w3c.github.io/DOM-Parsing/#dom-element-insertadjacenthtml
-ExceptionOr<void> Element::insertAdjacentHTML(const String& where, const String& markup)
+ExceptionOr<void> Element::insertAdjacentHTML(const String& where, const String& markup, std::optional<NodeVector&> addedNodes)
 {
     // Steps 1 and 2.
     auto contextElement = contextElementForInsertion(where, *this);
@@ -3651,6 +3651,13 @@ ExceptionOr<void> Element::insertAdjacentHTML(const String& where, const String&
     auto fragment = createFragmentForInnerOuterHTML(contextElement.releaseReturnValue(), markup, AllowScriptingContent);
     if (fragment.hasException())
         return fragment.releaseException();
+
+    if (UNLIKELY(addedNodes)) {
+        // Must be called before insertAdjacent, as otherwise the children of fragment will be moved
+        // to their new parent and will be harder to keep track of.
+        *addedNodes = collectChildNodes(fragment.returnValue());
+    }
+
     // Step 4.
     auto result = insertAdjacent(where, fragment.releaseReturnValue());
     if (result.hasException())
@@ -3658,6 +3665,11 @@ ExceptionOr<void> Element::insertAdjacentHTML(const String& where, const String&
     return { };
 }
 
+ExceptionOr<void> Element::insertAdjacentHTML(const String& where, const String& markup)
+{
+    return insertAdjacentHTML(where, markup, std::nullopt);
+}
+
 ExceptionOr<void> Element::insertAdjacentText(const String& where, const String& text)
 {
     auto result = insertAdjacent(where, document().createTextNode(text));
index 53a51cc..3f4cf4d 100644 (file)
@@ -312,6 +312,8 @@ public:
     WEBCORE_EXPORT void setTabIndex(int);
     virtual RefPtr<Element> focusDelegate();
 
+    ExceptionOr<void> insertAdjacentHTML(const String& where, const String& html, std::optional<NodeVector&> addedNodes);
+
     WEBCORE_EXPORT ExceptionOr<Element*> insertAdjacentElement(const String& where, Element& newChild);
     WEBCORE_EXPORT ExceptionOr<void> insertAdjacentHTML(const String& where, const String& html);
     WEBCORE_EXPORT ExceptionOr<void> insertAdjacentText(const String& where, const String& text);
index dfbe4c3..3493b01 100644 (file)
@@ -47,7 +47,7 @@ class DOMEditor::RemoveChildAction final : public InspectorHistory::Action {
     WTF_MAKE_NONCOPYABLE(RemoveChildAction);
 public:
     RemoveChildAction(Node& parentNode, Node& node)
-        : Action("RemoveChild")
+        : InspectorHistory::Action()
         , m_parentNode(parentNode)
         , m_node(node)
     {
@@ -78,7 +78,7 @@ private:
 class DOMEditor::InsertBeforeAction final : public InspectorHistory::Action {
 public:
     InsertBeforeAction(Node& parentNode, Ref<Node>&& node, Node* anchorNode)
-        : Action("InsertBefore")
+        : InspectorHistory::Action()
         , m_parentNode(parentNode)
         , m_node(WTFMove(node))
         , m_anchorNode(anchorNode)
@@ -127,7 +127,7 @@ class DOMEditor::RemoveAttributeAction final : public InspectorHistory::Action {
     WTF_MAKE_NONCOPYABLE(RemoveAttributeAction);
 public:
     RemoveAttributeAction(Element& element, const String& name)
-        : Action("RemoveAttribute")
+        : InspectorHistory::Action()
         , m_element(element)
         , m_name(name)
     {
@@ -160,7 +160,7 @@ class DOMEditor::SetAttributeAction final : public InspectorHistory::Action {
     WTF_MAKE_NONCOPYABLE(SetAttributeAction);
 public:
     SetAttributeAction(Element& element, const AtomicString& name, const AtomicString& value)
-        : Action("SetAttribute")
+        : InspectorHistory::Action()
         , m_element(element)
         , m_name(name)
         , m_value(value)
@@ -197,7 +197,7 @@ private:
 class DOMEditor::SetOuterHTMLAction final : public InspectorHistory::Action {
 public:
     SetOuterHTMLAction(Node& node, const String& html)
-        : Action("SetOuterHTML")
+        : InspectorHistory::Action()
         , m_node(node)
         , m_nextSibling(node.nextSibling())
         , m_html(html)
@@ -239,11 +239,50 @@ private:
     DOMEditor m_domEditor { m_history };
 };
 
+class DOMEditor::InsertAdjacentHTMLAction final : public InspectorHistory::Action {
+    WTF_MAKE_NONCOPYABLE(InsertAdjacentHTMLAction);
+public:
+    InsertAdjacentHTMLAction(Element& element, const String& position, const String& html)
+        : InspectorHistory::Action()
+        , m_element(element)
+        , m_position(position)
+        , m_html(html)
+    {
+    }
+
+private:
+    ExceptionOr<void> perform() final
+    {
+        return redo();
+    }
+
+    ExceptionOr<void> undo() final
+    {
+        for (auto& addedNode : m_addedNodes)
+            addedNode->remove();
+        m_addedNodes.clear();
+        return { };
+    }
+
+    ExceptionOr<void> redo() final
+    {
+        auto result = m_element->insertAdjacentHTML(m_position, m_html, m_addedNodes);
+        if (result.hasException())
+            return result.releaseException();
+        return { };
+    }
+
+    Ref<Element> m_element;
+    NodeVector m_addedNodes;
+    String m_position;
+    String m_html;
+};
+
 class DOMEditor::ReplaceWholeTextAction final : public InspectorHistory::Action {
     WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction);
 public:
     ReplaceWholeTextAction(Text& textNode, const String& text)
-        : Action("ReplaceWholeText")
+        : InspectorHistory::Action()
         , m_textNode(textNode)
         , m_text(text)
     {
@@ -277,7 +316,7 @@ class DOMEditor::ReplaceChildNodeAction final: public InspectorHistory::Action {
     WTF_MAKE_NONCOPYABLE(ReplaceChildNodeAction);
 public:
     ReplaceChildNodeAction(Node& parentNode, Ref<Node>&& newNode, Node& oldNode)
-        : Action("ReplaceChildNode")
+        : InspectorHistory::Action()
         , m_parentNode(parentNode)
         , m_newNode(WTFMove(newNode))
         , m_oldNode(oldNode)
@@ -309,7 +348,7 @@ class DOMEditor::SetNodeValueAction final : public InspectorHistory::Action {
     WTF_MAKE_NONCOPYABLE(SetNodeValueAction);
 public:
     SetNodeValueAction(Node& node, const String& value)
-        : Action("SetNodeValue")
+        : InspectorHistory::Action()
         , m_node(node)
         , m_value(value)
     {
@@ -374,6 +413,11 @@ ExceptionOr<void> DOMEditor::setOuterHTML(Node& node, const String& html, Node*&
     return result;
 }
 
+ExceptionOr<void> DOMEditor::insertAdjacentHTML(Element& element, const String& where, const String& html)
+{
+    return m_history.perform(std::make_unique<InsertAdjacentHTMLAction>(element, where, html));
+}
+
 ExceptionOr<void> DOMEditor::replaceWholeText(Text& textNode, const String& text)
 {
     return m_history.perform(std::make_unique<ReplaceWholeTextAction>(textNode, text));
@@ -422,6 +466,11 @@ bool DOMEditor::setOuterHTML(Node& node, const String& html, Node*& newNode, Err
     return populateErrorString(setOuterHTML(node, html, newNode), errorString);
 }
 
+bool DOMEditor::insertAdjacentHTML(Element& element, const String& where, const String& html, ErrorString& errorString)
+{
+    return populateErrorString(insertAdjacentHTML(element, where, html), errorString);
+}
+
 bool DOMEditor::replaceWholeText(Text& textNode, const String& text, ErrorString& errorString)
 {
     return populateErrorString(replaceWholeText(textNode, text), errorString);
index e95a936..87ab943 100644 (file)
@@ -55,6 +55,7 @@ public:
     ExceptionOr<void> replaceWholeText(Text&, const String& text);
     ExceptionOr<void> replaceChild(Node& parentNode, Ref<Node>&& newNode, Node& oldNode);
     ExceptionOr<void> setNodeValue(Node& parentNode, const String& value);
+    ExceptionOr<void> insertAdjacentHTML(Element&, const String& where, const String& html);
 
     bool insertBefore(Node& parentNode, Ref<Node>&&, Node* anchorNode, ErrorString&);
     bool removeChild(Node& parentNode, Node&, ErrorString&);
@@ -62,9 +63,11 @@ public:
     bool removeAttribute(Element&, const String& name, ErrorString&);
     bool setOuterHTML(Node&, const String& html, Node*& newNode, ErrorString&);
     bool replaceWholeText(Text&, const String& text, ErrorString&);
+    bool insertAdjacentHTML(Element&, const String& where, const String& html, ErrorString&);
 
 private:
     class DOMAction;
+    class InsertAdjacentHTMLAction;
     class InsertBeforeAction;
     class RemoveAttributeAction;
     class RemoveChildAction;
index 2c0816e..00d5f18 100644 (file)
 namespace WebCore {
 
 class UndoableStateMark : public InspectorHistory::Action {
-public:
-    UndoableStateMark()
-        : Action("[UndoableState]")
-    {
-    }
-
 private:
     ExceptionOr<void> perform() final { return { }; }
     ExceptionOr<void> undo() final { return { }; }
index 318fca3..b1e1fc2 100644 (file)
@@ -41,13 +41,7 @@ public:
     class Action {
         WTF_MAKE_FAST_ALLOCATED;
     public:
-        explicit Action(const String& name)
-            : m_name { name }
-        {
-        }
-
         virtual ~Action() = default;
-        virtual String toString() { return m_name; }
 
         virtual String mergeId() { return emptyString(); }
         virtual void merge(std::unique_ptr<Action>) { };
index aa935ab..5c40131 100644 (file)
@@ -104,8 +104,8 @@ static unsigned computePseudoClassMask(const InspectorArray& pseudoClassArray)
 class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
     WTF_MAKE_NONCOPYABLE(StyleSheetAction);
 public:
-    StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet)
-        : InspectorHistory::Action(name)
+    StyleSheetAction(InspectorStyleSheet* styleSheet)
+        : InspectorHistory::Action()
         , m_styleSheet(styleSheet)
     {
     }
@@ -118,7 +118,7 @@ class InspectorCSSAgent::SetStyleSheetTextAction final : public InspectorCSSAgen
     WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
 public:
     SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text)
-        : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetStyleSheetText"), styleSheet)
+        : InspectorCSSAgent::StyleSheetAction(styleSheet)
         , m_text(text)
     {
     }
@@ -170,7 +170,7 @@ class InspectorCSSAgent::SetStyleTextAction final : public InspectorCSSAgent::St
     WTF_MAKE_NONCOPYABLE(SetStyleTextAction);
 public:
     SetStyleTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& text)
-        : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetStyleText"), styleSheet)
+        : InspectorCSSAgent::StyleSheetAction(styleSheet)
         , m_cssId(cssId)
         , m_text(text)
     {
@@ -215,7 +215,7 @@ class InspectorCSSAgent::SetRuleSelectorAction final : public InspectorCSSAgent:
     WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
 public:
     SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector)
-        : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetRuleSelector"), styleSheet)
+        : InspectorCSSAgent::StyleSheetAction(styleSheet)
         , m_cssId(cssId)
         , m_selector(selector)
     {
@@ -250,7 +250,7 @@ class InspectorCSSAgent::AddRuleAction final : public InspectorCSSAgent::StyleSh
     WTF_MAKE_NONCOPYABLE(AddRuleAction);
 public:
     AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector)
-        : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("AddRule"), styleSheet)
+        : InspectorCSSAgent::StyleSheetAction(styleSheet)
         , m_selector(selector)
     {
     }
index f9d7dbf..167fda4 100644 (file)
@@ -808,6 +808,20 @@ void InspectorDOMAgent::setOuterHTML(ErrorString& errorString, int nodeId, const
         pushChildNodesToFrontend(newId);
 }
 
+void InspectorDOMAgent::insertAdjacentHTML(ErrorString& errorString, int nodeId, const String& position, const String& html)
+{
+    Node* node = assertEditableNode(errorString, nodeId);
+    if (!node)
+        return;
+
+    if (!is<Element>(node)) {
+        errorString = ASCIILiteral("Can only call insertAdjacentHTML on Elements.");
+        return;
+    }
+
+    m_domEditor->insertAdjacentHTML(downcast<Element>(*node), position, html, errorString);
+}
+
 void InspectorDOMAgent::setNodeValue(ErrorString& errorString, int nodeId, const String& value)
 {
     Node* node = assertEditableNode(errorString, nodeId);
index d942eff..5fc5446 100644 (file)
@@ -121,6 +121,7 @@ public:
     void setNodeName(ErrorString&, int nodeId, const String& name, int* newId) override;
     void getOuterHTML(ErrorString&, int nodeId, WTF::String* outerHTML) override;
     void setOuterHTML(ErrorString&, int nodeId, const String& outerHTML) override;
+    void insertAdjacentHTML(ErrorString&, int nodeId, const String& position, const String& html) override;
     void setNodeValue(ErrorString&, int nodeId, const String& value) override;
     void getEventListenersForNode(ErrorString&, int nodeId, const WTF::String* const objectGroup, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::DOM::EventListener>>& listenersArray) override;
     void setEventListenerDisabled(ErrorString&, int eventListenerId, bool disabled) override;
index a40d358..8aaf565 100644 (file)
@@ -1,3 +1,17 @@
+2017-11-09  Devin Rousso  <webkit@devinrousso.com>
+
+        Web Inspector: support undo/redo of insertAdjacentHTML
+        https://bugs.webkit.org/show_bug.cgi?id=179283
+
+        Reviewed by Joseph Pecoraro.
+
+        * UserInterface/Models/DOMNode.js:
+        (WI.DOMNode.prototype.insertAdjacentHTML):
+
+        * UserInterface/Views/DOMTreeElement.js:
+        (WI.DOMTreeElement.prototype._startEditingAsHTML):
+        Drive-by: only attempt to update the cursor if an initialValue is supplied.
+
 2017-11-09  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Make domain availability a list of types instead of a single type
index 94dd208..1de69f1 100644 (file)
@@ -505,16 +505,20 @@ WI.DOMNode = class DOMNode extends WI.Object
         if (this.nodeType() !== Node.ELEMENT_NODE)
             return;
 
-        // FIXME: <https://webkit.org/b/179283> Web Inspector: support undo/redo of insertAdjacentHTML
+        // COMPATIBILITY (iOS 11.0): DOM.insertAdjacentHTML did not exist.
+        if (!DOMAgent.insertAdjacentHTML) {
+            WI.RemoteObject.resolveNode(this).then((object) => {
+                function inspectedPage_node_insertAdjacentHTML(position, html) {
+                    this.insertAdjacentHTML(position, html);
+                }
 
-        WI.RemoteObject.resolveNode(this).then((object) => {
-            function inspectedPage_node_insertAdjacentHTML(position, html) {
-                this.insertAdjacentHTML(position, html);
-            }
+                object.callFunction(inspectedPage_node_insertAdjacentHTML, [position, html]);
+                object.release();
+            });
+            return;
+        }
 
-            object.callFunction(inspectedPage_node_insertAdjacentHTML, [position, html]);
-            object.release();
-        });
+        DOMAgent.insertAdjacentHTML(this.id, position, html, this._makeUndoableCallback());
     }
 
     removeNode(callback)
index ca79901..2e1fb3a 100644 (file)
@@ -1044,7 +1044,7 @@ WI.DOMTreeElement = class DOMTreeElement extends WI.TreeElement
         config.setMultiline(true);
         this._editing = WI.startEditing(this._htmlEditElement, config);
 
-        if (!isNaN(options.startPosition)) {
+        if (options.initialValue && !isNaN(options.startPosition)) {
             let range = document.createRange();
             range.setStart(this._htmlEditElement.firstChild, options.startPosition);
             range.collapse(true);