From 3cb405965c7e6cfa9864f242da40e328f2be89d4 Mon Sep 17 00:00:00 2001 From: Alex Vincent Date: Thu, 28 May 2020 00:58:24 +0000 Subject: [PATCH] Bug 1626015 - Implement ParentNode#ReplaceChildren. r=emilio Differential Revision: https://phabricator.services.mozilla.com/D75891 --- dom/base/nsINode.cpp | 29 +++++++ dom/base/nsINode.h | 2 + dom/webidl/ParentNode.webidl | 2 + .../meta/dom/idlharness.window.js.ini | 34 --------- .../nodes/ParentNode-replaceChildren.html.ini | 76 ------------------- .../dom/nodes/ParentNode-replaceChildren.html | 14 ++-- 6 files changed, 40 insertions(+), 117 deletions(-) delete mode 100644 testing/web-platform/meta/dom/nodes/ParentNode-replaceChildren.html.ini diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 4fa19f091d3e..7c0d4bd261bf 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -2025,6 +2025,35 @@ void nsINode::Append(const Sequence& aNodes, AppendChild(*node, aRv); } +// https://dom.spec.whatwg.org/#dom-parentnode-replacechildren +void nsINode::ReplaceChildren(const Sequence& aNodes, + ErrorResult& aRv) { + nsCOMPtr doc = OwnerDoc(); + nsCOMPtr node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv); + if (aRv.Failed()) { + return; + } + + EnsurePreInsertionValidity(*node, nullptr, aRv); + if (aRv.Failed()) { + return; + } + + // Needed when used in combination with contenteditable (maybe) + mozAutoDocUpdate updateBatch(doc, true); + + nsAutoMutationBatch mb(this, true, false); + + // Replace all with node within this. + while (mFirstChild) { + RemoveChildNode(mFirstChild, true); + } + mb.RemovalDone(); + + AppendChild(*node, aRv); + mb.NodesAdded(); +} + void nsINode::RemoveChildNode(nsIContent* aKid, bool aNotify) { // NOTE: This function must not trigger any calls to // Document::GetRootElement() calls until *after* it has removed aKid from diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h index 52af71eae489..8a58b9e21cb6 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -2033,6 +2033,8 @@ class nsINode : public mozilla::dom::EventTarget { ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT void Append(const Sequence& aNodes, ErrorResult& aRv); + MOZ_CAN_RUN_SCRIPT void ReplaceChildren( + const Sequence& aNodes, ErrorResult& aRv); void GetBoxQuads(const BoxQuadOptions& aOptions, nsTArray>& aResult, CallerType aCallerType, diff --git a/dom/webidl/ParentNode.webidl b/dom/webidl/ParentNode.webidl index 1d6244a4f60a..a2c43daa2aa0 100644 --- a/dom/webidl/ParentNode.webidl +++ b/dom/webidl/ParentNode.webidl @@ -28,4 +28,6 @@ interface mixin ParentNode { void prepend((Node or DOMString)... nodes); [CEReactions, Throws, Unscopable] void append((Node or DOMString)... nodes); + [CEReactions, Throws, Unscopable] + void replaceChildren((Node or DOMString)... nodes); }; diff --git a/testing/web-platform/meta/dom/idlharness.window.js.ini b/testing/web-platform/meta/dom/idlharness.window.js.ini index 0f497e539032..1458c6571b18 100644 --- a/testing/web-platform/meta/dom/idlharness.window.js.ini +++ b/testing/web-platform/meta/dom/idlharness.window.js.ini @@ -6,37 +6,3 @@ [ShadowRoot interface: attribute onslotchange] expected: FAIL - - [Element interface: element must inherit property "replaceChildren((Node or DOMString)...)" with the proper type] - expected: FAIL - - [Document interface: calling replaceChildren((Node or DOMString)...) on xmlDoc with too few arguments must throw TypeError] - expected: FAIL - - [Document interface: calling replaceChildren((Node or DOMString)...) on new Document() with too few arguments must throw TypeError] - expected: FAIL - - [DocumentFragment interface: document.createDocumentFragment() must inherit property "replaceChildren((Node or DOMString)...)" with the proper type] - expected: FAIL - - [DocumentFragment interface: operation replaceChildren((Node or DOMString)...)] - expected: FAIL - - [Element interface: operation replaceChildren((Node or DOMString)...)] - expected: FAIL - - [Document interface: operation replaceChildren((Node or DOMString)...)] - expected: FAIL - - [Element interface: calling replaceChildren((Node or DOMString)...) on element with too few arguments must throw TypeError] - expected: FAIL - - [Document interface: new Document() must inherit property "replaceChildren((Node or DOMString)...)" with the proper type] - expected: FAIL - - [DocumentFragment interface: calling replaceChildren((Node or DOMString)...) on document.createDocumentFragment() with too few arguments must throw TypeError] - expected: FAIL - - [Document interface: xmlDoc must inherit property "replaceChildren((Node or DOMString)...)" with the proper type] - expected: FAIL - diff --git a/testing/web-platform/meta/dom/nodes/ParentNode-replaceChildren.html.ini b/testing/web-platform/meta/dom/nodes/ParentNode-replaceChildren.html.ini deleted file mode 100644 index ae9d14fd80b6..000000000000 --- a/testing/web-platform/meta/dom/nodes/ParentNode-replaceChildren.html.ini +++ /dev/null @@ -1,76 +0,0 @@ -[ParentNode-replaceChildren.html] - [DocumentFragment.replaceChildren() with null as an argument, on a parent having a child.] - expected: FAIL - - [DocumentFragment.replaceChildren() with only text as an argument, on a parent having no child.] - expected: FAIL - - [Element.replaceChildren() with null as an argument, on a parent having no child.] - expected: FAIL - - [Element.replaceChildren() without any argument, on a parent having no child.] - expected: FAIL - - [If node is a host-including inclusive ancestor of parent, then throw a HierarchyRequestError DOMException.] - expected: FAIL - - [If node is an Element and parent is a document with another element, then throw a HierarchyRequestError DOMException.] - expected: FAIL - - [DocumentFragment.replaceChildren() with null as an argument, on a parent having no child.] - expected: FAIL - - [DocumentFragment.replaceChildren() with one element and text as argument, on a parent having a child.] - expected: FAIL - - [Element.replaceChildren() with null as an argument, on a parent having a child.] - expected: FAIL - - [DocumentFragment.replaceChildren() with only one element as an argument, on a parent having no child.] - expected: FAIL - - [Element.replaceChildren() should move nodes in the right order] - expected: FAIL - - [If node is a Text node and parent is a document, then throw a HierarchyRequestError DOMException.] - expected: FAIL - - [If node is a DocumentFragment with an element and parent is a document with another element, then throw a HierarchyRequestError DOMException.] - expected: FAIL - - [DocumentFragment.replaceChildren() with undefined as an argument, on a parent having no child.] - expected: FAIL - - [If node is a doctype and parent is not a document, then throw a HierarchyRequestError DOMException.] - expected: FAIL - - [If node is a doctype and parent is a document with another doctype, then throw a HierarchyRequestError DOMException.] - expected: FAIL - - [If node is a DocumentFragment with multiple elements and parent is a document, then throw a HierarchyRequestError DOMException.] - expected: FAIL - - [Element.replaceChildren() with undefined as an argument, on a parent having no child.] - expected: FAIL - - [Element.replaceChildren() with only one element as an argument, on a parent having no child.] - expected: FAIL - - [Element.replaceChildren() with one element and text as argument, on a parent having a child.] - expected: FAIL - - [DocumentFragment.replaceChildren() should move nodes in the right order] - expected: FAIL - - [If node is a doctype and parent is a document with an element, then throw a HierarchyRequestError DOMException.] - expected: FAIL - - [Element.replaceChildren() with only text as an argument, on a parent having no child.] - expected: FAIL - - [DocumentFragment.replaceChildren() without any argument, on a parent having no child.] - expected: FAIL - - [If node is not a DocumentFragment, DocumentType, Element, Text, ProcessingInstruction, or Comment node, then throw a HierarchyRequestError DOMException.] - expected: FAIL - diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-replaceChildren.html b/testing/web-platform/tests/dom/nodes/ParentNode-replaceChildren.html index 6557db441284..b1c1008284bb 100644 --- a/testing/web-platform/tests/dom/nodes/ParentNode-replaceChildren.html +++ b/testing/web-platform/tests/dom/nodes/ParentNode-replaceChildren.html @@ -94,14 +94,14 @@ const observer = new MutationObserver(mutations => { t.step(() => { - assert_equals(phase, 1); - assert_equals(mutations.length, 1); + assert_equals(phase, 1, "phase"); + assert_equals(mutations.length, 1, "mutations.length"); const mutation = mutations[0]; - assert_equals(mutation.type, "childList"); - assert_equals(mutation.addedNodes.length, 2); - assert_array_equals([...mutation.addedNodes], insertions); - assert_equals(mutation.removedNodes.length, 2); - assert_array_equals([...mutation.removedNodes], children); + assert_equals(mutation.type, "childList", "mutation.type"); + assert_equals(mutation.addedNodes.length, 2, "added nodes length"); + assert_array_equals([...mutation.addedNodes], insertions, "added nodes"); + assert_equals(mutation.removedNodes.length, 2, "removed nodes length"); + assert_array_equals([...mutation.removedNodes], children, "removed nodes"); }); t.done(); });