Rename getAssignedNodes to assignedNodes and support flattened option
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 30 Apr 2016 04:19:00 +0000 (04:19 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 30 Apr 2016 04:19:00 +0000 (04:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=157225

Reviewed by Antti Koivisto.

Source/WebCore:

Renamed getAssignedNodes and added the the support for {flattened: true/false} as spec'ed at
http://w3c.github.io/webcomponents/spec/shadow/#widl-HTMLSlotElement-assignedNodes-sequence-Node--AssignedNodesOptions-options

Test: fast/shadow-dom/HTMLSlotElement-interface.html

* html/HTMLSlotElement.cpp:
(WebCore::flattenAssignedNodes): Added.
(WebCore::HTMLSlotElement::assignedNodesForBindings): Added.
* html/HTMLSlotElement.h:
* html/HTMLSlotElement.idl:

LayoutTests:

* fast/shadow-dom/HTMLSlotElement-interface-expected.txt:
* fast/shadow-dom/HTMLSlotElement-interface.html:

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

LayoutTests/ChangeLog
LayoutTests/fast/shadow-dom/HTMLSlotElement-interface-expected.txt
LayoutTests/fast/shadow-dom/HTMLSlotElement-interface.html
Source/WebCore/ChangeLog
Source/WebCore/html/HTMLSlotElement.cpp
Source/WebCore/html/HTMLSlotElement.h
Source/WebCore/html/HTMLSlotElement.idl

index c8d848f..70c7d3b 100644 (file)
@@ -1,3 +1,13 @@
+2016-04-29  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Rename getAssignedNodes to assignedNodes and support flattened option
+        https://bugs.webkit.org/show_bug.cgi?id=157225
+
+        Reviewed by Antti Koivisto.
+
+        * fast/shadow-dom/HTMLSlotElement-interface-expected.txt:
+        * fast/shadow-dom/HTMLSlotElement-interface.html:
+
 2016-04-29  Simon Fraser  <simon.fraser@apple.com>
 
         Blur filter escapes an enclosing overflow:hidden
index d532cae..9ef6587 100644 (file)
@@ -1,8 +1,20 @@
 
 PASS HTMLSlotElement must be defined on window 
 PASS "name" attribute on HTMLSlotElement must reflect "name" attribute 
-PASS getAssignedNodes method on HTMLSlotElement must return the list of distributed nodes 
-PASS getAssignedNodes must update when slot and name attributes are modified 
-PASS getAssignedNodes must update when a default slot is introduced dynamically by a slot rename 
-PASS getAssignedNodes must update when slot elements are inserted or removed 
+PASS assignedNodes() on a HTMLSlotElement must return an empty array when the slot element is not in a tree or in a document tree 
+PASS assignedNodes({"flattened":false}) on a HTMLSlotElement must return an empty array when the slot element is not in a tree or in a document tree 
+PASS assignedNodes({"flattened":true}) on a HTMLSlotElement must return an empty array when the slot element is not in a tree or in a document tree 
+PASS assignedNodes() must return the list of assigned nodes when none of the assigned nodes themselves are slots 
+PASS assignedNodes({"flattened":false}) must return the list of assigned nodes when none of the assigned nodes themselves are slots 
+PASS assignedNodes({"flattened":true}) must return the list of assigned nodes when none of the assigned nodes themselves are slots 
+PASS assignedNodes() must update when slot and name attributes are modified 
+PASS assignedNodes({"flattened":false}) must update when slot and name attributes are modified 
+PASS assignedNodes({"flattened":true}) must update when slot and name attributes are modified 
+PASS assignedNodes must update when a default slot is introduced dynamically by a slot rename 
+PASS assignedNodes({"flattened":false}) must update when slot and name attributes are modified 
+PASS assignedNodes({"flattened":true}) must update when slot and name attributes are modified 
+PASS assignedNodes must update when slot elements are inserted or removed 
+PASS assignedNodes must update when slot elements are inserted or removed 
+PASS assignedNodes must update when slot elements are inserted or removed 
+PASS assignedNodes({flatten: true}) must return the distributed nodes, and assignedNodes() and assignedNodes({flatten: false}) must returned the assigned nodes 
 
index 5e99dce..af8d97b 100644 (file)
@@ -34,125 +34,236 @@ test(function () {
     assert_equals(slotElement.getAttribute('name'), 'bar', '"name" attribute must update the "name" content attribute');
 }, '"name" attribute on HTMLSlotElement must reflect "name" attribute');
 
-test(function () {
-    assert_true('getAssignedNodes' in HTMLSlotElement.prototype, '"getAssignedNodes" method must be defined on HTMLSlotElement.prototype');
+function testSlotOutsideShadowTree(options)
+{
+    test(function () {
+        assert_true('assignedNodes' in HTMLSlotElement.prototype, '"assignedNodes" method must be defined on HTMLSlotElement.prototype');
 
-    var shadowHost = document.createElement('div');
-    var child = document.createElement('p');
+        var slotElement = document.createElement('slot');
+        assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when the slot element is not in any tree');
 
-    var shadowRoot = shadowHost.attachShadow({mode: 'open'});
-    var slotElement = document.createElement('slot');
-    shadowRoot.appendChild(slotElement);
+        document.body.appendChild(slotElement);
+        assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when the slot element is in a document tree');
 
-    assert_array_equals(slotElement.getAssignedNodes(), [], 'getAssignedNodes must return an empty array when there are no nodes in the shadow tree');
+    }, 'assignedNodes(' + (options ? JSON.stringify(options) : '')
+        + ') on a HTMLSlotElement must return an empty array when the slot element is not in a tree or in a document tree');
+}
 
-    shadowHost.appendChild(child);
-    assert_array_equals(slotElement.getAssignedNodes(), [child], 'getAssignedNodes on a default slot must return an element without slot element');
+testSlotOutsideShadowTree(null);
+testSlotOutsideShadowTree({flattened: false});
+testSlotOutsideShadowTree({flattened: true});
 
-    child.setAttribute('slot', 'foo');
-    assert_array_equals(slotElement.getAssignedNodes(), [], 'getAssignedNodes on a default slot must not return an element with non-empty slot attribute');
+function testSingleLevelOfSlotting(options)
+{
+    test(function () {
+        assert_true('assignedNodes' in HTMLSlotElement.prototype, '"assignedNodes" method must be defined on HTMLSlotElement.prototype');
 
-    child.setAttribute('slot', '');
-    assert_array_equals(slotElement.getAssignedNodes(), [child], 'getAssignedNodes on a default slot must return an element with empty slot attribute');
+        var shadowHost = document.createElement('div');
+        var child = document.createElement('p');
 
-    slotElement.setAttribute('name', 'bar');
-    assert_array_equals(slotElement.getAssignedNodes(), [], 'getAssignedNodes on a named slot must not return an element with empty slot attribute');
+        var shadowRoot = shadowHost.attachShadow({mode: 'open'});
+        var slotElement = document.createElement('slot');
+        shadowRoot.appendChild(slotElement);
 
-    slotElement.setAttribute('name', '');
-    assert_array_equals(slotElement.getAssignedNodes(), [child], 'getAssignedNodes on an empty name slot must return an element with empty slot attribute');
+        assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when there are no nodes in the shadow tree');
 
-}, 'getAssignedNodes method on HTMLSlotElement must return the list of distributed nodes');
+        shadowHost.appendChild(child);
+        assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on a default slot must return an element without slot element');
 
-test(function () {
-    var shadowHost = document.createElement('div');
-    var p = document.createElement('p');
-    var b = document.createElement('b');
-    shadowHost.appendChild(p);
-    shadowHost.appendChild(b);
+        child.setAttribute('slot', 'foo');
+        assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() on a default slot must not return an element with non-empty slot attribute');
 
-    var shadowRoot = shadowHost.attachShadow({mode: 'open'});
-    var slotElement = document.createElement('slot');
-    shadowRoot.appendChild(slotElement);
+        child.setAttribute('slot', '');
+        assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on a default slot must return an element with empty slot attribute');
 
-    assert_array_equals(slotElement.getAssignedNodes(), [p, b], 'getAssignedNodes must return the distributed nodes');
+        slotElement.setAttribute('name', 'bar');
+        assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() on a named slot must not return an element with empty slot attribute');
 
-    slotElement.name = 'foo';
-    assert_array_equals(slotElement.getAssignedNodes(), [], 'getAssignedNodes must be empty when there are no matching elements for the slot name');
+        slotElement.setAttribute('name', '');
+        assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on an empty name slot must return an element with empty slot attribute');
 
-    b.slot = 'foo';
-    assert_array_equals(slotElement.getAssignedNodes(), [b], 'getAssignedNodes must return the nodes with the matching slot name');
+    }, 'assignedNodes(' + (options ? JSON.stringify(options) : '') + ') must return the list of assigned nodes when none of the assigned nodes themselves are slots');
+}
 
-    p.slot = 'foo';
-    assert_array_equals(slotElement.getAssignedNodes(), [p, b], 'getAssignedNodes must return the nodes with the matching slot name in the tree order');
+testSingleLevelOfSlotting(null);
+testSingleLevelOfSlotting({flattened: false});
+testSingleLevelOfSlotting({flattened: true});
 
-    slotElement.removeAttribute('name');
-    assert_array_equals(slotElement.getAssignedNodes(), [], 'getAssignedNodes must be empty for a default slot when all elements have "slot" attributes specified');
+function testMutatingSlottedContents(options)
+{
+    test(function () {
+        var shadowHost = document.createElement('div');
+        var p = document.createElement('p');
+        var b = document.createElement('b');
+        shadowHost.appendChild(p);
+        shadowHost.appendChild(b);
+
+        var shadowRoot = shadowHost.attachShadow({mode: 'open'});
+        var slotElement = document.createElement('slot');
+        shadowRoot.appendChild(slotElement);
 
-}, 'getAssignedNodes must update when slot and name attributes are modified');
+        assert_array_equals(slotElement.assignedNodes(options), [p, b], 'assignedNodes must return the distributed nodes');
 
-test(function () {
-    var shadowHost = document.createElement('div');
-    var child = document.createElement('span');
-    shadowHost.appendChild(child);
+        slotElement.name = 'foo';
+        assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty when there are no matching elements for the slot name');
 
-    var shadowRoot = shadowHost.attachShadow({mode: 'open'});
-    var slotElement = document.createElement('slot');
-    slotElement.name = 'foo';
-    shadowRoot.appendChild(slotElement);
+        b.slot = 'foo';
+        assert_array_equals(slotElement.assignedNodes(options), [b], 'assignedNodes must return the nodes with the matching slot name');
+
+        p.slot = 'foo';
+        assert_array_equals(slotElement.assignedNodes(options), [p, b], 'assignedNodes must return the nodes with the matching slot name in the tree order');
+
+        slotElement.removeAttribute('name');
+        assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty for a default slot when all elements have "slot" attributes specified');
+
+    }, 'assignedNodes(' + (options ? JSON.stringify(options) : '') + ') must update when slot and name attributes are modified');
+}
+
+testMutatingSlottedContents(null);
+testMutatingSlottedContents({flattened: false});
+testMutatingSlottedContents({flattened: true});
+
+function testMutatingSlotName(options)
+{
+    test(function () {
+        var shadowHost = document.createElement('div');
+        var child = document.createElement('span');
+        shadowHost.appendChild(child);
+
+        var shadowRoot = shadowHost.attachShadow({mode: 'open'});
+        var slotElement = document.createElement('slot');
+        slotElement.name = 'foo';
+        shadowRoot.appendChild(slotElement);
+
+        assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty when there are no matching elements for the slot name');
+
+        slotElement.removeAttribute('name');
+        assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes must be empty when there are no matching elements for the slot name');
+
+    }, 'assignedNodes must update when a default slot is introduced dynamically by a slot rename');
+}
+
+testMutatingSlotName(null);
+testMutatingSlottedContents({flattened: false});
+testMutatingSlottedContents({flattened: true});
 
-    assert_array_equals(slotElement.getAssignedNodes(), [], 'getAssignedNodes must be empty when there are no matching elements for the slot name');
+function testInsertingAndRemovingSlots(options)
+{
+    test(function () {
+        var shadowHost = document.createElement('div');
+        var p = document.createElement('p');
+        var text = document.createTextNode('');
+        var comment = document.createComment('');
+        var processingInstruction = document.createProcessingInstruction('target', 'data');
+        var b = document.createElement('b');
+        shadowHost.appendChild(p);
+        shadowHost.appendChild(text);
+        shadowHost.appendChild(comment);
+        shadowHost.appendChild(processingInstruction);
+        shadowHost.appendChild(b);
+
+        var shadowRoot = shadowHost.attachShadow({mode: 'open'});
 
-    slotElement.removeAttribute('name');
-    assert_array_equals(slotElement.getAssignedNodes(), [child], 'getAssignedNodes must be empty when there are no matching elements for the slot name');
+        var firstSlotElement = document.createElement('slot');
+        shadowRoot.appendChild(firstSlotElement);
 
-}, 'getAssignedNodes must update when a default slot is introduced dynamically by a slot rename');
+        var secondSlotElement = document.createElement('slot');
+        shadowRoot.appendChild(secondSlotElement);
+
+        assert_array_equals(firstSlotElement.assignedNodes(options), [p, text, b],
+            'assignedNodes on a default slot must return the elements without slot attributes and text nodes');
+        assert_array_equals(secondSlotElement.assignedNodes(options), [],
+            'assignedNodes on the second unnamed slot element must return an empty array');
+
+        shadowRoot.removeChild(firstSlotElement);
+        assert_array_equals(firstSlotElement.assignedNodes(options), [],
+            'assignedNodes on a detached formerly-default slot must return an empty array');
+        assert_array_equals(secondSlotElement.assignedNodes(options), [p, text, b],
+            'assignedNodes on the second unnamed slot element after removing the first must return the elements without slot attributes and text nodes');
+
+        shadowRoot.removeChild(secondSlotElement);
+        shadowRoot.appendChild(secondSlotElement);
+        assert_array_equals(firstSlotElement.assignedNodes(options), [],
+            'Removing and re-inserting a default slot must not change the result of assignedNodes on a detached slot');
+        assert_array_equals(secondSlotElement.assignedNodes(options), [p, text, b],
+            'Removing and re-inserting a default slot must not change the result of assignedNodes');
+
+        shadowRoot.insertBefore(firstSlotElement, secondSlotElement);
+        assert_array_equals(firstSlotElement.assignedNodes(options), [p, text, b],
+            'assignedNodes on a newly inserted unnamed slot element must return the elements without slot attributes and text nodes');
+        assert_array_equals(secondSlotElement.assignedNodes(options), [],
+            'assignedNodes on formerly-first but now second unnamed slot element must return an empty array');
+
+    }, 'assignedNodes must update when slot elements are inserted or removed');
+}
+
+testInsertingAndRemovingSlots(null);
+testInsertingAndRemovingSlots({flattened: false});
+testInsertingAndRemovingSlots({flattened: true});
 
 test(function () {
-    var shadowHost = document.createElement('div');
-    var p = document.createElement('p');
-    var text = document.createTextNode('');
-    var comment = document.createComment('');
-    var processingInstruction = document.createProcessingInstruction('target', 'data');
-    var b = document.createElement('b');
-    shadowHost.appendChild(p);
-    shadowHost.appendChild(text);
-    shadowHost.appendChild(comment);
-    shadowHost.appendChild(processingInstruction);
-    shadowHost.appendChild(b);
-
-    var shadowRoot = shadowHost.attachShadow({mode: 'open'});
-
-    var firstSlotElement = document.createElement('slot');
-    shadowRoot.appendChild(firstSlotElement);
-
-    var secondSlotElement = document.createElement('slot');
-    shadowRoot.appendChild(secondSlotElement);
-
-    assert_array_equals(firstSlotElement.getAssignedNodes(), [p, text, b],
-        'getAssignedNodes on a default slot must return the elements without slot attributes and text nodes');
-    assert_array_equals(secondSlotElement.getAssignedNodes(), [],
-        'getAssignedNodes on the second unnamed slot element must return an empty array');
-
-    shadowRoot.removeChild(firstSlotElement);
-    assert_array_equals(firstSlotElement.getAssignedNodes(), [],
-        'getAssignedNodes on a detached formerly-default slot must return an empty array');
-    assert_array_equals(secondSlotElement.getAssignedNodes(), [p, text, b],
-        'getAssignedNodes on the second unnamed slot element after removing the first must return the elements without slot attributes and text nodes');
-
-    shadowRoot.removeChild(secondSlotElement);
-    shadowRoot.appendChild(secondSlotElement);
-    assert_array_equals(firstSlotElement.getAssignedNodes(), [],
-        'Removing and re-inserting a default slot must not change the result of getAssignedNodes on a detached slot');
-    assert_array_equals(secondSlotElement.getAssignedNodes(), [p, text, b],
-        'Removing and re-inserting a default slot must not change the result of getAssignedNodes');
-
-    shadowRoot.insertBefore(firstSlotElement, secondSlotElement);
-    assert_array_equals(firstSlotElement.getAssignedNodes(), [p, text, b],
-        'getAssignedNodes on a newly inserted unnamed slot element must return the elements without slot attributes and text nodes');
-    assert_array_equals(secondSlotElement.getAssignedNodes(), [],
-        'getAssignedNodes on formerly-first but now second unnamed slot element must return an empty array');
-
-}, 'getAssignedNodes must update when slot elements are inserted or removed');
+    var outerHost = document.createElement('div');
+    var outerChild = document.createElement('span');
+    outerHost.appendChild(outerChild);
+
+    var outerShadow = outerHost.attachShadow({mode: 'closed'});
+    var innerHost = document.createElement('div');
+    var outerSlot = document.createElement('slot');
+    var innerChild = document.createElement('b');
+    outerShadow.appendChild(innerHost);
+    innerHost.appendChild(outerSlot);
+    innerHost.appendChild(innerChild);
+
+    var innerShadow = innerHost.attachShadow({mode: 'closed'});
+    var innerSlot = document.createElement('slot');
+    innerShadow.appendChild(innerSlot);
+
+    assert_array_equals(outerSlot.assignedNodes(), [outerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+    assert_array_equals(outerSlot.assignedNodes({flatten: false}), [outerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+    assert_array_equals(outerSlot.assignedNodes({flatten: true}), [outerChild], 'assignedNodes({flatten: true}) on a default slot must return the assigned nodes if they are not themselves slots');
+
+    assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+    assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+    assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
+
+    outerSlot.name = 'foo';
+    assert_array_equals(outerSlot.assignedNodes(), [], 'assignedNodes() on a named slot must return an empty array if there are no matching elements');
+    assert_array_equals(outerSlot.assignedNodes({flatten: false}), [], 'assignedNodes({flatten: false}) on a named slot must return an empty array if there are no matching elements');
+    assert_array_equals(outerSlot.assignedNodes({flatten: true}), [], 'assignedNodes({flatten: true}) on a named slot must return an empty array if there are no matching elements');
+
+    assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+    assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+    assert_array_equals(innerSlot.assignedNodes({flatten: true}), [innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
+
+    outerChild.slot = 'foo';
+    assert_array_equals(outerSlot.assignedNodes(), [outerChild], 'assignedNodes() on a named slot must return matching elements');
+    assert_array_equals(outerSlot.assignedNodes({flatten: false}), [outerChild], 'assignedNodes({flatten: false}) on a named slot must return matching elements');
+    assert_array_equals(outerSlot.assignedNodes({flatten: true}), [outerChild], 'assignedNodes({flatten: true}) on a named slot must return matching elements');
+
+    assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+    assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+    assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
+
+    var newInnerSlot = document.createElement('slot');
+    innerShadow.insertBefore(newInnerSlot, innerSlot);
+    assert_array_equals(newInnerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+    assert_array_equals(newInnerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+    assert_array_equals(newInnerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
+
+    assert_array_equals(innerSlot.assignedNodes(), [], 'assignedNodes() on a nameless slot element which appears after a default slot must return an empty array');
+    assert_array_equals(innerSlot.assignedNodes({flatten: false}), [], 'assignedNodes({flatten: false}) on a nameless slot element which appears after a default slot must return an empty array');
+    assert_array_equals(innerSlot.assignedNodes({flatten: true}), [], 'assignedNodes({flatten: true}) on a nameless slot element which appears after a default slot must return an empty array');
+
+    innerShadow.removeChild(newInnerSlot);
+    assert_array_equals(newInnerSlot.assignedNodes(), [], 'assignedNodes() must return an empty array when the slot element is not in any tree');
+    assert_array_equals(newInnerSlot.assignedNodes({flatten: false}), [], 'assignedNodes({flatten: false}) must return an empty array when the slot element is not in any tree');
+    assert_array_equals(newInnerSlot.assignedNodes({flatten: true}), [], 'assignedNodes({flatten: true}) must return an empty array when the slot element is not in any tree');
+
+    assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+    assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+    assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
+
+}, 'assignedNodes({flatten: true}) must return the distributed nodes, and assignedNodes() and assignedNodes({flatten: false}) must returned the assigned nodes');
 
 </script>
 </body>
index 6787a43..be46d04 100644 (file)
@@ -1,3 +1,21 @@
+2016-04-29  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Rename getAssignedNodes to assignedNodes and support flattened option
+        https://bugs.webkit.org/show_bug.cgi?id=157225
+
+        Reviewed by Antti Koivisto.
+
+        Renamed getAssignedNodes and added the the support for {flattened: true/false} as spec'ed at
+        http://w3c.github.io/webcomponents/spec/shadow/#widl-HTMLSlotElement-assignedNodes-sequence-Node--AssignedNodesOptions-options
+
+        Test: fast/shadow-dom/HTMLSlotElement-interface.html
+
+        * html/HTMLSlotElement.cpp:
+        (WebCore::flattenAssignedNodes): Added.
+        (WebCore::HTMLSlotElement::assignedNodesForBindings): Added.
+        * html/HTMLSlotElement.h:
+        * html/HTMLSlotElement.idl:
+
 2016-04-29  Simon Fraser  <simon.fraser@apple.com>
 
         Make clipToRect() and restoreClip() have similar signatures
index 7a23778..47c19cf 100644 (file)
@@ -28,6 +28,7 @@
 
 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
 
+#include "Dictionary.h"
 #include "ElementChildIterator.h"
 #include "Event.h"
 #include "EventNames.h"
@@ -99,6 +100,36 @@ const Vector<Node*>* HTMLSlotElement::assignedNodes() const
     return shadowRoot->assignedNodesForSlot(*this);
 }
 
+static void flattenAssignedNodes(Vector<Node*>& nodes, const Vector<Node*>& assignedNodes)
+{
+    for (Node* node : assignedNodes) {
+        if (is<HTMLSlotElement>(*node)) {
+            if (auto* innerAssignedNodes = downcast<HTMLSlotElement>(*node).assignedNodes())
+                flattenAssignedNodes(nodes, *innerAssignedNodes);
+            continue;
+        }
+        nodes.append(node);
+    }
+}
+
+const Vector<Node*> HTMLSlotElement::assignedNodesForBindings(const Dictionary& options) const
+{
+    bool shouldFlatten = false;
+    options.get("flatten", shouldFlatten);
+
+    Vector<Node*> nodes;
+    auto* assignedNodes = this->assignedNodes();
+    if (!assignedNodes)
+        return nodes;
+
+    if (shouldFlatten)
+        flattenAssignedNodes(nodes, *assignedNodes);
+    else
+        nodes = *assignedNodes;
+
+    return nodes;
+}
+
 void HTMLSlotElement::enqueueSlotChangeEvent()
 {
     if (m_hasEnqueuedSlotChangeEvent)
index 8a4484e..32eab33 100644 (file)
@@ -38,6 +38,7 @@ public:
     static Ref<HTMLSlotElement> create(const QualifiedName&, Document&);
 
     const Vector<Node*>* assignedNodes() const;
+    const Vector<Node*> assignedNodesForBindings(const Dictionary& options) const;
 
     void enqueueSlotChangeEvent();
 
index 8fbd61c..e6375db 100644 (file)
@@ -31,6 +31,6 @@
 ] interface HTMLSlotElement : HTMLElement {
 
     [Reflect] attribute DOMString name;
-    [ImplementedAs=assignedNodes] sequence<Node> getAssignedNodes();
+    [ImplementedAs=assignedNodesForBindings] sequence<Node> assignedNodes(optional Dictionary options);
 
 };