HTMLSlotElement-interface.html (16485B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Shadow DOM: HTMLSlotElement interface</title> 5 <meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> 6 <meta name="assert" content="HTMLSlotElement must exist on window with name attribute and getAssignedNode() method"> 7 <link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#the-slot-element"> 8 <script src="/resources/testharness.js"></script> 9 <script src="/resources/testharnessreport.js"></script> 10 </head> 11 <body> 12 <div id="log"></div> 13 <script> 14 15 test(function () { 16 assert_true('HTMLSlotElement' in window, 'HTMLSlotElement must be defined on window'); 17 assert_equals(Object.getPrototypeOf(HTMLSlotElement.prototype), HTMLElement.prototype, 'HTMLSlotElement should inherit from HTMLElement'); 18 assert_true(document.createElement('slot') instanceof HTMLSlotElement, 'slot element should be an instance of HTMLSlotElement'); 19 assert_true(document.createElement('slot') instanceof HTMLElement, 'slot element should be an instance of HTMLElement'); 20 }, 'HTMLSlotElement must be defined on window'); 21 22 test(function () { 23 assert_true('name' in HTMLSlotElement.prototype, '"name" attribute must be defined on HTMLSlotElement.prototype'); 24 25 var slotElement = document.createElement('slot'); 26 assert_equals(slotElement.name, '', '"name" attribute must return the empty string when "name" content attribute is not set'); 27 28 slotElement.setAttribute('name', 'foo'); 29 assert_equals(slotElement.name, 'foo', '"name" attribute must return the value of the "name" content attribute'); 30 31 slotElement.name = 'bar'; 32 assert_equals(slotElement.name, 'bar', '"name" attribute must return the assigned value'); 33 assert_equals(slotElement.getAttribute('name'), 'bar', '"name" attribute must update the "name" content attribute'); 34 }, '"name" attribute on HTMLSlotElement must reflect "name" attribute'); 35 36 function testSlotOutsideShadowTree(options) 37 { 38 test(function () { 39 assert_true('assignedNodes' in HTMLSlotElement.prototype, '"assignedNodes" method must be defined on HTMLSlotElement.prototype'); 40 41 var slotElement = document.createElement('slot'); 42 assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when the slot element is not in any tree'); 43 44 document.body.appendChild(slotElement); 45 assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when the slot element is in a document tree'); 46 47 }, 'assignedNodes(' + (options ? JSON.stringify(options) : '') 48 + ') on a HTMLSlotElement must return an empty array when the slot element is not in a tree or in a document tree'); 49 } 50 51 testSlotOutsideShadowTree(null); 52 testSlotOutsideShadowTree({flattened: false}); 53 testSlotOutsideShadowTree({flattened: true}); 54 55 function testSingleLevelOfSlotting(options) 56 { 57 test(function () { 58 assert_true('assignedNodes' in HTMLSlotElement.prototype, '"assignedNodes" method must be defined on HTMLSlotElement.prototype'); 59 60 var shadowHost = document.createElement('div'); 61 var child = document.createElement('p'); 62 63 var shadowRoot = shadowHost.attachShadow({mode: 'open'}); 64 var slotElement = document.createElement('slot'); 65 shadowRoot.appendChild(slotElement); 66 67 assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when there are no nodes in the shadow tree'); 68 69 shadowHost.appendChild(child); 70 assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on a default slot must return an element without slot element'); 71 72 child.setAttribute('slot', 'foo'); 73 assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() on a default slot must not return an element with non-empty slot attribute'); 74 75 child.setAttribute('slot', ''); 76 assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on a default slot must return an element with empty slot attribute'); 77 78 slotElement.setAttribute('name', 'bar'); 79 assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() on a named slot must not return an element with empty slot attribute'); 80 81 slotElement.setAttribute('name', ''); 82 assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on an empty name slot must return an element with empty slot attribute'); 83 84 }, 'assignedNodes(' + (options ? JSON.stringify(options) : '') + ') must return the list of assigned nodes when none of the assigned nodes themselves are slots'); 85 } 86 87 testSingleLevelOfSlotting(null); 88 testSingleLevelOfSlotting({flattened: false}); 89 testSingleLevelOfSlotting({flattened: true}); 90 91 function testMutatingSlottedContents(options) 92 { 93 test(function () { 94 var shadowHost = document.createElement('div'); 95 var p = document.createElement('p'); 96 var b = document.createElement('b'); 97 shadowHost.appendChild(p); 98 shadowHost.appendChild(b); 99 100 var shadowRoot = shadowHost.attachShadow({mode: 'open'}); 101 var slotElement = document.createElement('slot'); 102 shadowRoot.appendChild(slotElement); 103 104 assert_array_equals(slotElement.assignedNodes(options), [p, b], 'assignedNodes must return the distributed nodes'); 105 106 slotElement.name = 'foo'; 107 assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty when there are no matching elements for the slot name'); 108 109 b.slot = 'foo'; 110 assert_array_equals(slotElement.assignedNodes(options), [b], 'assignedNodes must return the nodes with the matching slot name'); 111 112 p.slot = 'foo'; 113 assert_array_equals(slotElement.assignedNodes(options), [p, b], 'assignedNodes must return the nodes with the matching slot name in the tree order'); 114 115 slotElement.removeAttribute('name'); 116 assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty for a default slot when all elements have "slot" attributes specified'); 117 118 }, 'assignedNodes(' + (options ? JSON.stringify(options) : '') + ') must update when slot and name attributes are modified'); 119 } 120 121 testMutatingSlottedContents(null); 122 testMutatingSlottedContents({flattened: false}); 123 testMutatingSlottedContents({flattened: true}); 124 125 function testMutatingSlotName(options) 126 { 127 test(function () { 128 var shadowHost = document.createElement('div'); 129 var child = document.createElement('span'); 130 shadowHost.appendChild(child); 131 132 var shadowRoot = shadowHost.attachShadow({mode: 'open'}); 133 var slotElement = document.createElement('slot'); 134 slotElement.name = 'foo'; 135 shadowRoot.appendChild(slotElement); 136 137 assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty when there are no matching elements for the slot name'); 138 139 slotElement.removeAttribute('name'); 140 assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes must be empty when there are no matching elements for the slot name'); 141 142 }, 'assignedNodes(' + (options ? JSON.stringify(options) : '') + ') must update when a default slot is introduced dynamically by a slot rename'); 143 } 144 145 testMutatingSlotName(null); 146 testMutatingSlotName({flattened: false}); 147 testMutatingSlotName({flattened: true}); 148 149 function testInsertingAndRemovingSlots(options) 150 { 151 test(function () { 152 var shadowHost = document.createElement('div'); 153 var p = document.createElement('p'); 154 var text = document.createTextNode(''); 155 var comment = document.createComment(''); 156 var processingInstruction = document.createProcessingInstruction('target', 'data'); 157 var b = document.createElement('b'); 158 shadowHost.appendChild(p); 159 shadowHost.appendChild(text); 160 shadowHost.appendChild(comment); 161 shadowHost.appendChild(processingInstruction); 162 shadowHost.appendChild(b); 163 164 var shadowRoot = shadowHost.attachShadow({mode: 'open'}); 165 166 var firstSlotElement = document.createElement('slot'); 167 shadowRoot.appendChild(firstSlotElement); 168 169 var secondSlotElement = document.createElement('slot'); 170 shadowRoot.appendChild(secondSlotElement); 171 172 assert_array_equals(firstSlotElement.assignedNodes(options), [p, text, b], 173 'assignedNodes on a default slot must return the elements without slot attributes and text nodes'); 174 assert_array_equals(secondSlotElement.assignedNodes(options), [], 175 'assignedNodes on the second unnamed slot element must return an empty array'); 176 177 shadowRoot.removeChild(firstSlotElement); 178 assert_array_equals(firstSlotElement.assignedNodes(options), [], 179 'assignedNodes on a detached formerly-default slot must return an empty array'); 180 assert_array_equals(secondSlotElement.assignedNodes(options), [p, text, b], 181 'assignedNodes on the second unnamed slot element after removing the first must return the elements without slot attributes and text nodes'); 182 183 shadowRoot.removeChild(secondSlotElement); 184 shadowRoot.appendChild(secondSlotElement); 185 assert_array_equals(firstSlotElement.assignedNodes(options), [], 186 'Removing and re-inserting a default slot must not change the result of assignedNodes on a detached slot'); 187 assert_array_equals(secondSlotElement.assignedNodes(options), [p, text, b], 188 'Removing and re-inserting a default slot must not change the result of assignedNodes'); 189 190 shadowRoot.insertBefore(firstSlotElement, secondSlotElement); 191 assert_array_equals(firstSlotElement.assignedNodes(options), [p, text, b], 192 'assignedNodes on a newly inserted unnamed slot element must return the elements without slot attributes and text nodes'); 193 assert_array_equals(secondSlotElement.assignedNodes(options), [], 194 'assignedNodes on formerly-first but now second unnamed slot element must return an empty array'); 195 196 }, 'assignedNodes(' + (options ? JSON.stringify(options) : '') + ') must update when slot elements are inserted or removed'); 197 } 198 199 testInsertingAndRemovingSlots(null); 200 testInsertingAndRemovingSlots({flattened: false}); 201 testInsertingAndRemovingSlots({flattened: true}); 202 203 test(function () { 204 var outerHost = document.createElement('div'); 205 var outerChild = document.createElement('span'); 206 outerHost.appendChild(outerChild); 207 208 var outerShadow = outerHost.attachShadow({mode: 'closed'}); 209 var innerHost = document.createElement('div'); 210 var outerSlot = document.createElement('slot'); 211 var innerChild = document.createElement('b'); 212 outerShadow.appendChild(innerHost); 213 innerHost.appendChild(outerSlot); 214 innerHost.appendChild(innerChild); 215 216 var innerShadow = innerHost.attachShadow({mode: 'closed'}); 217 var innerSlot = document.createElement('slot'); 218 innerShadow.appendChild(innerSlot); 219 220 assert_array_equals(outerSlot.assignedNodes(), [outerChild], 'assignedNodes() on a default slot must return the assigned nodes'); 221 assert_array_equals(outerSlot.assignedNodes({flatten: false}), [outerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes'); 222 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'); 223 224 assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes'); 225 assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes'); 226 assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes'); 227 228 outerSlot.name = 'foo'; 229 assert_array_equals(outerSlot.assignedNodes(), [], 'assignedNodes() on a named slot must return an empty array if there are no matching elements'); 230 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'); 231 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'); 232 233 assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes'); 234 assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes'); 235 assert_array_equals(innerSlot.assignedNodes({flatten: true}), [innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes'); 236 237 outerChild.slot = 'foo'; 238 assert_array_equals(outerSlot.assignedNodes(), [outerChild], 'assignedNodes() on a named slot must return matching elements'); 239 assert_array_equals(outerSlot.assignedNodes({flatten: false}), [outerChild], 'assignedNodes({flatten: false}) on a named slot must return matching elements'); 240 assert_array_equals(outerSlot.assignedNodes({flatten: true}), [outerChild], 'assignedNodes({flatten: true}) on a named slot must return matching elements'); 241 242 assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes'); 243 assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes'); 244 assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes'); 245 246 var newInnerSlot = document.createElement('slot'); 247 innerShadow.insertBefore(newInnerSlot, innerSlot); 248 assert_array_equals(newInnerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes'); 249 assert_array_equals(newInnerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes'); 250 assert_array_equals(newInnerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes'); 251 252 assert_array_equals(innerSlot.assignedNodes(), [], 'assignedNodes() on a nameless slot element which appears after a default slot must return an empty array'); 253 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'); 254 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'); 255 256 innerShadow.removeChild(newInnerSlot); 257 assert_array_equals(newInnerSlot.assignedNodes(), [], 'assignedNodes() must return an empty array when the slot element is not in any tree'); 258 assert_array_equals(newInnerSlot.assignedNodes({flatten: false}), [], 'assignedNodes({flatten: false}) must return an empty array when the slot element is not in any tree'); 259 assert_array_equals(newInnerSlot.assignedNodes({flatten: true}), [], 'assignedNodes({flatten: true}) must return an empty array when the slot element is not in any tree'); 260 261 assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes'); 262 assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes'); 263 assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes'); 264 265 }, 'assignedNodes({flatten: true}) must return the distributed nodes, and assignedNodes() and assignedNodes({flatten: false}) must returned the assigned nodes'); 266 267 </script> 268 </body> 269 </html>