UNPKG

@polymer/polymer

Version:

The Polymer library makes it easy to create your own web components. Give your element some markup and properties, and then use it on a site. Polymer provides features like dynamic templates and data binding to reduce the amount of boilerplate you need to

1,234 lines (1,098 loc) 34.4 kB
<!doctype html> <!-- @license Copyright (c) 2017 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt --> <html> <head> <meta charset="utf-8"> <script src="../../../webcomponentsjs/webcomponents-lite.js"></script> <script> (function() { let define = window.customElements.define; let order = []; window.customElements.define = function(name, fn, options) { order.push(name); return define.call(window.customElements, name, fn, options); }; customElements.defineOrder = order; })(); </script> <script src="../../../web-component-tester/browser.js"></script> <link rel="import" href="../../polymer.html"> <style> #priority[style-scope=x-styled], #priority.style-scope.x-styled { border: 1px solid black; } </style> </head> <body> <dom-module id="x-keyframes"> <template> <style> :host { display: block; position: relative; border: 10px solid blue; left: 0px; /* Prefix required by Safari <= 8 */ -webkit-animation-duration: 0.3s; animation-duration: 0.3s; -webkit-animation-fill-mode: forwards; animation-fill-mode: forwards; } :host([animated]) { /* Prefix required by Safari <= 8 */ -webkit-animation-name: x-keyframes-animation; animation-name: x-keyframes-animation; } /* Prefix required by Safari <= 8 */ @-webkit-keyframes x-keyframes-animation { 0% { left: var(--keyframes0, 0px); } 100% { left: var(--keyframes100, 10px); } } @keyframes x-keyframes-animation { 0% { left: var(--keyframes0, 0px); } 100% { left: var(--keyframes100, 10px); } } </style> x-keyframes </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-keyframes', properties: { animated: { type: Boolean, value: false, reflectToAttribute: true } } }); }); </script> </dom-module> <dom-module id="x-gchild"> <template> <style> </style> <div id="target">x-gchild</div> </template> </dom-module> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-gchild' }); }); </script> <dom-module id="x-child"> <template> <div id="simple">simple</div> <div id="complex1" class="scoped">complex1</div> <div id="complex2" selected>complex2</div> <div id="media">media</div> <div id="shadow" class="shadowTarget">shadowTarget</div> <div id="deep" class="deepTarget">deepTarget</div> <x-gchild id="gchild1"></x-gchild> <x-gchild id="gchild2" class="wide"></x-gchild> </template> </dom-module> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-child', hostAttributes: { class: 'nug' } }); }); </script> <dom-module id="x-child2"> <template> <style> :host(.wide) #target{ border: none; } </style> <div id="target">x-child2</div> </template> </dom-module> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-child2' }); }); </script> <dom-module id="x-scope-class"> <template> <div id="scope">Trivial</div> </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-scope-class' }); }); </script> </dom-module> <dom-module id="x-class-literal"> <template> <div id="scope" class$="a [[b]] c" class="d e">Trivial</div> </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-class-literal' }); }); </script> </dom-module> <dom-module id="x-styled"> <template> <style> :host { display: block; border: 1px solid orange; --keyframes100: 100px; } :host(.wide) { border-width: 2px; } :host(.wide)::after { content: '-content-'; }; #keyframes2.special { --keyframes100: 200px; } #simple { border: 3px solid orange; } .scoped, [selected] { border: 4px solid pink; } @media(max-width: 10000px) { .media { border: 5px solid brown; } } .container ::slotted(*) { border: 6px solid navy; } #priority { border: 9px solid orange; } .container1 > ::slotted([slot=content1]) { border: 13px solid navy; } .container2 > ::slotted([slot=content2]) { border: 14px solid navy; } .computed { border: 15px solid orange; } .computeda { border: 20px solid orange; } .a.computedb { border: 16px solid gray; } #child { border: 16px solid tomato; display: block; } svg { margin-top: 20px; } #circle { fill: seagreen; stroke-width: 1px; stroke: tomato; } </style> <slot name="blank"></slot> <div id="simple">simple</div> <div id="complex1" class="scoped">complex1</div> <div id="complex2" selected>complex2</div> <div id="media" class="media">media</div> <div class="container1"> <slot name="content1"></slot> </div> <div class="container2"> <slot name="content2"></slot> </div> <div class="container"> <slot></slot> </div> <x-child id="child"></x-child> <div id="priority">priority</div> <x-child2 class="wide" id="child2"></x-child2> <div id="computed" class$="{{computeClass(aClass)}}">Computed</div> <div> <div id="computed2" class$="a {{computeClass('computedb')}}">Computed</div> </div> <div id="repeatContainer"> <template id="repeat" is="dom-repeat" items="{{items}}"> <a class$="{{aaClass}}">A Computed</a> </template> </div> <svg height="25" width="25"> <circle id="circle" cx="12" cy="12" r="10"></circle> </svg> <x-scope-class id="scopeClass"></x-scope-class> <x-keyframes id="keyframes"></x-keyframes> <x-keyframes id="keyframes2"></x-keyframes> </template> </dom-module> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-styled', properties: { items: {value: [{}]} }, computeClass: function(className) { return className; } }); }); </script> <template id="dynamic"> <div class="added"> Added <div class="sub-added"> Sub-added </div> </div> </template> <dom-module id="x-dynamic-scope"> <template> <style> .added { border: 17px solid beige; } .sub-added { border: 18px solid #fafafa; } </style> <div id="container"></div> </template> </dom-module> <script> (function() { var doc = document.currentScript.ownerDocument; var dynamic = doc.querySelector('template#dynamic'); HTMLImports.whenReady(function() { Polymer({ is: 'x-dynamic-scope', ready: function() { // simulate 3rd party action by using normal dom to add to element. var dom = document.importNode(dynamic.content, true); this.$.container.appendChild(dom); } }); }); })(); </script> <template id="dynamic-style-template"> <style> :host { border: 40px solid tomato; } </style> <div>big border</div> </template> <script> (function() { var doc = document.currentScript.ownerDocument; var template = doc.querySelector('template#dynamic-style-template'); HTMLImports.whenReady(function() { Polymer({ is: 'x-dynamic-template', registered: function() { this._template = template; } }); }); })(); </script> <template id="svg"> <svg class="svg" viewBox="0 0 24 24"> <circle id="circle" r="12" cx="12" cy="12" /> </svg> </template> <dom-module id="x-dynamic-svg"> <template> <style> .svg { height: 24px; width: 24px; } #circle { fill: red; fill-opacity: 0.5; } </style> <div id="container"></div> </template> <script> (function() { var doc = document.currentScript.ownerDocument; var template = doc.querySelector('template#svg'); HTMLImports.whenReady(function() { Polymer({ is: 'x-dynamic-svg', ready: function() { this.scopeSubtree(this.$.container, true); var dom = document.importNode(template.content, true); this.$.container.appendChild(dom); } }); }); })(); </script> </dom-module> <dom-module id="x-specificity"> <template> <style> :host { border-top: 1px solid red; } :host(.bar) { border-top: 2px solid red; } </style> <slot></slot> </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-specificity'}); }); </script> </dom-module> <custom-style> <style> html { --x-specificity-parent : { border: 10px solid blue; }; --x-specificity-nested : { border: 3px solid red; }; } </style> </custom-style> <dom-module id="x-specificity-parent"> <template> <style> ::slotted(:not(template)) { @apply(--x-specificity-parent); } </style> <slot></slot> </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-specificity-parent'}); }); </script> </dom-module> <dom-module id="x-specificity-nested"> <template> <style> :host { @apply(--x-specificity-nested); } </style> </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-specificity-nested'}); }); </script> </dom-module> <custom-style> <style> html { --x-overriding : { border-top: 1px solid red; } } </style> </custom-style> <dom-module id="x-overriding"> <template> <style> .red { @apply(--x-overriding); } .green { @apply(--x-overriding); border-top: 2px solid green; } .red-2 { border-top: 2px solid green; @apply(--x-overriding); } .blue { @apply(--x-overriding); border-top: 3px solid blue; } </style> <div class="red">red</div> <div class="green">green</div> <div class="red-2">green-2</div> <div class="blue">blue</div> </template> </dom-module> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-overriding' }); }); </script> <dom-module id="x-attr-selector"> <template> <style> #foo1 ~ #bar1 { border: 2px solid red; } #foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2] { border: 4px solid red; } #foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2] ~ #foo3[attr~=foo3][a~=a] ~ #bar3[attr~=bar3][a~=a] { border: 6px solid red; } </style> <div id="foo1"></div> <div id="bar1">bar1</div> <div id="foo2" attr="foo2"></div> <div id="bar2" attr="bar2">bar2</div> <div id="foo3" attr="foo3" a="a"></div> <div id="bar3" attr="bar3" a="a">bar3</div> </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-attr-selector'}); }); </script> </dom-module> <dom-module id="shared-style"> <template> <style> :host(x-shared1) { display: block; border: 2px solid orange; } :host(x-shared2) { display: block; border: 4px solid orange; } :host(.x-shared1) { top: 10px; }; </style> </template> </dom-module> <dom-module id="x-shared1"> <template> <style include="shared-style"></style> x-shared1 </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-shared1'}); }); </script> </dom-module> <dom-module id="x-shared2"> <template> <style include="shared-style"></style> x-shared2 </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-shared2'}); }); </script> </dom-module> <dom-module id="x-slotted"> <template> <style> ::slotted(.auto-content) { border: 2px solid orange; } .bar, ::slotted(.complex-child) { border: 6px solid navy; } #container ::slotted(*) { border: 8px solid green; } </style> <slot></slot> <div id="container"> <slot name="container"></slot> </div> </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-slotted'}); }); </script> </dom-module> <template id="xClass"> <style> :host { display: block; border: 1px solid orange; } </style> </template> <script> HTMLImports.whenReady(function() { customElements.define('x-class-no-is', class extends Polymer.Element { static get template() { return window.xClass; } }); customElements.define('x-template-string', class extends Polymer.Element { static get template() { return `<style> :host { display: block; border: 1px solid orange; } </style>;`; } }); }); </script> <div class="scoped">no margin</div> <x-styled> <div slot="content1">Foo</div> <div slot="content2">Bar</div> <div class="content">Content</div> </x-styled> <x-styled class="wide"></x-styled> <x-dynamic-scope></x-dynamic-scope> <dom-bind id="bind"> <template> <div id="dom-bind-static" class="static">static</div> <span id="dom-bind-dynamic" class$="[[dynamic]]">[[dynamic]]</span> </template> </dom-bind> <x-dynamic-svg></x-dynamic-svg> <x-specificity></x-specificity> <x-specificity class="bar"></x-specificity> <x-specificity-parent> <x-specificity-nested></x-specificity-nested> </x-specificity-parent> <x-overriding></x-overriding> <dom-module id="nested-shared-style"> <template> <style> :host { padding-top: 10px; } </style> </template> </dom-module> <dom-module id="x-nested-style"> <template> <div id="container"> <style include="nested-shared-style"> :host { display: block; border: 10px solid black; } </style> </div> </template> <script> addEventListener('WebComponentsReady', () => { class XNestedStyle extends Polymer.Element { static get is() {return 'x-nested-style';} } customElements.define(XNestedStyle.is, XNestedStyle); }); </script> </dom-module> <dom-module id="x-interleaved-styles"> <template> <style include="x-nested-style"></style> <style> :host { padding-top: 5px; } </style> <style> :host { color: blue; } </style> </template> <script> addEventListener('WebComponentsReady', () => { class XInterleaved extends Polymer.Element { static get is() {return 'x-interleaved-styles';} } customElements.define(XInterleaved.is, XInterleaved); }); </script> </dom-module> <dom-module id="x-only-link-style"> <link rel="import" type="css" href="styling-import-host.css"> <link rel="import" type="css" href="styling-import-host2.css"> <template></template> <script> addEventListener('WebComponentsReady', () => { class XOnlyLink extends Polymer.Element { static get is() { return 'x-only-link-style'; } } customElements.define(XOnlyLink.is, XOnlyLink); }); </script> </dom-module> <dom-module id="double-shared-style"> <template> <style> .double-shared-style { color: green; } </style> </template> </dom-module> <dom-module id="importing-double-shared-style"> <template> <style include="double-shared-style"> </style> </template> </dom-module> <dom-module id="double-shared-styling-element"> <template> <style include="importing-double-shared-style double-shared-style"></style> </template> <script> HTMLImports.whenReady(() => { class DoubleSharedStylingElement extends Polymer.Element { static get is() { return 'double-shared-styling-element'; } } customElements.define(DoubleSharedStylingElement.is, DoubleSharedStylingElement); }); </script> </dom-module> <script> (function() { function assertComputed(element, value, property, pseudo) { var computed = getComputedStyle(element, pseudo); property = property || 'border-top-width'; if (Array.isArray(value)) { assert.oneOf(computed[property], value, 'computed style incorrect for ' + property); } else { assert.equal(computed[property], value, 'computed style incorrect for ' + property); } } var styled = document.querySelector('x-styled'); var styledWide = document.querySelector('x-styled.wide'); var unscoped = document.querySelector('.scoped'); suite('scoped-styling', function() { test(':host, :host(...)', function() { assertComputed(styled, '1px'); assertComputed(styledWide, '2px'); assertComputed(styled, ['', 'none'], 'content', '::after'); assertComputed(styledWide, ['"-content-"', '-content-'], 'content', '::after'); }); test('scoped selectors, simple and complex', function() { assertComputed(styled.$.simple, '3px'); assertComputed(styled.$.complex1, '4px'); assertComputed(styled.$.complex2, '4px'); }); test('media query scoped selectors', function() { assertComputed(styled.$.media, '5px'); }); test('upper bound encapsulation', function() { assertComputed(unscoped, '0px'); }); test('lower bound encapsulation', function() { assertComputed(styled.$.child.$.simple, '0px'); assertComputed(styled.$.child.$.complex1, '0px'); assertComputed(styled.$.child.$.complex2, '0px'); assertComputed(styled.$.child.$.media, '0px'); }); test('::slotted selectors', function() { var content = document.querySelector('.content'); var content1 = document.querySelector('[slot=content1]'); var content2 = document.querySelector('[slot=content2]'); assertComputed(content, '6px'); assertComputed(content1, '13px'); assertComputed(content2, '14px'); }); test('auto ::slotted selector', function() { var x = document.createElement('x-slotted'); var d1 = document.createElement('div'); d1.classList.add('auto-content'); d1.textContent = 'auto-content'; document.body.appendChild(x); Polymer.dom(x).appendChild(d1); Polymer.flush(); assertComputed(d1, '2px'); }); test('::slotted + child in complex selector', function() { var x = document.createElement('x-slotted'); var d1 = document.createElement('div'); d1.classList.add('complex-child'); d1.textContent = 'complex-child'; document.body.appendChild(x); Polymer.dom(x).appendChild(d1); Polymer.flush(); assertComputed(d1, '6px'); }); test('::slotted + named slot', function() { var x = document.createElement('x-slotted'); var d1 = document.createElement('div'); d1.setAttribute('slot', 'container'); d1.textContent = 'named slot child'; document.body.appendChild(x); Polymer.dom(x).appendChild(d1); Polymer.flush(); assertComputed(d1, '8px'); }); test('elements dynamically added/removed from root', function() { var d = document.createElement('div'); d.classList.add('scoped'); d.textContent = 'Dynamically... Scoped!'; Polymer.dom(styled.root).appendChild(d); Polymer.flush(); assertComputed(d, '4px'); Polymer.dom(document.body).appendChild(d); Polymer.flush(); assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when added to other root'); assert.notInclude(d.className, styled.is, 'scoping class not removed when added to other root'); assertComputed(d, '0px'); Polymer.dom(styled.root).appendChild(d); Polymer.flush(); assertComputed(d, '4px'); }); test('elements dynamically added/removed from host', function() { var d = document.createElement('div'); d.classList.add('scoped'); d.slot = 'blank'; d.textContent = 'Dynamically... unScoped!'; Polymer.dom(styled).appendChild(d); Polymer.flush(); assertComputed(d, '0px'); Polymer.dom(document.body).appendChild(d); Polymer.flush(); assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when added to other root'); assert.notInclude(d.className, styled.is, 'scoping class not removed when added to other root'); Polymer.dom(styled).appendChild(d); Polymer.flush(); assertComputed(d, '0px'); Polymer.dom(styled).removeChild(d); Polymer.flush(); assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when removed from root'); assert.notInclude(d.className, styled.is, 'scoping class not removed when removed from root'); Polymer.dom(styled).appendChild(d); Polymer.flush(); assertComputed(d, '0px'); }); test('keyframes change scope', function(done) { if (navigator.userAgent.match('Edge') && (!window.ShadyCSS || window.ShadyCSS.nativeCss)) { // skip test due to missing variable support in keyframes // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12084341/ this.skip(); } var xKeyframes = styled.$.keyframes; var onAnimationEnd = function() { xKeyframes.removeEventListener('animationend', onAnimationEnd); xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd); assertComputed(xKeyframes, '100px', 'left'); xKeyframes = styled.$.keyframes2; onAnimationEnd = function() { xKeyframes.removeEventListener('animationend', onAnimationEnd); xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd); assertComputed(xKeyframes, '200px', 'left'); done(); }; xKeyframes.addEventListener('animationend', onAnimationEnd); xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd); Polymer.dom(xKeyframes).classList.add('special'); xKeyframes.updateStyles(); xKeyframes.animated = true; }; xKeyframes.addEventListener('animationend', onAnimationEnd); xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd); xKeyframes.animated = true; assertComputed(xKeyframes, '0px', 'left'); }); test('elements with computed classes', function() { assertComputed(styled.$.computed, '0px'); styled.aClass = 'computed'; assertComputed(styled.$.computed, '15px'); assertComputed(styled.$.computed2, '16px'); }); test('<a> with computed classes dynamically added', function() { assertComputed(styled.$.repeatContainer.firstElementChild, '0px'); styled.aaClass = 'computeda'; assertComputed(styled.$.repeatContainer.firstElementChild, '20px'); }); test('elements with hostAttributes: class', function() { assertComputed(styled.$.child, '16px'); }); test('element subtree added via dom api', function() { var container = document.querySelector('x-dynamic-scope').$.container; var a = container.querySelector('.added'); assertComputed(a, '17px'); var b = container.querySelector('.sub-added'); assertComputed(b, '18px'); }); test('styles in dynamically selected template', function() { var el = document.createElement('x-dynamic-template'); document.body.appendChild(el); if (el.shadowRoot) { // style properly removed assert.notOk(el.querySelector('style')); } assertComputed(el, '40px'); document.body.removeChild(el); }); test('attribute inclusive selector and general sibling selectors', function() { var e = document.createElement('x-attr-selector'); document.body.appendChild(e); Polymer.flush(); assertComputed(e.$.bar1, '2px'); assertComputed(e.$.bar2, '4px'); assertComputed(e.$.bar3, '6px'); }); test('svg classes are dynamically scoped correctly', function() { var container = document.querySelector('x-dynamic-svg').$.container; var svg = container.querySelector('.svg'); var computed = getComputedStyle(svg); assert.equal(computed.height, '24px'); assert.equal(computed.width, '24px'); var circle = container.querySelector('#circle'); computed = getComputedStyle(circle); assert.equal(computed['fill-opacity'], '0.5'); }); test(':host with element tag selector', function() { var s1 = document.createElement('x-shared1'); document.body.appendChild(s1); assertComputed(s1, '2px'); var s2 = document.createElement('x-shared2'); document.body.appendChild(s2); assertComputed(s2, '4px'); }); test(':host with superset of element tag selector does not leak', function() { var t = document.createElement('div'); t.textContent = 'host leak test'; t.classList.add('x-shared1'); document.body.appendChild(t); assertComputed(t, 'auto', 'top'); }); test(':host(...) with non-matching type selector does not leak', function() { var t = document.createElement('x-shared1x-shared2'); t.textContent = ':host(non-matching-type-selector)'; document.body.appendChild(t); assertComputed(t, '0px'); t = document.createElement('x-shared2x-shared1'); t.textContent = ':host(non-matching-type-selector)'; document.body.appendChild(t); assertComputed(t, '0px'); }); test('static is not required for scoping styling', function() { var e = document.createElement('x-class-no-is'); document.body.appendChild(e); assertComputed(e, '1px'); }); test('template string has scoped styling', function() { var e = document.createElement('x-template-string'); document.body.appendChild(e); assertComputed(e, '1px'); }); test('styles work correctly when not direct children of the template', function() { var e = document.createElement('x-nested-style'); document.body.appendChild(e); assertComputed(e, '10px'); assertComputed(e, '10px', 'padding-top'); }); test('interleaved styles and styles with includes work as expected', function() { var e = document.createElement('x-interleaved-styles'); document.body.appendChild(e); assertComputed(e, '5px', 'padding-top'); }); test('elements without styles work', function() { var e = document.createElement('x-only-link-style'); document.body.appendChild(e); assertComputed(e, '2px'); }); test('initial literal values in class are preserved when a class$ binding is present', function() { var e = document.createElement('x-class-literal'); document.body.appendChild(e); var el = e.$.scope; assert.isTrue(el.classList.contains('a')); assert.isTrue(el.classList.contains('c')); assert.isTrue(el.classList.contains('d')); assert.isTrue(el.classList.contains('e')); }); }); suite('double including style sheets', function() { let el; setup(function() { el = document.createElement('double-shared-styling-element'); document.body.appendChild(el); }); teardown(function() { document.body.removeChild(el); }); test('only includes style modules once', function() { const style = el.shadowRoot.querySelector('style'); // We cant use the regular "does a sub-node have the correct style", // because we actually need to assert on the actual style content. // In native shadow dom, the style element resides in the shadowRoot, // but in shadyDOM it has moved to the head and the selector has been altered. if (style) { assert.equal(style.textContent, `.double-shared-style { color: green; }`, 'There should be only one class selector in this style element'); } else { assert.equal(document.head.querySelector('[scope="double-shared-styling-element"]').textContent, `.double-shared-style.double-shared-styling-element { color: green; }`); } }); }); if (window.ShadyDOM) { suite('scoped-styling-shady-only', function() { test('element style precedence below document styles', function() { assertComputed(styledWide.$.priority, '1px'); }); test('styles shimmed in registration order', function() { var regList = customElements.defineOrder; function regIndex(styleScope) { for (var i=0, r; (r=regList[i]); i++) { if (styleScope.match(new RegExp(r + '\\-?\\d*$'))) { return i; } } } var s$ = document.head.querySelectorAll('style[scope]'); for (var i=0, scope, prevScope, n=0, o=0; i<s$.length; i++) { scope = s$[i].getAttribute('scope'); n = regIndex(scope); assert.isTrue(n >= o, 'style not in registration order, expected `' + scope + '` to be before `' + prevScope + '`'); o = n; prevScope = scope; } }); test('svg elements properly scoped', function() { assert.include(styled.$.circle.getAttribute('class'), 'x-styled'); assert.include(styled.$.circle.getAttribute('class'), 'style-scope'); assert.notInclude(styled.$.circle.getAttribute('class'), 'null'); assertComputed(styled.$.circle, '1px', 'strokeWidth'); }); test('dom-bind content is unscoped', function() { var e = document.querySelector('#bind'); e.dynamic = 'dynamic'; var staticClassEl = document.querySelector('#dom-bind-static'); assert.equal(staticClassEl.className, 'static'); var dynamicClassEl = document.querySelector('#dom-bind-dynamic'); assert.equal(dynamicClassEl.className, 'dynamic'); }); test('serializeValueToAttribute for class', function() { var s = styled.$.scopeClass; var scope = s.$.scope; assert.isTrue(s.classList.contains('style-scope')); assert.isTrue(s.classList.contains('x-styled')); s.serializeValueToAttribute('foo', 'class'); assert.isTrue(s.classList.contains('foo')); assert.isTrue(s.classList.contains('style-scope')); assert.isTrue(s.classList.contains('x-styled')); // assert.isTrue(scope.classList.contains('style-scope')); assert.isTrue(scope.classList.contains('x-scope-class')); s.serializeValueToAttribute('foo', 'class', scope); assert.isTrue(scope.classList.contains('foo')); assert.isTrue(scope.classList.contains('style-scope')); assert.isTrue(scope.classList.contains('x-scope-class')); }); test('specificity of :host selector with class', function() { assertComputed(document.querySelector('x-specificity'), '1px'); assertComputed(document.querySelector('x-specificity.bar'), '2px'); }); test('specificity of ::slotted :not(template) selector', function() { assertComputed(document.querySelector('x-specificity-nested'), '10px'); }); test('overwriting mixin properties', function() { var el = document.querySelector('x-overriding'); assertComputed(el.shadowRoot.querySelector('.red'), '1px'); assertComputed(el.shadowRoot.querySelector('.green'), '2px'); assertComputed(el.shadowRoot.querySelector('.red-2'), '1px'); assertComputed(el.shadowRoot.querySelector('.blue'), '3px'); }); test('dynamically scope element class on add/remove', function () { var el = document.createElement('x-scope-class'); document.body.appendChild(el); Polymer.flush(); var div = document.createElement('div'); el.shadowRoot.appendChild(div); Polymer.flush(); assert.isTrue(div.classList.contains('style-scope')); assert.isTrue(div.classList.contains('x-scope-class')); el.shadowRoot.appendChild(div); Polymer.flush(); document.body.removeChild(el); }); test('dynamically scope element class on setAttribute class', function () { var el = document.createElement('x-scope-class'); document.body.appendChild(el); Polymer.flush(); var div = document.createElement('div'); el.shadowRoot.appendChild(div); Polymer.flush(); div.setAttribute('class', 'foo'); assert.isTrue(div.classList.contains('foo')); assert.isTrue(div.classList.contains('style-scope')); assert.isTrue(div.classList.contains('x-scope-class')); el.shadowRoot.appendChild(div); Polymer.flush(); document.body.removeChild(el); }); test('dynamically scope element class on set className', function () { var el = document.createElement('x-scope-class'); document.body.appendChild(el); Polymer.flush(); var div = document.createElement('div'); el.shadowRoot.appendChild(div); Polymer.flush(); div.className = 'foo'; assert.isTrue(div.classList.contains('foo')); assert.isTrue(div.classList.contains('style-scope')); assert.isTrue(div.classList.contains('x-scope-class')); el.shadowRoot.appendChild(div); Polymer.flush(); document.body.removeChild(el); }); }); } })(); </script> </body> </html>