@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,633 lines (1,491 loc) • 69.5 kB
HTML
<!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>
if (window.customElements) {
customElements.forcePolyfill = true;
}
window.ShadyDOM = {
force: true
};
</script>
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
<script src="../../../web-component-tester/browser.js"></script>
<link rel="import" href="../../polymer.html">
</head>
<body>
<dom-module id="x-project">
<template>
x-project: [<slot></slot>]
</template>
</dom-module>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-project'
});
});
</script>
<dom-module id="x-reproject">
<template>
<x-project>x-reproject: [<slot></slot>]</x-project>
</template>
</dom-module>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-reproject'
});
});
</script>
<dom-module id='x-rereproject'>
<template>
<x-reproject>x-rereproject: [<slot></slot>]</x-reproject>
</template>
</dom-module>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-rereproject',
attachedCount: 0,
attached: function() {
this.attachedCount++;
}
});
});
</script>
<dom-module id="x-test">
<template>
<x-rereproject><span id="projected">projected</span></x-rereproject>
</template>
</dom-module>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-test'
});
});
</script>
<dom-module id="x-test-no-distribute">
<template>
<span>Local dom without insertion point.</span>
</template>
</dom-module>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-test-no-distribute'
});
});
</script>
<dom-module id="x-distribute">
<template>
<div>
<span>Elements without test attribute</span>
<div id="notTestContainer" style="color: white; background-color: green; min-height: 1em;">
<slot id="notTestContent"></slot>
</div>
<span>Elements with test attribute</span>
<div style="color: white; background-color: red; min-height: 1em;">
<div id="testContainer">
<slot id="testContent" name="test"></slot>
</div>
</div>
</div>
</template>
</dom-module>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: "x-distribute"
});
});
</script>
<dom-module id="x-compose">
<template><x-project id="project"></x-project></template>
</dom-module>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-compose'
});
});
</script>
<dom-module id="x-select3">
<template><slot id="x-select3-slot" name="s3"></slot></template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-select3'});
});
</script>
</dom-module>
<dom-module id="x-select2">
<template><x-select3 id="select"><slot id="x-select2-slot" name="s2"></slot></x-select3></template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-select2'});
});
</script>
</dom-module>
<dom-module id="x-select1">
<template><x-select2 id="select"><slot id="x-select1-slot" name="s1"></slot></x-select2></template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-select1'});
});
</script>
</dom-module>
<dom-module id="x-echo">
<template><slot></slot></template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-echo'});
});
</script>
</dom-module>
<dom-module id="x-simple">
<template><div>simple</div></template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-simple'});
});
</script>
</dom-module>
<dom-module id="x-redistribute-a-b">
<template>
<x-echo id="echo1"><slot name="a"></slot></x-echo>
<x-echo id="echo2"><slot name="b"></slot></x-echo>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-redistribute-a-b'});
});
</script>
</dom-module>
<dom-module id="x-attr">
<template>Attr1</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-attr',
hostAttributes: {
slot: 'bar'
}
});
});</script>
</dom-module>
<dom-module id="x-attr2">
<template>Attr2</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-attr2',
// TODO(sorvell): cannot put `slot` into properties because it is patched.
ready: function() {
this.slot = 'foo';
}
});
});
</script>
</dom-module>
<dom-module id="x-select-attr">
<template>
Foo: [<slot name="foo"></slot>]
Bar: [<slot name="bar"></slot>]
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-select-attr'});
});
</script>
</dom-module>
<dom-module id="x-compose-select-attr">
<template>
<x-select-attr id="select">
<x-attr id="attr1"></x-attr>
<x-attr2 id="attr2"></x-attr2>
</x-select-attr>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-compose-select-attr'});
});
</script>
</dom-module>
<dom-module id="x-clonate">
<template><span>[</span><slot></slot><span>]</span></template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-clonate'
});
});
</script>
</dom-module>
<dom-module id="x-attach3">
<template>
<style>
:host {
display: block;
border: 1px dashed orange;
padding: 4px;
box-sizing: border-box;
}
:host > ::slotted(.add3) {
box-sizing: border-box;
height: 20px;
background: #333;
border: 2px solid yellow;
}
</style>
<slot></slot>
<template is="dom-if" if="{{shouldIf(done.count)}}">
<x-attach2></x-attach2>
</template>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-attach3',
properties: {
done: {value: {count: 0}}
},
ready: function() {
this.done.count++;
},
attached: function() {
var d = document.createElement('div');
d.className = 'add3';
this.appendChild(d);
},
shouldIf: function(x) {
return x < 3;
}
});
});
</script>
</dom-module>
<dom-module id="x-attach2">
<template>
<style>
:host {
display: block;
border: 1px dashed tomato;
padding: 4px;
}
x-attach3 > ::slotted(.add2) {
box-sizing: border-box;
height: 20px;
background: gray;
border: 2px solid yellow;
}
</style>
<x-attach3><slot></slot></x-attach3>
<template is="dom-if" if="{{shouldIf(done.count)}}">
<x-attach1></x-attach1>
</template>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-attach2',
properties: {
done: {value: {count: 0}}
},
ready: function() {
this.done.count++;
},
attached: function() {
var d = document.createElement('div');
d.className = 'add2';
this.appendChild(d);
},
shouldIf: function(x) {
return x < 3;
}
});
});
</script>
</dom-module>
<dom-module id="x-attach1">
<template>
<style>
:host {
display: block;
border: 1px dashed seagreen;
padding: 4px;
}
.slotContainer ::slotted(.add1) {
box-sizing: border-box;
height: 20px;
background: lightgray;
border: 2px solid yellow;
}
</style>
<x-attach2><div class="slotContainer"><slot></slot><div></x-attach2>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-attach1',
attached: function() {
var d = document.createElement('div');
d.className = 'add1';
this.appendChild(d);
}
});
});
</script>
</dom-module>
<dom-module id="x-commented">
<template><span>[</span><!--comment--><slot></slot></span><span>]</span></slot></template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-commented'});
});
</script>
</dom-module>
<dom-module id="polymer-dom-repeat">
<template>
<div>
<div>
<div>
<div id="container">
<template id="repeater" is="dom-repeat" items="{{items}}">
<div>stuff</div>
</template>
</div>
</div>
</div>
</div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'polymer-dom-repeat',
properties: {
items: {
value: function() {
return ['a', 'b', 'c', 'd', 'e'];
}
}
}
});
});
</script>
</dom-module>
<dom-module id="x-deep-contains">
<template>
<div id="shadowed"></div>
<slot name="light"></slot>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-deep-contains',
created: function() {
var e = document.createElement('div');
e.setAttribute('slot', 'light');
this.appendChild(e);
e = document.createElement('div');
e.setAttribute('slot', 'notdistributed');
this.appendChild(e);
}
});
});
</script>
</dom-module>
<dom-module id="x-wrapped">
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-wrapped'
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-0-0">
<template>
<slot></slot>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-0-0',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-0-0-light-0">
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-0-0-light-0',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-0-0-light">
<template>
<div>
<div>
<x-shadow-host-root-0-0-light-0></x-shadow-host-root-0-0-light-0>
</div>
</div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-0-0-light',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-0-1">
<template>
<slot></slot>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-0-1',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-0-1-light">
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-0-1-light',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-0">
<template>
<slot></slot>
<div>
<x-shadow-host-root-0-0>
<x-shadow-host-root-0-0-light></x-shadow-host-root-0-0-light>
</x-shadow-host-root-0-0>
</div>
<x-shadow-host-root-0-1>
<x-shadow-host-root-0-1-light></x-shadow-host-root-0-1-light>
</x-shadow-host-root-0-1>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-0',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-0-light">
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-0-light',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-1-0">
<template>
<slot></slot>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-1-0',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-1-0-light">
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-1-0-light',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-1-1">
<template>
<slot></slot>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-1-1',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-1-1-light">
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-1-1-light',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-1">
<template>
<slot></slot>
<div>
<x-shadow-host-root-1-0>
<x-shadow-host-root-1-0-light></x-shadow-host-root-1-0-light>
</x-shadow-host-root-1-0>
</div>
<div>
<div>
<div>
<x-shadow-host-root-1-1>
<x-shadow-host-root-1-1-light></x-shadow-host-root-1-1-light>
</x-shadow-host-root-1-1>
</div>
</div>
</div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-1',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-1-light-0">
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-1-light-0',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-1-light">
<template>
<x-shadow-host-root-1-light-0></x-shadow-host-root-1-light-0>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-1-light',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root">
<template>
<slot></slot>
<div>
<div>
<x-shadow-host-root-0>
<x-shadow-host-root-0-light></x-shadow-host-root-0-light>
</x-shadow-host-root-0>
</div>
</div>
<div>
<x-shadow-host-root-1>
<x-shadow-host-root-1-light></x-shadow-host-root-1-light>
</x-shadow-host-root-1>
</div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-shadow-host-root-light">
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-shadow-host-root-light',
hostAttributes: {
tabindex: '-1'
}
});
});
</script>
</dom-module>
<dom-module id="x-outer">
<template>
<x-inner id="inner">
<slot></slot>
</x-inner>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-outer'
});
});
</script>
</dom-module>
<dom-module id="x-inner">
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-inner',
attached: function(){
this.listen(this, 'click', '_onClick');
},
_onClick: function(event){
this._eventTarget = event.target;
}
});
});
</script>
</dom-module>
<x-test></x-test>
<div class="accessors">
<x-test-no-distribute><div class="child"></div></x-test-no-distribute>
<x-project><div class="child"></div></x-project>
</div>
<x-test-no-distribute id="noDistribute">
<div class="bar">Bar</div>
<div class="foo">Foo</div>
</x-test-no-distribute>
<x-select1>
<div class="select-child"></div>
</x-select1>
<x-select-class1>
<div></div>
</x-select-class1>
<x-select-attr>
<x-attr></x-attr>
</x-select-attr>
<x-compose-select-attr></x-compose-select-attr>
<x-redistribute-a-b></x-redistribute-a-b>
<div id="container">
<x-echo></x-echo>
<span>1</span>
<span>2</span>
</div>
<x-deep-contains></x-deep-contains>
<x-wrapped></x-wrapped>
<x-shadow-host-root>
<x-shadow-host-root-light></x-shadow-host-root-light>
</x-shadow-host-root>
<x-outer>
<button>click me</button>
</x-outer>
<script>
if (!window.ShadyDOM) {
ShadyDOM = {
patch: function() {},
flush: function() {}
};
}
</script>
<script>
'use strict';
function createEnabledElement(tag) {
var e = document.createElement(tag);
document.body.appendChild(e);
document.body.removeChild(e);
return e;
}
function allInsertionPoints(e) {
var r = [];
while (e) {
e = e.assignedSlot;
if (e) {
r.push(e);
}
}
return r;
}
var checkUnpatchedDom = false;
suite('ShadyDOM', function() {
var testElement;
suiteSetup(function() {
testElement = document.querySelector('x-test');
});
test('querySelector (local)', function() {
var projected = testElement.root.querySelector('#projected');
assert.equal(projected.textContent, 'projected');
var p2 = testElement.querySelector('#projected');
assert.isNull(p2);
var rere = testElement.root.querySelector('x-rereproject');
assert.equal(rere.is, 'x-rereproject');
var re = rere.root.querySelector('x-reproject');
assert.equal(re.is, 'x-reproject');
var p = re.root.querySelector('x-project');
assert.equal(p.is, 'x-project');
});
test('querySelectorAll (local)', function() {
var rere = testElement.root.querySelector('x-rereproject');
var re = rere.root.querySelector('x-reproject');
var p = re.root.querySelector('x-project');
var rereList = rere.root.querySelectorAll('*');
assert.include(rereList, re);
assert.equal(rereList.length, 2);
var reList = re.root.querySelectorAll('*');
assert.include(reList, p);
assert.equal(reList.length, 2);
var pList = p.root.querySelectorAll('*');
assert.equal(pList.length, 1);
});
test('querySelector (light)', function() {
var projected = testElement.root.querySelector('#projected');
var rere = testElement.root.querySelector('x-rereproject');
var re = rere.root.querySelector('x-reproject');
var p = re.root.querySelector('x-project');
assert.equal(rere.querySelector('#projected'), projected);
assert(re.querySelector('slot'));
assert(p.querySelector('slot'));
});
test('querySelectorAll (light)', function() {
var projected = testElement.root.querySelector('#projected');
var rere = testElement.root.querySelector('x-rereproject');
var re = rere.root.querySelector('x-reproject');
var p = re.root.querySelector('x-project');
assert.equal(rere.querySelectorAll('#projected')[0], projected);
assert(re.querySelectorAll('slot').length, 1);
assert(p.querySelectorAll('slot').length, 1);
});
test('querySelectorAll with dom-repeat', function() {
var el = document.createElement('polymer-dom-repeat');
document.body.appendChild(el);
el.$.repeater.render();
Polymer.flush();
assert.equal(el.$.container.querySelectorAll('*').length, 7, 'querySelectorAll finds repeated elements');
document.body.removeChild(el);
});
test('querySelector document', function() {
assert.ok(document.querySelector('body'));
});
test('projection', function() {
var projected = testElement.root.querySelector('#projected');
assert.equal(projected.textContent, 'projected');
var rere = testElement.root.querySelector('x-rereproject');
assert.equal(rere.is, 'x-rereproject');
var re = rere.root.querySelector('x-reproject');
assert.equal(re.is, 'x-reproject');
var p = re.root.querySelector('x-project');
assert.equal(p.is, 'x-project');
var c1 = rere.root.querySelector('slot');
assert.include(c1.assignedNodes({flatten: true}), projected);
var c2 = re.root.querySelector('slot');
assert.include(c2.assignedNodes({flatten: true}), projected);
var c3 = p.root.querySelector('slot');
assert.include(c3.assignedNodes({flatten: true}), projected);
var ip$ = [c1, c2, c3];
var as$ = allInsertionPoints(projected);
assert.deepEqual(as$, ip$);
});
test('shadyRoot (reproject)', function() {
var select = document.querySelector('x-select1');
var child = select.firstElementChild;
var c1 = select.root.querySelector('slot');
var c2 = select.$.select.root.querySelector('slot');
var c3 = select.$.select.$.select.root.querySelector('slot');
assert.equal(c1.getAttribute('name'), 's1');
assert.equal(c2.getAttribute('name'), 's2');
assert.equal(c3.getAttribute('name'), 's3');
// var ip$ = [c1, c2, c3];
assert.equal(child.className, 'select-child');
assert.equal(allInsertionPoints(child).length, 0);
child.slot = 's1';
Polymer.flush();
assert.deepEqual(allInsertionPoints(child), [c1]);
child.slot = 's2';
c1.setAttribute('name', 's2');
c1.slot = 's2';
Polymer.flush();
assert.deepEqual(allInsertionPoints(child), [c1, c2]);
child.slot = 's3';
c1.setAttribute('name', 's3');
c1.slot = 's3';
c2.setAttribute('name', 's3');
c2.slot = 's3';
Polymer.flush();
assert.deepEqual(allInsertionPoints(child), [c1, c2, c3]);
child.slot = '';
Polymer.flush();
assert.deepEqual(allInsertionPoints(child), []);
child.slot = 's3';
Polymer.flush();
assert.deepEqual(allInsertionPoints(child), [c1, c2, c3]);
child.slot = '';
Polymer.flush();
assert.deepEqual(allInsertionPoints(child), []);
child.slot = 's2';
c1.setAttribute('name', 's2');
c1.slot = 's2';
c2.setAttribute('name', 's2');
c2.slot = 's2';
Polymer.flush();
assert.deepEqual(allInsertionPoints(child), [c1, c2]);
child.slot = 's1';
c1.setAttribute('name', 's1');
c1.slot = 's1';
Polymer.flush();
assert.deepEqual(allInsertionPoints(child), [c1]);
child.slot = '';
Polymer.flush();
assert.deepEqual(allInsertionPoints(child), []);
});
test('without a host setting hostAttributes/reflecting properties provokes distribution', function() {
var e = document.querySelector('x-select-attr');
var ip$ = e.root.querySelectorAll('slot');
var c = e.firstElementChild;
Polymer.flush();
assert.equal(allInsertionPoints(c)[0], ip$[1], 'child not distributed based on host attribute');
c.slot = 'foo';
Polymer.flush();
assert.equal(allInsertionPoints(c)[0], ip$[0], 'child not distributed based on reflecting attribute');
c.slot = '';
Polymer.flush();
assert.equal(allInsertionPoints(c).length, 0, 'child not distributed based on reflecting attribute');
});
test('within a host setting hostAttributes/reflecting properties provokes distribution', function() {
var e = document.querySelector('x-compose-select-attr');
var ip$ = e.$.select.root.querySelectorAll('slot');
var c1 = e.$.attr1;
Polymer.flush();
assert.equal(allInsertionPoints(c1)[0], ip$[1], 'child not distributed based on host attribute');
c1.slot = 'foo';
Polymer.flush();
assert.equal(allInsertionPoints(c1)[0], ip$[0], 'child not distributed based on reflecting attribute');
c1.slot = 'bar';
Polymer.flush();
assert.equal(allInsertionPoints(c1)[0], ip$[1], 'child not distributed based on reflecting attribute');
var c2 = e.$.attr2;
Polymer.flush();
assert.equal(allInsertionPoints(c2)[0], ip$[0], 'child not distributed based on default value');
});
test('appendChild (light)', function() {
var rere = testElement.root.querySelector('x-rereproject');
var s = document.createElement('span');
s.id = 'added';
s.textContent = 'Added';
rere.appendChild(s);
assert.equal(testElement.root.querySelector('#added'), s);
});
test('insertBefore (light)', function() {
var rere = testElement.root.querySelector('x-rereproject');
var ref = testElement.root.querySelector('#added');
var s = document.createElement('span');
s.id = 'added2';
s.textContent = 'Added2';
rere.insertBefore(s, ref);
assert.equal(testElement.root.querySelector('#added2'), s);
});
test('removeChild (light)', function() {
var added = testElement.root.querySelector('#added');
var added2 = testElement.root.querySelector('#added2');
var rere = testElement.root.querySelector('x-rereproject');
assert.equal(testElement.root.querySelectorAll('*').length, 4);
rere.removeChild(added);
rere.removeChild(added2);
assert.equal(testElement.root.querySelectorAll('*').length, 2);
});
test('appendChild (local)', function() {
var rere = testElement.root.querySelector('x-rereproject');
var s = document.createElement('span');
s.id = 'local';
s.textContent = 'Local';
rere.root.appendChild(s);
assert.equal(rere.root.querySelector('#local'), s);
});
test('insertBefore (local)', function() {
var rere = testElement.root.querySelector('x-rereproject');
var ref = testElement.root.querySelector('#local');
var s = document.createElement('span');
s.id = 'local2';
s.textContent = 'Local2';
rere.root.insertBefore(s, ref);
assert.equal(rere.root.querySelector('#local2'), s);
});
test('removeChild (local)', function() {
var rere = testElement.root.querySelector('x-rereproject');
var local = rere.root.querySelector('#local');
var local2 = rere.root.querySelector('#local2');
rere.root.removeChild(local);
rere.root.removeChild(local2);
assert.equal(rere.root.querySelectorAll('#local').length, 0);
});
test('localDom.insertBefore first element results in minimal change', function() {
var children = testElement.root.childNodes;
var rere = testElement.root.querySelector('x-rereproject');
assert.equal(rere.attachedCount, 1);
var s = document.createElement('span');
s.id = 'local-first';
s.textContent = 'Local First';
testElement.root.insertBefore(s, children[0]);
assert.equal(testElement.root.querySelector('#local-first'), s);
assert.equal(rere.attachedCount, 1);
testElement.root.removeChild(s);
assert.equal(rere.attachedCount, 1);
});
test('appendChild (fragment, local)', function() {
var rere = testElement.root.querySelector('x-rereproject');
var fragment = document.createDocumentFragment();
var childCount = 5;
for (var i=0; i < childCount; i++) {
var s = document.createElement('span');
s.textContent = i;
fragment.appendChild(s);
}
rere.root.appendChild(fragment);
var added = rere.root.querySelectorAll('span');
assert.equal(added.length, childCount);
for (i=0; i < added.length; i++) {
rere.root.removeChild(added[i]);
}
assert.equal(rere.root.querySelectorAll('span').length, 0);
});
test('insertBefore (fragment, local)', function() {
var rere = testElement.root.querySelector('x-rereproject');
var fragment = document.createDocumentFragment();
var childCount = 5;
for (var i=0; i < childCount; i++) {
var s = document.createElement('span');
s.textContent = i;
fragment.appendChild(s);
}
var l = document.createElement('span');
l.textContent = 'last';
rere.root.appendChild(l);
rere.root.insertBefore(fragment, l);
var added = rere.root.querySelectorAll('span');
assert.equal(added.length, childCount+1);
assert.equal(added[added.length-1], l);
for (i=0; i < added.length; i++) {
rere.root.removeChild(added[i]);
}
assert.equal(rere.root.querySelectorAll('span').length, 0);
});
test('mutations using fragments without logical dom', function() {
var d = document.createElement('div');
document.body.appendChild(d);
assert.equal(d.childNodes.length, 0);
var frag = document.createDocumentFragment();
var c = document.createElement('div');
frag.appendChild(c);
d.appendChild(frag);
assert.equal(d.childNodes.length, 1);
assert.equal(d.firstChild, c);
var c1 = document.createElement('div');
frag.appendChild(c1);
d.appendChild(frag);
assert.equal(d.childNodes.length, 2);
assert.equal(d.firstChild, c);
assert.equal(d.lastChild, c1);
});
test('appendChild interacts with unmanaged parent tree', function() {
var container = document.querySelector('#container');
var echo = container.firstElementChild;
assert.equal(echo.localName, 'x-echo');
var s1 = echo.nextElementSibling;
assert.equal(s1.textContent, '1');
var s2 = s1.nextElementSibling;
assert.equal(s2.textContent, '2');
assert.equal(container.children.length, 3);
echo.appendChild(s1);
Polymer.flush();
assert.equal(container.children.length, 2);
assert.equal(echo.nextElementSibling, s2);
echo.appendChild(s2);
Polymer.flush();
assert.equal(container.children.length, 1);
assert.equal(echo.nextElementSibling, null);
container.appendChild(s1);
Polymer.flush();
assert.equal(container.children.length, 2);
assert.equal(echo.nextElementSibling, s1);
container.appendChild(s2);
Polymer.flush();
assert.equal(container.children.length, 3);
assert.equal(echo.nextElementSibling, s1);
assert.equal(s1.nextElementSibling, s2);
});
test('distribute (forced)', function() {
var rere = testElement.root.querySelector('x-rereproject');
var re = rere.root.querySelector('x-reproject');
var p = re.root.querySelector('x-project');
var s = document.createElement('span');
s.id = 'light';
s.textContent = 'Light';
rere.appendChild(s);
assert.equal(rere.querySelector('#light'), s);
assert.equal(s.parentNode, rere);
if (checkUnpatchedDom) {
assert.notEqual(Polymer.TreeApi.Composed.getParentNode(s), rere);
}
if (checkUnpatchedDom) {
assert.equal(Polymer.TreeApi.Composed.getParentNode(s), p);
}
rere.removeChild(s);
if (checkUnpatchedDom) {
assert.equal(Polymer.TreeApi.Composed.getParentNode(s), p);
}
if (checkUnpatchedDom) {
assert.equal(Polymer.TreeApi.Composed.getParentNode(s), null);
}
});
test('queryDistributedElements', function() {
var rere = testElement.root.querySelector('x-rereproject');
var re = rere.root.querySelector('x-reproject');
var p = re.root.querySelector('x-project');
var projected = testElement.root.querySelector('#projected');
var d$ = p.queryDistributedElements('*');
assert.equal(d$.length, 1);
assert.equal(d$[0], projected);
});
test('getEffectiveChildNodes', function() {
var rere = testElement.root.querySelector('x-rereproject');
var re = rere.root.querySelector('x-reproject');
var projected = testElement.root.querySelector('#projected');
var c$ = re.getEffectiveChildNodes();
assert.equal(c$.length, 3);
assert.equal(c$[1], projected);
});
test('querySelector', function() {
var test = document.querySelector('x-test');
var rere = document.querySelector('x-rereproject');
var projected = document.querySelector('#projected');
assert.ok(test);
assert.notOk(rere);
assert.notOk(projected);
});
test('event', function() {
var rere = testElement.root.querySelector('x-rereproject');
var re = rere.root.querySelector('x-reproject');
var p = re.root.querySelector('x-project');
var eventHandled = 0;
testElement.addEventListener('test-event', function(e) {
eventHandled++;
assert.equal(e.composedPath()[0], p);
assert.equal(e.target, testElement);
var path = e.composedPath();
// path includes window only on more recent Shadow DOM implementations
// account for that here.
assert.ok(path.length >= 10);
assert.equal(path[0], p);
assert.equal(path[2], re);
assert.equal(path[4], rere);
assert.equal(path[6], testElement);
// event.path *should* be an array
assert.isArray(path);
assert.isFunction(path.indexOf);
assert(path.indexOf(testElement) > -1);
});
rere.addEventListener('test-event', function(e) {
eventHandled++;
assert.equal(e.target, rere);
});
p.fire('test-event');
assert.equal(eventHandled, 2);
});
test('event.target', function() {
var e = document.querySelector('x-outer');
var b = document.querySelector('x-outer button');
b.dispatchEvent(new Event('click', {bubbles: true}));
assert.equal(e.$.inner._eventTarget.localName, 'button', 'event restarted incorrectly');
});
test('parentNode', function() {
var rere = testElement.root.querySelector('x-rereproject');
var projected = testElement.root.querySelector('#projected');
assert.equal(testElement.parentNode, document.body);
assert.equal(projected.parentNode, rere);
});
test('childNodes is an array', function() {
var test = document.querySelector('x-test');
assert.isTrue(Array.isArray(test.childNodes));
});
test('cloneNode shallow', function() {
var a = document.createElement('div');
a.innerHTML = '<x-clonate><span>1</span><span>2</span></x-clonate>';
var b = a.firstElementChild.cloneNode();
document.body.appendChild(b);
assert.equal(b.childNodes.length, 0, 'shallow copy has incorrect children');
if (checkUnpatchedDom) {
assert.equal(b.children.length, 2, 'shallow copy has incorrect composed children');
}
});
test('cloneNode deep', function() {
var a = document.createElement('div');
a.innerHTML = '<x-clonate><span>1</span><span>2</span></x-clonate>';
var b = a.cloneNode(true);
document.body.appendChild(b);
assert.equal(b.firstElementChild.childNodes.length, 2, 'deep copy has incorrect children');
if (checkUnpatchedDom) {
assert.equal(b.children.length, 4, 'deep copy has incorrect composed children');
}
});
test('importNode shallow', function() {
var a = document.createElement('div');
a.innerHTML = '<x-clonate><span>1</span><span>2</span></x-clonate>';
// NOTE: Safari defaults do `deep` true for importNode so be explicit here.
var b = document.importNode(a.firstElementChild, false);
document.body.appendChild(b);
assert.equal(b.childNodes.length, 0, 'shallow import has incorrect children');
if (checkUnpatchedDom) {
assert.equal(b.children.length, 2, 'shallow import has incorrect composed children');
}
});
test('importNode deep', function() {
var a = document.createElement('div');
a.innerHTML = '<x-clonate><span>1</span><span>2</span></x-clonate>';
var b = document.importNode(a, true);
document.body.appendChild(b);
assert.equal(b.firstElementChild.childNodes.length, 2, 'deep copy has incorrect children');
if (checkUnpatchedDom) {
assert.equal(b.children.length, 4, 'deep copy has incorrect composed children');
}
});
test('styling: flush causes attached and re-flushes if necessary', function(done) {
var a = document.createElement('x-attach1');
document.body.appendChild(a);
Polymer.flush();
assert.equal(a.offsetHeight, 540);
done();
});
test('flush reentrancy', function() {
// Setup callbacks
var order = [];
var cb1 = sinon.spy(function() { order.push(cb1); });
var cb2 = sinon.spy(function() { order.push(cb2); });
var cb3 = sinon.spy(function() { order.push(cb3); });
var cb4 = sinon.spy(function() { order.push(cb4); });
var cbReentrant = sinon.spy(function() {
order.push(cbReentrant);
ShadyDOM.enqueue(cb3);
Polymer.flush();
ShadyDOM.enqueue(cb4);
});
// Enqueue
ShadyDOM.enqueue(cb1);
ShadyDOM.enqueue(cbReentrant);
ShadyDOM.enqueue(cb2);
// Flush
Polymer.flush();
// Check callbacks called and in correct order
assert.isTrue(cb1.calledOnce);
assert.isTrue(cb2.calledOnce);
assert.isTrue(cb3.calledOnce);
assert.isTrue(cb4.calledOnce);
assert.isTrue(cbReentrant.calledOnce);
assert.sameMembers(order, [cb1, cbReentrant, cb2, cb3, cb4]);
});
test('event.composedPath correctly calculated for elements with destination insertion points', function(done) {
var re = document.createElement('x-reproject');
document.body.appendChild(re);
Polymer.flush();
var p = re.root.querySelector('x-project');
var child = document.createElement('p');
child.innerHTML = "hello";
// child will be inserted into p after distributeContent is performed.
re.appendChild(child);
Polymer.flush();
child.addEventListener('child-event', function(e){
var path = e.composedPath();
assert.isTrue(path.indexOf(p) !== -1, 'path contains p');
assert.isTrue(path.indexOf(re) !== -1, 'path contains re');
done();
});
var evt = new CustomEvent('child-event');
child.dispatchEvent(evt);
document.body.removeChild(re);
});
});
suite('Accessors', function() {
var noDistribute, distribute;
suiteSetup(function() {
noDistribute = document.querySelector('.accessors x-test-no-distribute');
distribute = document.querySelector('.accessors x-project');
});
test('node accessors (no distribute)', function() {
var child = noDistribute.children[0];
assert.isTrue(child.classList.contains('child'), 'test node could not be found');
var before = document.createElement('div');
var after = document.createElement('div');
noDistribute.insertBefore(before, child);
noDistribute.appendChild(after);
Polymer.flush();
assert.equal(noDistribute.firstChild, before, 'firstChild incorrect');
assert.equal(noDistribute.lastChild, after, 'lastChild incorrect');
assert.equal(before.nextSibling, child, 'nextSibling incorrect');
assert.equal(child.nextSibling, after, 'nextSibling incorrect');
assert.equal(after.previousSibling, child, 'previousSibling incorrect');
assert.equal(after.nextSibling, null, 'nextSibling incorrect');
assert.equal(child.previousSibling, before, 'previousSibling incorrect');
});
test('node accessors (distribute)', function() {
var child = distribute.children[0];
assert.isTrue(child.classList.contains('child'), 'test node could not be found');
var before = document.createElement('div');
var after = document.createElement('div');
distribute.insertBefore(before, child);
distribute.appendChild(after);
Polymer.flush();
assert.equal(distribute.firstChild, before, 'firstChild incorrect');
assert.equal(distribute.lastChild, after, 'lastChild incorrect');
assert.equal(before.nextSibling, child, 'nextSibling incorrect');
assert.equal(child.nextSibling, after, 'nextSibling incorrect');
assert.equal(after.previousSibling, child, 'previousSibling incorrect');
assert.equal(after.nextSibling, null, 'nextSibling incorrect');
assert.equal(child.previousSibling, before, 'previousSibling incorrect');
});
test('element accessors (no distribute)', function() {
var parent = document.createElement('x-test-no-distribute');
var child = document.createElement('div');
parent.appendChild(child);
var before = document.createElement('div');
var after = document.createElement('div');
parent.insertBefore(before, child);
parent.appendChild(after);
assert.equal(parent.firstElementChild, before, 'firstElementChild incorrect');
assert.equal(parent.lastElementChild, after, 'lastElementChild incorrect');
assert.equal(before.nextElementSibling, child, 'nextElementSibling incorrect');
assert.equal(child.nextElementSibling, after, 'nextElementSibling incorrect');
assert.equal(after.previousElementSibling, child, 'previousElementSibling incorrect');
assert.equal(child.previousElementSibling, before, 'previousElementSibling incorrect');
});
test('element accessors (distribute)', function() {
var parent = document.createElement('x-project');
var child = document.createElement('div');
parent.appendChild(child);
var before = document.createElement('div');
var after = document.createElement('div');
parent.insertBefore(before, child);
parent.appendChild(after);
assert.equal(parent.firstElementChild, before, 'firstElementChild incorrect');
assert.equal(parent.lastElementChild, after, 'lastElementChild incorrect');
assert.equal(before.nextElementSibling, child, 'nextElementSibling incorrect');
assert.equal(child.nextElementSibling, after, 'nextElementSibling incorrect');
assert.equal(after.previousElementSibling, child, 'previousElementSibling incorrect');
assert.equal(child.previousElementSibling, before, 'previousElementSibling incorrect');
});
test('node accessors (empty logical tree)', function() {
var element = document.createElement('x-simple');
assert.equal(element.parentNode, null, 'parentNode incorrect');
assert.equal(element.firstChild, null, 'firstChild incorrect');
assert.equal(element.lastChild, null, 'lastChild incorrect');
assert.equal(element.nextSibling, null, 'nextSibling incorrect');
assert.equal(element.previousSibling, null, 'previousSibling incorrect');
assert.equal(element.firstElementChild, null, 'firstElementChild incorrect');
assert.equal(element.lastElementChild, null, 'lastElementChild incorrect');
assert.equal(element.nextElementSibling, null, 'nextElementSibling incorrect');
assert.equal(element.previousElementSibling, null, 'previousElementSibling incorrect');
});
test('node accessors (unmanaged logical tree)', function() {
var element = document.createElement('div');
var child1 = document.createElement('div');
var child2 = document.createElement('div');
element.appendChild(child1);
element.appendChild(child2);
assert.equal(element.parentNode, null, 'parentNode incorrect');
assert.equal(element.firstChild, child1, 'firstChild incorrect');
assert.equal(element.lastChild, child2, 'lastChild incorrect');
assert.equal(element.nextSibling, null, 'nextSibling incorrect');
assert.equal(element.previousSibling, null, 'previousSibling incorrect');
assert.equal(element.firstElementChild, child1, 'firstElementChild incorrect');
assert.equal(element.lastElementChild, child2, 'lastElementChild incorrect');
assert.equal(element.nextElementSibling, null, 'nextElementSibling incorrect');
assert.equal(element.previousElementSibling, null, 'previousElementSibling incorrect');
});
test('textContent', function() {
var testElement = document.createElement('x-project');
testElement.textContent = 'Hello World';
assert.equal(testElement.textContent, 'Hello World', 'textContent getter incorrect');
if (checkUnpatchedDom) {
Polymer.flush();
assert.equal(Polymer.TreeApi.Composed.getChildNodes(testElement)[1].textContent, 'Hello World', 'text content setter incorrect');
}
testElement = createEnabledElement('x-commented');
assert.equal(testElement.root.textContent, '[]', 'text content getter with comment incorrect');
var textNode = document.createTextNode('foo');
assert.equal(textNode.textContent, 'foo', 'text content getter on textnode incorrect');
textNode.textContent = 'bar';
assert.equal(textNode.textContent, 'bar', 'text content setter on textnode incorrect');
var commentNode = document.createComment('foo');
assert.equal(commentNode.textContent, 'foo', 'text content getter on commentnode incorrect');
commentNode.textContent = 'bar';
assert.equal(commentNode.textContent, 'bar', 'text content setter on commentnode incorrect');
});
test('innerHTML', function() {
var testElement = document.createElement('x-project');
testElement.innerHTML = '<div>Hello World</div><div>2</div><div>3</div>';
var added = testElement.firstChild;
assert.equal(added.textContent , 'Hello World', 'innerHTML setter incorrect');
assert.equal(testElement.innerHTML , '<div>Hello World</div><div>2</div><div>3</div>', 'innerHTML getter incorrect');
if (checkUnpatchedDom) {
Polymer.flush();
var children = Polymer.TreeApi.Composed.getChildNodes(testElement);
assert.equal(children[1], added, 'innerHTML setter composed incorrectly');
assert.equal(children[2].textContent, '2', 'innerHTML setter composed incorrectly');
assert.equal(children[3].textContent, '3', 'innerHTML setter composed incorrectly');
}
});
test('innerHTML (non-composed)', function() {
var testElement = document.createElement('div');
document.body.appendChild(testElement);
testElement.innerHTML = '<div>Hello World</div><div>2</div><div>3</div>';
var added = testElement.firstChild;
assert.equal(added.textContent , 'Hello World', 'innerHTML setter incorrect');
assert.equal(testElement.innerHTML , '<div>Hello World</div><div>2</div><div>3</div>', 'innerHTML getter incorrect');
assert.equal(testElement.children.length, 3);
});
});
suite('activeElement', function() {
var r;
// light
var r_l;
// shadow
var r_0;
// light
var r_0_l;
// shadow
var r_0_0;
// light
var r_0_0_l;
// shadow
var r_0_0_l_0;
var r_0_1;
// light
var r_0_1_l;
var r_1;
// light
var r_1_l;
// shadow
var r_1_l_0;
// shadow
var r_1_0;
// light
var r_1_0_l;
var r_1_1;
// light
var r_1_1_l;
suiteSetup(function() {
r = document.querySelector('x-shadow-host-root');
r_l = r.querySelector('x-shadow-host-root-light');
r_0 = r.root.querySelector('x-shadow-host-root-0');
r_0_l = r_0.querySelector('x-shadow-host-root-0-light');
r_0_0 = r_0.root.querySelector('x-shadow-host-root-0-0');
r_0_0_l = r_0_0.querySelector('x-shadow-host-root-0-0-light');
r_0_0_l_0 = r_0_0_l.root.querySelector('x-shadow-host-root-0-0-light-0');
r_0_1 = r_0.root.querySelector('x-shadow-host-root-0-1');
r_0_1_l = r_0_1.querySelector('x-shadow-host-root-0-1-light');
r_1 = r.root.querySelector('x-shadow-host-root-1');
r_1_l = r_1.querySelector('x-shadow-host-root-1-light');
r_1_l_0 = r_1_l.root.querySelector('x-shadow-host-root-1-light-0');
r_1_0 = r_1.root.querySelector('x-shadow-host-root-1-0');
r_1_0_l = r_1_0.querySelector('x-shadow-host-root-1-0-light');
r_1_1 = r_1.root.querySelector('x-shadow-host-root-1-1');
r_1_1_l = r_1_1.querySelector('x-shadow-host-root-1-1-light');
});
test('r.focus()', function() {
r.focus();
assert.equal(document._activeElement, r, 'document.activeElement === r');
assert.equal(r.root.activeElement, null, 'r.root.activeElement === null');
assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');
assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');
assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');
assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');
assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');
assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');
});
test('r_l.focus()', function() {
r_l.focus();
assert.equal(document._activeElement, r_l, 'document.activeElement === r_l');
assert.equal(r.root.activeElement, null, 'r.root.activeElement === null');
assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');
assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');
assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');
assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');
assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');
assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');
});
test('r_0.focus()', function() {
r_0.focus();
assert.equal(document._activeElement, r, 'document.activeElement === r');
assert.equal(r.root.activeElement, r_0, 'r.root.activeElement === r_0');
assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');
assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');
assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');
assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');
assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');
assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');
});
test('r_0_l.focus()', function() {
r_0_l.focus();
assert.equal(document._activeElement, r, 'document.activeElement === r');
assert.equal(r.root.activeElement, r_0_l, 'r.root.activeElement === r_0_l');
assert.equal(r_0.root.activeElement, null, 'r_0.root.activeElement === null');
assert.equal(r_1.root.activeElement, null, 'r_1.root.activeElement === null');
assert.equal(r_0_0.root.activeElement, null, 'r_0_0.root.activeElement === null');
assert.equal(r_0_1.root.activeElement, null, 'r_0_1.root.activeElement === null');
assert.equal(r_1_0.root.activeElement, null, 'r_1_0.root.activeElement === null');
assert.equal(r_1_1.root.activeElement, null, 'r_1_1.root.activeElement === null');
});
test('r_0_0.focus()', function() {
r_0_0.focus();
assert.equal(document._activeElement, r, 'document.activeElement === r');
assert.equal(r.root.ac