mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
334 lines
12 KiB
HTML
334 lines
12 KiB
HTML
<!doctype html>
|
|
<!--
|
|
@license
|
|
Copyright (c) 2014 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 src="../../../web-component-tester/browser.js"></script>
|
|
<link rel="import" href="../../polymer.html">
|
|
<link rel="import" href="styling-scoped-elements.html">
|
|
<style>
|
|
#priority[style-scope=x-styled], #priority.style-scope.x-styled {
|
|
border: 1px solid black;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="scoped">no margin</div>
|
|
|
|
<x-styled>
|
|
<div class="content1">Foo</div>
|
|
<div class="content2">Bar</div>
|
|
<div class="content">Content</div>
|
|
</x-styled>
|
|
|
|
<x-styled class="wide"></x-styled>
|
|
|
|
<button is="x-button"></button>
|
|
<button class="special" is="x-button"></button>
|
|
|
|
<x-dynamic-scope></x-dynamic-scope>
|
|
|
|
<template id="bind" is="dom-bind">
|
|
<div id="dom-bind-static" class="static">static</div>
|
|
<span id="dom-bind-dynamic" class$="[[dynamic]]">[[dynamic]]</span>
|
|
</template>
|
|
|
|
<x-dynamic-svg></x-dynamic-svg>
|
|
<x-specificity></x-specificity>
|
|
<x-specificity class="bar"></x-specificity>
|
|
<div is="x-specificity-parent">
|
|
<div is="x-specificity-nested"></div>
|
|
</div>
|
|
<x-overriding></x-overriding>
|
|
|
|
<x-scope-no-class>
|
|
<div></div>
|
|
</x-scope-no-class>
|
|
|
|
<script>
|
|
suite('scoped-styling', function() {
|
|
|
|
function assertComputed(element, value, property) {
|
|
var computed = getComputedStyle(element);
|
|
property = property || 'border-top-width';
|
|
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');
|
|
var button = document.querySelector('[is=x-button]');
|
|
var specialButton = document.querySelector('[is=x-button].special');
|
|
|
|
test(':host, :host(...)', function() {
|
|
assertComputed(styled, '1px');
|
|
assertComputed(styledWide, '2px');
|
|
|
|
});
|
|
|
|
test(':host-context(...)', function() {
|
|
assertComputed(styled.$.child.$.gchild1.$.target, '0px');
|
|
assertComputed(styled.$.child.$.gchild2.$.target, '10px');
|
|
assertComputed(styledWide.$.child.$.gchild1.$.target, '10px');
|
|
assertComputed(styledWide.$.child.$.gchild2.$.target, '10px');
|
|
});
|
|
|
|
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('::content selectors', function() {
|
|
var content = document.querySelector('.content');
|
|
var content1 = document.querySelector('.content1');
|
|
var content2 = document.querySelector('.content2');
|
|
assertComputed(content, '6px');
|
|
assertComputed(content1, '13px');
|
|
assertComputed(content2, '14px');
|
|
});
|
|
|
|
test('::shadow selectors', function() {
|
|
assertComputed(styled.$.child.$.shadow, '7px');
|
|
});
|
|
|
|
test('/deep/ selectors', function() {
|
|
assertComputed(styled.$.child.$.deep, '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.dom.flush();
|
|
assertComputed(d, '4px');
|
|
Polymer.dom(document.body).appendChild(d);
|
|
Polymer.dom.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.root).appendChild(d);
|
|
Polymer.dom.flush();
|
|
assertComputed(d, '4px');
|
|
Polymer.dom(styled.root).removeChild(d);
|
|
Polymer.dom.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.root).appendChild(d);
|
|
Polymer.dom.flush();
|
|
assertComputed(d, '4px');
|
|
});
|
|
|
|
test('elements dynamically added/removed from host', function() {
|
|
var d = document.createElement('div');
|
|
d.classList.add('scoped');
|
|
d.classList.add('blank');
|
|
d.textContent = 'Dynamically... unScoped!';
|
|
Polymer.dom(styled).appendChild(d);
|
|
Polymer.dom.flush();
|
|
assertComputed(d, '0px');
|
|
Polymer.dom(document.body).appendChild(d);
|
|
Polymer.dom.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.dom.flush();
|
|
assertComputed(d, '0px');
|
|
Polymer.dom(styled).removeChild(d);
|
|
Polymer.dom.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.dom.flush();
|
|
assertComputed(d, '0px');
|
|
});
|
|
|
|
test('keyframes change scope', function(done) {
|
|
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');
|
|
});
|
|
|
|
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('type extension elements', function() {
|
|
assertComputed(button, '10px');
|
|
assertComputed(specialButton, '11px');
|
|
});
|
|
|
|
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.shadyRoot) {
|
|
// style properly removed
|
|
assert.notOk(el.querySelector('style'));
|
|
}
|
|
assertComputed(el, '40px');
|
|
document.body.removeChild(el);
|
|
});
|
|
|
|
suite('scoped-styling-shady-only', function() {
|
|
|
|
suiteSetup(function() {
|
|
if (Polymer.Settings.useNativeShadow) {
|
|
this.skip();
|
|
}
|
|
});
|
|
|
|
test('element style precedence below document styles', function() {
|
|
assertComputed(styledWide.$.priority, '1px');
|
|
});
|
|
|
|
test('styles shimmed in registration order', function() {
|
|
var s$ = document.head.querySelectorAll('style[scope]');
|
|
var expected = ['x-keyframes', 'x-keyframes-1', 'x-keyframes-0', 'x-gchild', 'x-child2',
|
|
'x-styled', 'x-button', 'x-mixed-case', 'x-mixed-case-button',
|
|
'x-dynamic-scope', 'x-dynamic-template', 'x-dynamic-svg',
|
|
'x-specificity', 'x-overriding', 'x-overriding-0',
|
|
'x-specificity-parent-0', 'x-specificity-nested-0'];
|
|
var actual = [];
|
|
for (var i=0; i<s$.length; i++) {
|
|
actual.push(s$[i].getAttribute('scope'));
|
|
}
|
|
assert.deepEqual(actual, expected);
|
|
});
|
|
|
|
test('svg elements properly scoped', function() {
|
|
assert.include(styled.$.circle.getAttribute('class'), 'style-scope x-styled');
|
|
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.equal(s.className, 'style-scope x-styled');
|
|
s.serializeValueToAttribute('foo', 'class');
|
|
assert.equal(s.className, 'foo style-scope x-styled');
|
|
//
|
|
assert.equal(scope.className, 'style-scope x-scope-class');
|
|
s.serializeValueToAttribute('foo', 'class', scope);
|
|
assert.include(scope.className, 'foo style-scope x-scope-class');
|
|
});
|
|
|
|
test('mixed-case elements', function() {
|
|
var x = document.createElement('x-mixed-case');
|
|
document.body.appendChild(x);
|
|
assertComputed(x, '13px');
|
|
x = document.createElement('button', 'x-mixed-case-button');
|
|
document.body.appendChild(x);
|
|
assertComputed(x, '14px');
|
|
});
|
|
|
|
test('specificity of :host selector with class', function() {
|
|
assertComputed(document.querySelector('x-specificity'), '1px');
|
|
assertComputed(document.querySelector('x-specificity.bar'), '2px');
|
|
});
|
|
|
|
test('specificity of ::content > :not(template) selector', function() {
|
|
assertComputed(document.querySelector('[is=x-specificity-nested]'), '10px');
|
|
});
|
|
|
|
test('x-scope with no class attribute', function () {
|
|
assert.equal(document.querySelector('x-scope-no-class > div').className, 'style-scope x-scope-no-class');
|
|
})
|
|
});
|
|
|
|
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');
|
|
});
|
|
});
|
|
|
|
</script>
|
|
</body>
|
|
</html>
|