<!DOCTYPE html> <title>Shadow DOM: slotchange Events</title> <meta name="author" title="Hayato Ito" href="mailto:hayato@google.com"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="resources/shadow-dom.js"></script> <div id="test1"> <div id="host1"> <template data-mode="open"> <slot id="s1" name="slot1"></slot> </template> <div id="c1" slot="slot1"></div> </div> </div> <script> function arraysEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (var i = 0; i < a.length; ++i) { if (a[i] !== b[i]) return false; } return true; } function doneIfSlotChange(slots, expectedAssignedNodes, test) { let matched = Array(slots.length).fill(false); for (let i=0; i<slots.length; i++) { slots[i].addEventListener('slotchange', test.step_func((e) => { matched[i] = arraysEqual(slots[i].assignedNodes(), expectedAssignedNodes[i]); if (matched.every(v => v)) { test.done(); } })) } } async_test((test) => { let n = createTestTree(test1); removeWhiteSpaceOnlyTextNodes(n.test1); let d1 = document.createElement('div'); d1.setAttribute('slot', 'slot1'); doneIfSlotChange([n.s1], [[n.c1, d1]], test); n.host1.appendChild(d1); }, 'slotchange event: Append a child to a host.'); async_test((test) => { let n = createTestTree(test1); removeWhiteSpaceOnlyTextNodes(n.test1); doneIfSlotChange([n.s1], [[]], test); n.c1.remove(); }, 'slotchange event: Remove a child from a host.'); async_test((test) => { let n = createTestTree(test1); removeWhiteSpaceOnlyTextNodes(n.test1); n.c1.remove(); doneIfSlotChange([n.s1], [[]], test); }, 'slotchange event: Remove a child before adding an event listener.'); async_test((test) => { let n = createTestTree(test1); removeWhiteSpaceOnlyTextNodes(n.test1); doneIfSlotChange([n.s1], [[]], test); n.c1.setAttribute('slot', 'slot-none'); }, 'slotchange event: Change slot= attribute to make it un-assigned.'); async_test((test) => { let n = createTestTree(test1); removeWhiteSpaceOnlyTextNodes(n.test1); doneIfSlotChange([n.s1], [[]], test); n.s1.setAttribute('name', 'slot-none'); }, 'slotchange event: Change slot\'s name= attribute so that none is assigned.'); </script> <div id="test2"> <div id="host1"> <template data-mode="open"> <slot id="s1" name="slot1"></slot> </template> <div id="c2" slot="slot2"></div> </div> </div> <script> async_test((test) => { let n = createTestTree(test2); removeWhiteSpaceOnlyTextNodes(n.test2); doneIfSlotChange([n.s1], [[n.c2]], test); n.c2.setAttribute('slot', 'slot1'); }, 'slotchange event: Change slot= attribute to make it assigned.'); async_test((test) => { let n = createTestTree(test2); removeWhiteSpaceOnlyTextNodes(n.test2); doneIfSlotChange([n.s1], [[n.c2]], test); n.s1.setAttribute('name', 'slot2'); }, 'slotchange event: Change slot\'s name= attribute so that a node is assigned to the slot.'); </script> <div id="test_fallback"> <div id="host1"> <template data-mode="open"> <slot id="s1"></slot> </template> </div> </div> <script> async_test((test) => { let n = createTestTree(test_fallback); removeWhiteSpaceOnlyTextNodes(n.test_fallback); doneIfSlotChange([n.s1], [[]], test); n.s1.appendChild(document.createElement('div')); }, 'slotchange event: Change fallback content - assignedNodes still empty.'); </script> <div id="test_fallback2"> <div id="host1"> <template data-mode="open"> <slot id="s1"> <div id="f1"></div> </slot> </template> </div> </div> <script> async_test((test) => { let n = createTestTree(test_fallback2); removeWhiteSpaceOnlyTextNodes(n.test_fallback2); doneIfSlotChange([n.s1], [[]], test); n.f1.remove(); }, 'slotchange event: Remove a fallback content - assignedNodes still empty.'); </script> <div id="test_fallback3"> <div id="host1"> <template data-mode="open"> <slot id="s2"> <slot id="s1"> <div id="f1"></div> </slot> </slot> </template> </div> </div> <script> async_test((test) => { let n = createTestTree(test_fallback3); removeWhiteSpaceOnlyTextNodes(n.test_fallback3); doneIfSlotChange([n.s1, n.s2], [[],[]], test); n.s1.appendChild(document.createElement('div')); }, 'slotchange event: Add a fallback content to nested slots - assignedNodes still empty.'); async_test((test) => { let n = createTestTree(test_fallback3); removeWhiteSpaceOnlyTextNodes(n.test_fallback3); doneIfSlotChange([n.s1, n.s2], [[],[]], test); n.f1.remove(); }, 'slotchange event: Remove a fallback content from nested slots - assignedNodes still empty.'); </script> <div id="test3"> <div id="host1"> <template id="shadowroot" data-mode="open"> <slot id="s1" name="slot1"></slot> </template> <div id="c1" slot="slot1"></div> </div> </div> <script> async_test((test) => { let n = createTestTree(test3); removeWhiteSpaceOnlyTextNodes(n.test3); doneIfSlotChange([n.s1], [[]], test); let slot = document.createElement('slot'); slot.setAttribute('name', 'slot1'); n.shadowroot.insertBefore(slot, n.s1); }, "slotchange event: Insert a slot before an existing slot."); </script> <div id="test4"> <div id="host1"> <template id="shadowroot" data-mode="open"> <slot id="s1" name="slot1"></slot> <slot id="s2" name="slot1"></slot> </template> <div id="c1" slot="slot1"></div> </div> </div> <script> async_test((test) => { let n = createTestTree(test4); removeWhiteSpaceOnlyTextNodes(n.test4); doneIfSlotChange([n.s2], [[n.c1]], test); n.s1.remove(); }, "slotchange event: Remove a preceding slot."); </script> <div id="test5"> <div id="host1"> <template data-mode="open"> <div id="host2"> <template data-mode="open"> <slot id="s2" name="slot2"></slot> </template> <slot id="s1" name="slot1" slot="slot2"></slot> </div> </template> <div id="c1" slot="slot1"></div> </div> </div> <script> async_test((test) => { let n = createTestTree(test5); removeWhiteSpaceOnlyTextNodes(n.test5); doneIfSlotChange([n.s1, n.s2], [[],[n.s1]], test); n.c1.remove(); }, "slotchange event: A slot is assigned to another slot."); </script> <div id="test6"> <div id="host1"> <template data-mode="open"> <div id="host2"> <template data-mode="open"> <slot id="s2" name="slot2"></slot> </template> <slot id="s1" name="slot1" slot="slot2"></slot> </div> </template> </div> </div> <script> async_test((test) => { let n = createTestTree(test6); removeWhiteSpaceOnlyTextNodes(n.test6); doneIfSlotChange([n.s2], [[]], test); n.s1.remove(); }, "slotchange event: Slotchange should be fired if assigned nodes are changed."); </script> <div id="test7"> <div id="host1"> <template data-mode="open"> <div id="host2"> <template data-mode="open"> <slot id="s2" name="slot2"></slot> </template> <slot id="s1" name="slot1" slot="slot2"></slot> </div> </template> </div> </div> <script> async_test((test) => { let n = createTestTree(test7); removeWhiteSpaceOnlyTextNodes(n.test7); let d1 = document.createElement('div'); d1.setAttribute('slot', 'slot1'); doneIfSlotChange([n.s1, n.s2], [[d1],[n.s1]], test); n.host1.appendChild(d1); }, "slotchange event: Child content is added to nested slots."); </script>