1<!DOCTYPE html> 2<!-- 3@license 4Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 5This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt 6The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt 7The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt 8Code distributed by Google as part of the polymer project is also 9subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt 10--> 11<html> 12<head> 13 <meta charset="utf-8"> 14 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 15 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes"> 16 <script> 17 WCT = {waitFor: function (cb) {HTMLImports.whenReady(cb)}} 18 </script> 19 <script src="./test-flags.js"></script> 20 <script src="../node_modules/wct-browser-legacy/browser.js"></script> 21 <script src="../node_modules/@webcomponents/webcomponents-platform/webcomponents-platform.js"></script> 22 <script src="../node_modules/es6-promise/dist/es6-promise.auto.min.js"></script> 23 <script src="../node_modules/@webcomponents/template/template.js"></script> 24 <script src="../node_modules/@webcomponents/html-imports/html-imports.min.js"></script> 25 <script src="../node_modules/@webcomponents/shadydom/shadydom.min.js"></script> 26 <script src="../node_modules/@webcomponents/custom-elements/custom-elements.min.js"></script> 27 <script src="../scoping-shim.min.js"></script> 28 <script src="../apply-shim.min.js"></script> 29 <script src="../custom-style-interface.min.js"></script> 30 <script src="module/generated/make-element.js"></script> 31 <script src="module/generated/custom-style-element.js"></script> 32</head> 33<body> 34 35 <custom-style> 36 <style> 37 x-container, x-sample, x-sample-dynamic, x-container-dynamic { 38 display: block; 39 padding: 10px; 40 margin: 10px; 41 border: 1px solid black; 42 } 43 44 .target { 45 background-color: rgb(0, 255, 0); 46 } 47 </style> 48 </custom-style> 49 50 <template id="x-sample"> 51 <style> 52 .target { 53 background-color: rgb(255, 0, 0); 54 } 55 </style> 56 <h2></h2> 57 <p>here .target elements are red</p> 58 <div class="target">I'm red</div> 59 <template id="renderer"> 60 <div class="target"></div> 61 </template> 62 </template> 63 64 <template id="x-container"> 65 <style> 66 .target { 67 background-color: rgb(123, 123, 123); 68 } 69 </style> 70 <h1>x-container</h1> 71 <p>here .target elements are gray</p> 72 <div class="target">I'm gray</div> 73 <slot></slot> 74 </template> 75 76 <h2>body</h2> 77 <p>here .target elements are green</p> 78 79 <div class="target">I'm green</div> 80 81 <x-sample id="inBody"></x-sample> 82 83 <x-sample id="inContainer"></x-sample> 84 85 <x-container></x-container> 86 87 <template id="x-dynamic"> 88 <style> 89 span { 90 background-color: rgb(123, 123, 123); 91 } 92 </style> 93 <div id="container"> 94 </div> 95 </template> 96 97 <x-dynamic></x-dynamic> 98 99 <template id="out-of-band"> 100 <style> 101 div { 102 color: var(--foo); 103 } 104 </style> 105 <div>oob shadowed</div> 106 </template> 107 108 <template id="oob-parent"> 109 <style> 110 out-of-band { 111 --foo: rgb(0, 0, 255); 112 } 113 </style> 114 <out-of-band></out-of-band> 115 </template> 116 117 <template id="oob-other-parent"> 118 <style> 119 out-of-band { 120 --foo: rgb(255, 0, 0); 121 } 122 </style> 123 </template> 124 125 <oob-parent></oob-parent> 126 <oob-other-parent></oob-other-parent> 127 128 <template id="x-sample-dynamic"> 129 <style> 130 .target { 131 background-color: rgb(255, 0, 0); 132 } 133 </style> 134 <h2></h2> 135 <p>here .target elements are red</p> 136 <div class="target">I'm red</div> 137 <template id="renderer"> 138 <div class="target"></div> 139 </template> 140 </template> 141 142 <template id="x-container-dynamic"> 143 <style> 144 .target { 145 background-color: rgb(123, 123, 123); 146 } 147 </style> 148 <h1>x-container</h1> 149 <p>here .target elements are gray</p> 150 <div class="target">I'm gray</div> 151 <slot></slot> 152 </template> 153 154 <x-container-dynamic></x-container-dynamic> 155 156 <template id="css-build" css-build="shady"> 157 <style>:host{@apply --fake;}</style> 158 <div class="style-scope css-build"></div> 159 </template> 160 161 <template id="css-build-comment"><!--css-build:shady--> 162 <style>:host{@apply --fake;}</style> 163 <div class="style-scope css-build-comment"></div> 164 </template> 165 166 <script> 167 suite('Dynamic Scoping', () => { 168 function stamp(parent, host) { 169 let template = host.shadowRoot.querySelector('template#renderer') 170 let el = template.content.cloneNode(true).querySelector('div.target'); 171 el.textContent = `stamped by ${host.id}`; 172 parent.appendChild(el); 173 return el; 174 } 175 test('DOM is scoped correctly when stamped from an element into document', (done) => { 176 let inBody = document.querySelector('x-sample#inBody'); 177 let inContainer = document.querySelector('x-sample#inContainer'); 178 makeElement('x-sample', function() { 179 this.shadowRoot.querySelector('h2').textContent = `${this.id}`; 180 }); 181 makeElement('x-container'); 182 setTimeout(() => { 183 let body = stamp(document.body, inBody); 184 let container = stamp(document.querySelector('x-container').shadowRoot, inContainer); 185 requestAnimationFrame(() => { 186 assert.equal(getComputedStyle(body).backgroundColor, 'rgb(0, 255, 0)'); 187 assert.equal(getComputedStyle(container).backgroundColor, 'rgb(123, 123, 123)') 188 done(); 189 }); 190 }, 300); 191 }); 192 test('DOM is scoped correctly when created dynamically inside a scoped container', (done) => { 193 makeElement('x-dynamic', function() { 194 let div = this.shadowRoot.querySelector('#container'); 195 let newDiv = div.cloneNode(true); 196 let span = document.createElement('span'); 197 span.textContent = 'created dynamically'; 198 newDiv.appendChild(span); 199 this.shadowRoot.appendChild(newDiv); 200 requestAnimationFrame(() => { 201 assert.equal(getComputedStyle(span).backgroundColor, 'rgb(123, 123, 123)'); 202 done(); 203 }) 204 }); 205 }); 206 test('moving a custom element between scopes recalculates correctly', function(done) { 207 makeElement('out-of-band'); 208 makeElement('oob-parent'); 209 makeElement('oob-other-parent'); 210 let parent = document.querySelector('oob-parent'); 211 let newParent = document.querySelector('oob-other-parent'); 212 let oob = parent.shadowRoot.querySelector('out-of-band'); 213 let shadowDiv = oob.shadowRoot.querySelector('div'); 214 newParent.shadowRoot.appendChild(oob); 215 requestAnimationFrame(() => { 216 assert.equal(getComputedStyle(shadowDiv).getPropertyValue('color').trim(), 'rgb(255, 0, 0)'); 217 done(); 218 }); 219 }) 220 function makeDynamicElement(name, connectedCallback) { 221 let template = document.querySelector(`template#${name}`); 222 if (template && window.ShadyCSS) { 223 window.ShadyCSS.prepareTemplate(template, name); 224 } 225 window.customElements.define(name, class extends window.HTMLElement { 226 constructor() { 227 super(); 228 if (template && !this.shadowRoot) { 229 this.attachShadow({mode: 'open'}); 230 this.shadowRoot.appendChild(document.importNode(template.content, true)); 231 } 232 } 233 connectedCallback() { 234 window.ShadyCSS && window.ShadyCSS.styleElement(this); 235 if (connectedCallback) { 236 connectedCallback.call(this); 237 } 238 } 239 }); 240 } 241 test('Nested DOM is scoped correctly when created dynamically inside a dynamic container', function(done) { 242 if (!window.customElements.polyfillWrapFlushCallback && window.ShadyDOM && window.ShadyDOM.inUse) { 243 /* 244 * This test is flaky if running with native custom elements and polyfill shadowdom, 245 * as the shadowdom polyfill may render inside of the constructor and create children, 246 * which is not allowed in the CE spec. 247 */ 248 this.skip(); 249 } 250 makeDynamicElement('x-container-dynamic'); 251 makeDynamicElement('x-sample-dynamic'); 252 const dynamicDiv = document.createElement('div'); 253 dynamicDiv.classList.add('target'); 254 dynamicDiv.innerText = 'I was created dynamically'; 255 const dynamicSample = document.createElement('x-sample-dynamic'); 256 const dynamicContainer = document.createElement('x-container-dynamic'); 257 dynamicSample.shadowRoot.appendChild(dynamicDiv); 258 dynamicContainer.shadowRoot.appendChild(dynamicSample); 259 document.querySelector('x-container-dynamic').shadowRoot.appendChild(dynamicContainer); 260 requestAnimationFrame(() => { 261 dynamicSample.shadowRoot.querySelectorAll('div.target').forEach((target) => 262 assert.equal(getComputedStyle(target).backgroundColor,'rgb(255, 0, 0)')); 263 done(); 264 }); 265 }); 266 267 test('templates marked with "css-build" will be left alone', function() { 268 makeElement('css-build'); 269 const template = document.querySelector('template#css-build'); 270 const div = template.content.querySelector('div'); 271 const divClasses = Array.from(div.classList); 272 assert.includeMembers(divClasses, ['style-scope', 'css-build']); 273 const style = template.content.querySelector('style'); 274 if (style) { 275 assert.match(style.textContent.trim(), /:host\s*{\s*@apply --fake;\s*}/); 276 } 277 }); 278 279 test('templates with css-build comments will be left alone', function() { 280 const template = document.querySelector('template#css-build-comment'); 281 const buildComment = template.content.firstChild; 282 assert.instanceOf(buildComment, Comment, 'first child of template content should be a Comment'); 283 makeElement('css-build-comment'); 284 const div = template.content.querySelector('div'); 285 const divClasses = Array.from(div.classList); 286 assert.includeMembers(divClasses, ['style-scope', 'css-build-comment']); 287 const style = template.content.querySelector('style'); 288 if (style) { 289 assert.match(style.textContent.trim(), /:host\s*{\s*@apply --fake;\s*}/); 290 } 291 assert.equal(buildComment.parentNode, null, 'build commment should have been removed'); 292 }); 293 }); 294 </script> 295</body> 296</html> 297