Element-innerHTML.html (6669B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"> 5 <link rel="help" href="https://github.com/whatwg/html/issues/10854"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 </head> 9 <div id="host"> 10 <template shadowrootmode="open" shadowrootclonable="true" shadowrootcustomelementregistry> 11 <new-element></new-element> 12 </template> 13 </div> 14 <body> 15 <script> 16 17 function createConnectedShadowTree(test, customElementRegistry) { 18 const host = document.createElement('div'); 19 const shadowRoot = host.attachShadow({mode: 'closed', customElementRegistry}); 20 document.body.appendChild(host); 21 test.add_cleanup(() => host.remove()); 22 return shadowRoot; 23 } 24 25 class GlobalSomeElement extends HTMLElement { }; 26 customElements.define('some-element', GlobalSomeElement); 27 28 class GlobalOtherElement extends HTMLElement { }; 29 customElements.define('other-element', GlobalOtherElement); 30 31 class WrongNewElement extends HTMLElement{ }; 32 customElements.define('new-element', WrongNewElement); 33 34 test((test) => { 35 const registry = new CustomElementRegistry; 36 37 class ScopedSomeElement extends HTMLElement { }; 38 registry.define('some-element', ScopedSomeElement); 39 40 class ScopedOtherElement extends HTMLElement { }; 41 registry.define('other-element', ScopedOtherElement); 42 43 const someElement = document.createElement('some-element', {customElementRegistry: registry}); 44 assert_true(someElement instanceof ScopedSomeElement); 45 someElement.innerHTML = '<other-element></other-element>'; 46 assert_true(someElement.querySelector('other-element') instanceof ScopedOtherElement); 47 }, 'innerHTML on a disconnected element should use the scoped registry it was created with'); 48 49 test((test) => { 50 const registry = new CustomElementRegistry; 51 52 class ScopedSomeElement extends HTMLElement { }; 53 registry.define('some-element', ScopedSomeElement); 54 55 class ScopedOtherElement extends HTMLElement { }; 56 registry.define('other-element', ScopedOtherElement); 57 58 const someElement = document.createElement('some-element', {customElementRegistry: registry}); 59 assert_true(someElement instanceof ScopedSomeElement); 60 someElement.innerHTML = ` 61 <other-element id="foo"> 62 <other-element id="bar"> 63 <div id="baz"> 64 <other-element id="nested-ce"></other-element> 65 </div> 66 </other-element> 67 </other-element> 68 <div id="bux"></div> 69 <another-element></another-element>`; 70 71 assert_true(someElement.querySelector('#foo') instanceof ScopedOtherElement); 72 assert_true(someElement.querySelector('#bar') instanceof ScopedOtherElement); 73 assert_true(someElement.querySelector('#nested-ce') instanceof ScopedOtherElement); 74 75 assert_true(someElement.querySelector('#foo').customElementRegistry === registry); 76 assert_true(someElement.querySelector('#bar').customElementRegistry === registry); 77 assert_true(someElement.querySelector('#baz').customElementRegistry === registry); 78 assert_true(someElement.querySelector('#nested-ce').customElementRegistry === registry); 79 assert_true(someElement.querySelector('#bux').customElementRegistry === registry); 80 assert_true(someElement.querySelector('another-element').customElementRegistry === registry); 81 }, 'nested descendants in innerHTML on a disconnected element should use the scoped registry the element was created with'); 82 83 test((test) => { 84 const registry = new CustomElementRegistry; 85 86 class ScopedSomeElement extends HTMLElement { }; 87 registry.define('some-element', ScopedSomeElement); 88 89 const div = document.createElement('div', {customElementRegistry: registry}); 90 div.innerHTML = '<span></span>'; 91 assert_equals(div.querySelector('span').customElementRegistry, registry); 92 }, 'innerHTML on a disconnected element should use the scoped registry it was created with when parsing a simple HTML'); 93 94 test((test) => { 95 const registry1 = new CustomElementRegistry; 96 const registry2 = new CustomElementRegistry; 97 98 class ScopedSomeElement extends HTMLElement { }; 99 registry1.define('some-element', ScopedSomeElement); 100 101 class ScopedOtherElement1 extends HTMLElement { }; 102 registry1.define('other-element', ScopedOtherElement1); 103 class ScopedOtherElement2 extends HTMLElement { }; 104 registry2.define('other-element', ScopedOtherElement2); 105 106 const shadowRoot1 = createConnectedShadowTree(test, registry1); 107 const shadowRoot2 = createConnectedShadowTree(test, registry2); 108 const someElement = document.createElement('some-element', {customElementRegistry: registry1}); 109 someElement.innerHTML = '<other-element></other-element>'; 110 assert_true(someElement.querySelector('other-element') instanceof ScopedOtherElement1); 111 shadowRoot2.appendChild(someElement); 112 someElement.innerHTML = '<other-element></other-element>'; 113 assert_true(someElement.querySelector('other-element') instanceof ScopedOtherElement1); 114 someElement.remove(); 115 someElement.innerHTML = '<other-element></other-element>'; 116 assert_true(someElement.querySelector('other-element') instanceof ScopedOtherElement1); 117 }, 'innerHTML on an inserted element should continue to use the scoped registry it was created with'); 118 119 test((test) => { 120 const shadowRoot = host.cloneNode(true).shadowRoot; 121 const container_element = shadowRoot.lastElementChild; 122 assert_equals(container_element.customElementRegistry, null); 123 assert_false(container_element instanceof WrongNewElement); 124 125 container_element.innerHTML = '<new-element><new-element></new-element></new-element>'; 126 const outer_element = container_element.querySelector('new-element'); 127 const inner_element = outer_element.querySelector('new-element'); 128 assert_equals(outer_element.customElementRegistry, null); 129 assert_false(outer_element instanceof WrongNewElement); 130 assert_equals(inner_element.customElementRegistry, null); 131 assert_false(inner_element instanceof WrongNewElement); 132 }, 'nested descendants in innerHTML should use the null registry when the container element has null registry'); 133 134 test((test) => { 135 const shadowRoot = host.cloneNode(true).shadowRoot; 136 shadowRoot.firstElementChild.insertAdjacentHTML('afterend', '<new-element></new-element>'); 137 const container_element = shadowRoot.lastElementChild; 138 assert_equals(container_element.customElementRegistry, null); 139 assert_false(container_element instanceof WrongNewElement); 140 }, 'insertAdjacentHTML should use the element\'s registry even when the registry is null'); 141 142 </script> 143 </body> 144 </html>