Adds node mutation apis to Polymer.dom: setAttribute, removeAttribute, classList. These methods automatically provoke distribution if necessary.

Adds redistribution support to `distributeContent`.
This commit is contained in:
Steven Orvell
2015-05-10 10:03:52 -07:00
parent 324272e90c
commit 82dc565b84
9 changed files with 529 additions and 135 deletions

View File

@@ -13,6 +13,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<script>
Polymer.DomApi = (function() {
'use strict';
var Settings = Polymer.Settings;
var getInnerHTML = Polymer.domInnerHTML.getInnerHTML;
@@ -28,6 +29,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
if (this.patch) {
this.patch();
}
this.classList = new DomApi.ClassList(this);
};
DomApi.prototype = {
@@ -365,10 +367,50 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
while (this.childNodes.length) {
this.removeChild(this.childNodes[0]);
}
},
// TODO(sorvell): make Polymer utils use these...
setAttribute: function(name, value) {
this.node.setAttribute(name, value);
this._distributeParent();
},
removeAttribute: function(name) {
this.node.removeAttribute(name);
this._distributeParent();
},
_distributeParent: function() {
if (this.parentNode && this.parentNode.shadyRoot) {
this.parentNode.distributeContent();
}
}
};
DomApi.ClassList = function(host) {
this.domApi = host;
this.node = host.node;
}
DomApi.ClassList.prototype = {
add: function() {
this.node.classList.add.apply(this.node.classList, arguments);
this.domApi._distributeParent();
},
remove: function() {
this.node.classList.remove.apply(this.node.classList, arguments);
this.domApi._distributeParent();
},
toggle: function() {
this.node.classList.toggle.apply(this.node.classList, arguments);
this.domApi._distributeParent();
}
}
// changes and accessors...
if (!Settings.useShadow) {
@@ -517,6 +559,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
return getInnerHTML(this.node, true);
};
} else {
DomApi.prototype.querySelectorAll = function(selector) {
@@ -543,6 +586,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
return n$ ? Array.prototype.slice.call(n$) : [];
};
DomApi.prototype._distributeParent = function() {}
Object.defineProperties(DomApi.prototype, {
childNodes: {

View File

@@ -72,15 +72,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
* Force this element to distribute its children to its local dom.
* A user should call `distributeContent` if distribution has been
* invalidated due to changes to selectors on child elements that
* effect distribution. For example, if an element contains an
* insertion point with <content select=".foo"> and a `foo` class is
* added to a child, then `distributeContent` must be called to update
* effect distribution that were not made via `Polymer.dom`.
* For example, if an element contains an insertion point with
* <content select=".foo"> and a `foo` class is added to a child,
* then `distributeContent` must be called to update
* local dom distribution.
*/
distributeContent: function() {
if (this._useContent) {
this.shadyRoot._distributionClean = false;
this._distributeContent();
if (this.shadyRoot) {
var dom = Polymer.dom(this);
var list = getRedistributingHosts(this);
list.push(this);
for (var i=0; i < list.length; i++) {
dom._lazyDistribute(list[i]);
}
}
},
@@ -151,6 +156,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
if (child._destinationInsertionPoints) {
child._destinationInsertionPoints = undefined;
}
if (isInsertionPoint(child)) {
clearDistributedDestinationInsertionPoints(child);
}
}
// insertion points
var root = this.shadyRoot;
@@ -328,14 +336,21 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
var points = child._destinationInsertionPoints;
if (!points) {
child._destinationInsertionPoints = [insertionPoint];
// TODO(sorvell): _destinationInsertionPoints may not be cleared when
// nodes are dynamically added/removed, therefore test before adding
// insertion points.
} else if (points.indexOf(insertionPoint) < 0) {
} else {
points.push(insertionPoint);
}
}
function clearDistributedDestinationInsertionPoints(insertionPoint) {
var e$ = insertionPoint._distributedNodes;
for (var i=0; i < e$.length; i++) {
var d = e$[i]._destinationInsertionPoints;
if (d) {
d.splice(d.indexOf(insertionPoint)+1, d.length);
}
}
}
function isFinalDestination(insertionPoint, node) {
var points = node._destinationInsertionPoints;
return points && points[points.length - 1] === insertionPoint;
@@ -379,6 +394,35 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
function getComposedParent(node) {
return node.__patched ? node._composedParent : node.parentNode;
}
// return this host's like of redistributing hosts.
function getRedistributingHosts(host) {
var list = [];
while (host && hostNeedsRedistribution(host)) {
host = host.domHost;
// order from top-bottom for efficiency
if (host) {
list.unshift(host);
}
}
return list;
}
// Return true if a host's children includes
// an insertion point that selects selectively
function hostNeedsRedistribution(host) {
var c$ = Polymer.dom(host).children;
for (var i=0, c; i < c$.length; i++) {
c = c$[i];
if (c.localName === 'content') {
var s = c.getAttribute('select');
if (s && s !== '*') {
return true;
}
}
}
}
})();
</script>

View File

@@ -34,9 +34,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
bool = !node.classList.contains(name);
}
if (bool) {
node.classList.add(name);
Polymer.dom(node).classList.add(name);
} else {
node.classList.remove(name);
Polymer.dom(node).classList.remove(name);
}
},
@@ -55,9 +55,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
bool = !node.hasAttribute(name);
}
if (bool) {
node.setAttribute(name, '');
Polymer.dom(node).setAttribute(name, '');
} else {
node.removeAttribute(name);
Polymer.dom(node).removeAttribute(name);
}
},
@@ -71,10 +71,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
*/
classFollows: function(name, toElement, fromElement) {
if (fromElement) {
fromElement.classList.remove(name);
Polymer.dom(fromElement).classList.remove(name);
}
if (toElement) {
toElement.classList.add(name);
Polymer.dom(toElement).classList.add(name);
}
},
@@ -88,10 +88,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
*/
attributeFollows: function(name, toElement, fromElement) {
if (fromElement) {
fromElement.removeAttribute(name);
Polymer.dom(fromElement).removeAttribute(name);
}
if (toElement) {
toElement.setAttribute(name, '');
Polymer.dom(toElement).setAttribute(name, '');
}
},

118
test/smoke/nested-ip.html Normal file
View File

@@ -0,0 +1,118 @@
<!doctype html>
<html>
<head>
<title>polymer</title>
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../../polymer.html">
</head>
<body>
<x-outer></x-outer>
<dom-module id="x-outer">
<template>
<x-inner>
<template is="dom-repeat" items="{{items}}">
<div item>{{item}}</div>
</template>
</x-inner>
</template>
</dom-module>
<dom-module id="x-inner">
<template>
<x-inner-most>
<content class="item" select="[item]"></content>
</x-inner-most>
<content class="notItem" select=":not([item])"></content>
</template>
</dom-module>
<dom-module id="x-inner-most">
<template>
<div style="background-color: green;">
<content class="test" select="[test]"></content>
</div>
<div style="background-color: red;">
<content class="notTest" select=":not([test])"></content>
</div>
<br>
<button on-click="_onTest1a">[test]:not[item]</button>
<button on-click="_onTest2a">:not[test][item]</button>
<button on-click="_onTest1b">auto: [test]:not[item]</button>
<button on-click="_onTest2b">auto: :not[test][item]</button>
</template>
</dom-module>
<script>
(function() {
HTMLImports.whenReady(function() {
Polymer({
is: 'x-outer',
properties: {
items: {
type: Array,
value: ["A", "B", "C"]
}
}
});
Polymer({
is: 'x-inner'
});
var element;
Polymer({
is: 'x-inner-most',
_onTest1a: function() {
this.doTest(function(e) {
e.setAttribute('test', '');
e.removeAttribute('item');
this.distributeContent();
});
},
_onTest1b: function() {
this.doTest(function(e) {
Polymer.dom(e).setAttribute('test', '');
Polymer.dom(e).removeAttribute('item');
});
},
_onTest2a: function() {
this.doTest(function(e) {
e.setAttribute('item', '');
e.removeAttribute('test');
this.distributeContent();
});
},
_onTest2b: function() {
this.doTest(function(e) {
Polymer.dom(e).setAttribute('item', '');
Polymer.dom(e).removeAttribute('test');
});
},
doTest: function(work) {
element = element || document.querySelector("[item]");
console.group('test');
console.log('before', Polymer.dom(element).getDestinationInsertionPoints());
//
work.call(this, element);
Polymer.dom.flush();
//
console.log('after', Polymer.dom(element).getDestinationInsertionPoints());
console.groupEnd('test');
}
});
});
})();
</script>
</body>
</html>

View File

@@ -87,4 +87,35 @@
Polymer({
is: 'x-compose'
});
</script>
</script>
<dom-module id="x-select3">
<template><content select="[s3]"></content></template>
<script>Polymer({is: 'x-select3'});</script>
</dom-module>
<dom-module id="x-select2">
<template><x-select3 id="select"><content select="[s2]"></content></x-select3></template>
<script>Polymer({is: 'x-select2'});</script>
</dom-module>
<dom-module id="x-select1">
<template><x-select2 id="select"><content select="[s1]"></content></x-select2></template>
<script>Polymer({is: 'x-select1'});</script>
</dom-module>
<dom-module id="x-select-class3">
<template><content select=".s3"></content></template>
<script>Polymer({is: 'x-select-class3'});</script>
</dom-module>
<dom-module id="x-select-class2">
<template><x-select-class3 id="select"><content select=".s2"></content></x-select-class3></template>
<script>Polymer({is: 'x-select-class2'});</script>
</dom-module>
<dom-module id="x-select-class1">
<template><x-select-class2 id="select"><content select=".s1"></content></x-select-class2></template>
<script>Polymer({is: 'x-select-class1'});</script>
</dom-module>

View File

@@ -31,6 +31,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<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>
<script src="polymer-dom.js"></script>
</body>

View File

@@ -30,6 +30,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<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>
<script src="polymer-dom.js"></script>
</body>

View File

@@ -1,12 +1,17 @@
suite('Polymer.dom', function() {
var testElement;
suiteSetup(function() {
testElement = document.querySelector('x-test');
})
test('querySelector (local)', function() {
var test = document.querySelector('x-test');
var projected = Polymer.dom(test.root).querySelector('#projected');
var projected = Polymer.dom(testElement.root).querySelector('#projected');
assert.equal(projected.textContent, 'projected');
var p2 = Polymer.dom(test).querySelector('#projected');
var p2 = Polymer.dom(testElement).querySelector('#projected');
assert.notOk(p2);
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
assert.equal(rere.is, 'x-rereproject');
var re = Polymer.dom(rere.root).querySelector('x-reproject');
assert.equal(re.is, 'x-reproject');
@@ -15,8 +20,7 @@ suite('Polymer.dom', function() {
});
test('querySelectorAll (local)', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var re = Polymer.dom(rere.root).querySelector('x-reproject');
var p = Polymer.dom(re.root).querySelector('x-project');
var rereList = Polymer.dom(rere.root).querySelectorAll('*');
@@ -30,9 +34,8 @@ suite('Polymer.dom', function() {
});
test('querySelector (light)', function() {
var test = document.querySelector('x-test');
var projected = Polymer.dom(test.root).querySelector('#projected');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var projected = Polymer.dom(testElement.root).querySelector('#projected');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var re = Polymer.dom(rere.root).querySelector('x-reproject');
var p = Polymer.dom(re.root).querySelector('x-project');
assert.equal(Polymer.dom(rere).querySelector('#projected'), projected);
@@ -41,9 +44,8 @@ suite('Polymer.dom', function() {
});
test('querySelectorAll (light)', function() {
var test = document.querySelector('x-test');
var projected = Polymer.dom(test.root).querySelector('#projected');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var projected = Polymer.dom(testElement.root).querySelector('#projected');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var re = Polymer.dom(rere.root).querySelector('x-reproject');
var p = Polymer.dom(re.root).querySelector('x-project');
assert.equal(Polymer.dom(rere).querySelectorAll('#projected')[0], projected);
@@ -52,10 +54,9 @@ suite('Polymer.dom', function() {
});
test('projection', function() {
var test = document.querySelector('x-test');
var projected = Polymer.dom(test.root).querySelector('#projected');
var projected = Polymer.dom(testElement.root).querySelector('#projected');
assert.equal(projected.textContent, 'projected');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
assert.equal(rere.is, 'x-rereproject');
var re = Polymer.dom(rere.root).querySelector('x-reproject');
assert.equal(re.is, 'x-reproject');
@@ -72,56 +73,196 @@ suite('Polymer.dom', function() {
});
test('distributeContent', function() {
var test = document.querySelector('x-test');
test._distributionClean = false;
test._distributeContent();
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var projected = Polymer.dom(testElement.root).querySelector('#projected');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var c1 = Polymer.dom(rere.root).querySelector('content');
var re = Polymer.dom(rere.root).querySelector('x-reproject');
var c2 = Polymer.dom(re.root).querySelector('content');
var p = Polymer.dom(re.root).querySelector('x-project');
var c3 = Polymer.dom(p.root).querySelector('content');
var ip$ = [c1, c2, c3];
testElement.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(projected).getDestinationInsertionPoints(), ip$);
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
assert.equal(rere.is, 'x-rereproject');
rere._distributionClean = false;
rere._distributeContent();
rere.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(projected).getDestinationInsertionPoints(), ip$);
var re = Polymer.dom(rere.root).querySelector('x-reproject');
assert.equal(re.is, 'x-reproject');
re._distributionClean = false;
re._distributeContent();
re.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(projected).getDestinationInsertionPoints(), ip$);
var p = Polymer.dom(re.root).querySelector('x-project');
assert.equal(p.is, 'x-project');
});
test('distributeContent (reproject)', function() {
var select = document.querySelector('x-select1');
var child = Polymer.dom(select).firstElementChild;
var c1 = Polymer.dom(select.root).querySelector('content');
var c2 = Polymer.dom(select.$.select.root).querySelector('content');
var c3 = Polymer.dom(select.$.select.$.select.root).querySelector('content');
assert.equal(c1.getAttribute('select'), '[s1]');
assert.equal(c2.getAttribute('select'), '[s2]');
assert.equal(c3.getAttribute('select'), '[s3]');
var ip$ = [c1, c2, c3];
assert.equal(child.className, 'select-child');
assert.equal(Polymer.dom(child).getDestinationInsertionPoints().length, 0);
child.setAttribute('s1', '');
select.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1]);
child.setAttribute('s2', '');
select.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2]);
child.setAttribute('s3', '');
select.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2, c3]);
child.removeAttribute('s1');
select.$.select.$.select.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), []);
child.setAttribute('s1', '');
select.$.select.$.select.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2, c3]);
child.removeAttribute('s2');
select.$.select.$.select.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1]);
child.setAttribute('s2', '');
select.$.select.$.select.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2, c3]);
child.removeAttribute('s3');
select.$.select.$.select.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2]);
child.removeAttribute('s2');
child.removeAttribute('s1');
select.distributeContent();
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), []);
});
test('Polymer.dom.setAttribute (reproject)', function() {
var select = document.querySelector('x-select1');
var child = Polymer.dom(select).firstElementChild;
var c1 = Polymer.dom(select.root).querySelector('content');
var c2 = Polymer.dom(select.$.select.root).querySelector('content');
var c3 = Polymer.dom(select.$.select.$.select.root).querySelector('content');
assert.equal(c1.getAttribute('select'), '[s1]');
assert.equal(c2.getAttribute('select'), '[s2]');
assert.equal(c3.getAttribute('select'), '[s3]');
var ip$ = [c1, c2, c3];
assert.equal(child.className, 'select-child');
assert.equal(Polymer.dom(child).getDestinationInsertionPoints().length, 0);
Polymer.dom(child).setAttribute('s1', '');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1]);
Polymer.dom(child).setAttribute('s2', '');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2]);
Polymer.dom(child).setAttribute('s3', '');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2, c3]);
Polymer.dom(child).removeAttribute('s1');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), []);
Polymer.dom(child).setAttribute('s1', '');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2, c3]);
Polymer.dom(child).removeAttribute('s2');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1]);
Polymer.dom(child).setAttribute('s2', '');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2, c3]);
Polymer.dom(child).removeAttribute('s3');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2]);
Polymer.dom(child).removeAttribute('s2');
Polymer.dom(child).removeAttribute('s1');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), []);
});
test('Polymer.dom.classListAdd/Remove/Toggle (reproject)', function() {
var select = document.querySelector('x-select-class1');
var child = Polymer.dom(select).firstElementChild;
var c1 = Polymer.dom(select.root).querySelector('content');
var c2 = Polymer.dom(select.$.select.root).querySelector('content');
var c3 = Polymer.dom(select.$.select.$.select.root).querySelector('content');
assert.equal(c1.getAttribute('select'), '.s1');
assert.equal(c2.getAttribute('select'), '.s2');
assert.equal(c3.getAttribute('select'), '.s3');
var ip$ = [c1, c2, c3];
assert.equal(Polymer.dom(child).getDestinationInsertionPoints().length, 0);
Polymer.dom(child).classList.add('s1');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1]);
Polymer.dom(child).classList.add('s2');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2]);
Polymer.dom(child).classList.add('s3');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2, c3]);
Polymer.dom(child).classList.toggle('s1');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), []);
Polymer.dom(child).classList.toggle('s1');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2, c3]);
Polymer.dom(child).classList.remove('s2');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1]);
Polymer.dom(child).classList.toggle('s2');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2, c3]);
Polymer.dom(child).classList.remove('s3');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), [c1, c2]);
Polymer.dom(child).classList.remove('s2');
Polymer.dom(child).classList.remove('s1');
Polymer.dom.flush();
assert.deepEqual(Polymer.dom(child).getDestinationInsertionPoints(), []);
});
test('appendChild (light)', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var s = document.createElement('span');
s.id = 'added';
s.textContent = 'Added';
Polymer.dom(rere).appendChild(s);
assert.equal(Polymer.dom(test.root).querySelector('#added'), s);
assert.equal(Polymer.dom(testElement.root).querySelector('#added'), s);
});
test('insertBefore (light)', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var ref = Polymer.dom(test.root).querySelector('#added');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var ref = Polymer.dom(testElement.root).querySelector('#added');
var s = document.createElement('span');
s.id = 'added2';
s.textContent = 'Added2';
Polymer.dom(rere).insertBefore(s, ref);
assert.equal(Polymer.dom(test.root).querySelector('#added2'), s);
assert.equal(Polymer.dom(testElement.root).querySelector('#added2'), s);
});
test('removeChild (light)', function() {
var test = document.querySelector('x-test');
var added = Polymer.dom(test.root).querySelector('#added');
var added2 = Polymer.dom(test.root).querySelector('#added2');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
assert.equal(Polymer.dom(test.root).querySelectorAll('*').length, 4);
var added = Polymer.dom(testElement.root).querySelector('#added');
var added2 = Polymer.dom(testElement.root).querySelector('#added2');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
assert.equal(Polymer.dom(testElement.root).querySelectorAll('*').length, 4);
Polymer.dom(rere).removeChild(added);
Polymer.dom(rere).removeChild(added2);
assert.equal(Polymer.dom(test.root).querySelectorAll('*').length, 2);
assert.equal(Polymer.dom(testElement.root).querySelectorAll('*').length, 2);
});
test('appendChild (local)', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var s = document.createElement('span');
s.id = 'local';
s.textContent = 'Local';
@@ -130,9 +271,8 @@ suite('Polymer.dom', function() {
});
test('insertBefore (local)', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var ref = Polymer.dom(test.root).querySelector('#local');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var ref = Polymer.dom(testElement.root).querySelector('#local');
var s = document.createElement('span');
s.id = 'local2';
s.textContent = 'Local2';
@@ -141,8 +281,7 @@ suite('Polymer.dom', function() {
});
test('removeChild (local)', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var local = Polymer.dom(rere.root).querySelector('#local');
var local2 = Polymer.dom(rere.root).querySelector('#local2');
Polymer.dom(rere.root).removeChild(local);
@@ -151,23 +290,21 @@ suite('Polymer.dom', function() {
});
test('localDom.insertBefore first element results in minimal change', function() {
var test = document.querySelector('x-test');
var children = Polymer.dom(test.root).childNodes;
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var children = Polymer.dom(testElement.root).childNodes;
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
assert.equal(rere.attachedCount, 1);
var s = document.createElement('span');
s.id = 'local-first';
s.textContent = 'Local First';
Polymer.dom(test.root).insertBefore(s, children[0]);
assert.equal(Polymer.dom(test.root).querySelector('#local-first'), s);
Polymer.dom(testElement.root).insertBefore(s, children[0]);
assert.equal(Polymer.dom(testElement.root).querySelector('#local-first'), s);
assert.equal(rere.attachedCount, 1);
Polymer.dom(test.root).removeChild(s);
Polymer.dom(testElement.root).removeChild(s);
assert.equal(rere.attachedCount, 1);
});
test('appendChild (fragment, local)', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var fragment = document.createDocumentFragment();
var childCount = 5;
for (var i=0; i < childCount; i++) {
@@ -185,8 +322,7 @@ suite('Polymer.dom', function() {
});
test('insertBefore (fragment, local)', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var fragment = document.createDocumentFragment();
var childCount = 5;
for (var i=0; i < childCount; i++) {
@@ -208,8 +344,7 @@ suite('Polymer.dom', function() {
});
test('distribute (forced)', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var re = Polymer.dom(rere.root).querySelector('x-reproject');
var p = Polymer.dom(re.root).querySelector('x-project');
var s = document.createElement('span');
@@ -221,7 +356,7 @@ suite('Polymer.dom', function() {
if (rere.shadyRoot) {
assert.notEqual(s._composedParent, rere);
}
Polymer.dom(test).flush();
Polymer.dom(testElement).flush();
if (rere.shadyRoot) {
assert.equal(s._composedParent, p);
}
@@ -229,18 +364,17 @@ suite('Polymer.dom', function() {
if (rere.shadyRoot) {
assert.equal(s._composedParent, p);
}
Polymer.dom(test).flush();
Polymer.dom(testElement).flush();
if (rere.shadyRoot) {
assert.equal(s._composedParent, null);
}
});
test('queryDistributedElements', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var re = Polymer.dom(rere.root).querySelector('x-reproject');
var p = Polymer.dom(re.root).querySelector('x-project');
var projected = Polymer.dom(test.root).querySelector('#projected');
var projected = Polymer.dom(testElement.root).querySelector('#projected');
var d$ = Polymer.dom(p.root).queryDistributedElements('*');
assert.equal(d$.length, 1);
assert.equal(d$[0], projected);
@@ -251,21 +385,20 @@ suite('Polymer.dom', function() {
var test = Polymer.dom().querySelector('x-test');
var rere = Polymer.dom().querySelector('x-rereproject');
var projected = Polymer.dom().querySelector('#projected');
assert.ok(test);
assert.ok(testElement);
assert.notOk(rere);
assert.notOk(projected);
});
test('Polymer.dom event', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var re = Polymer.dom(rere.root).querySelector('x-reproject');
var p = Polymer.dom(re.root).querySelector('x-project');
var eventHandled = 0;
test.addEventListener('test-event', function(e) {
testElement.addEventListener('test-event', function(e) {
eventHandled++;
assert.equal(Polymer.dom(e).rootTarget, p);
assert.equal(Polymer.dom(e).localTarget, test);
assert.equal(Polymer.dom(e).localTarget, testElement);
var path = Polymer.dom(e).path;
// path includes window only on more recent Shadow DOM implementations
// account for that here.
@@ -273,7 +406,7 @@ suite('Polymer.dom', function() {
assert.equal(path[0], p);
assert.equal(path[2], re);
assert.equal(path[4], rere);
assert.equal(path[6], test);
assert.equal(path[6], testElement);
});
rere.addEventListener('test-event', function(e) {
@@ -286,10 +419,9 @@ suite('Polymer.dom', function() {
});
test('parentNode', function() {
var test = document.querySelector('x-test');
var rere = Polymer.dom(test.root).querySelector('x-rereproject');
var projected = Polymer.dom(test.root).querySelector('#projected');
assert.equal(Polymer.dom(test).parentNode, wrap(document.body));
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
var projected = Polymer.dom(testElement.root).querySelector('#projected');
assert.equal(Polymer.dom(testElement).parentNode, wrap(document.body));
assert.equal(Polymer.dom(projected).parentNode, rere);
});
@@ -370,24 +502,24 @@ suite('Polymer.dom accessors', function() {
});
test('Polymer.dom textContent', function() {
var test = document.createElement('x-project');
Polymer.dom(test).textContent = 'Hello World';
assert.equal(Polymer.dom(test).textContent, 'Hello World', 'textContent getter incorrect');
if (test.shadyRoot) {
var testElement = document.createElement('x-project');
Polymer.dom(testElement).textContent = 'Hello World';
assert.equal(Polymer.dom(testElement).textContent, 'Hello World', 'textContent getter incorrect');
if (testElement.shadyRoot) {
Polymer.dom.flush();
assert.equal(test._composedChildren[1].textContent, 'Hello World', 'text content setter incorrect');
assert.equal(testElement._composedChildren[1].textContent, 'Hello World', 'text content setter incorrect');
}
});
test('Polymer.dom innerHTML', function() {
var test = document.createElement('x-project');
Polymer.dom(test).innerHTML = '<div>Hello World</div>';
var added = Polymer.dom(test).firstChild;
var testElement = document.createElement('x-project');
Polymer.dom(testElement).innerHTML = '<div>Hello World</div>';
var added = Polymer.dom(testElement).firstChild;
assert(added.textContent , 'Hello World', 'innerHTML setter incorrect');
assert(Polymer.dom(test).innerHTML , '<div>Hello World</div>', 'innerHTML getter incorrect');
if (test.shadyRoot) {
assert(Polymer.dom(testElement).innerHTML , '<div>Hello World</div>', 'innerHTML getter incorrect');
if (testElement.shadyRoot) {
Polymer.dom.flush();
assert.equal(test._composedChildren[1], added, 'innerHTML setter composed incorrectly');
assert.equal(testElement._composedChildren[1], added, 'innerHTML setter composed incorrectly');
}
});
});
@@ -455,14 +587,17 @@ suite('Polymer.dom non-distributed elements', function() {
// set / unset `test` attr and see if it distributes properly
child.setAttribute('test', '');
d.distributeContent();
Polymer.dom.flush();
testWithAttr();
//
child.removeAttribute('test');
d.distributeContent();
Polymer.dom.flush();
testNoAttr();
//
child.setAttribute('test', '');
d.distributeContent();
Polymer.dom.flush();
testWithAttr();
});

View File

@@ -49,7 +49,7 @@ function testRender(descr, hostInnerHtml, shadowRootHtml, expectedHtml) {
// Pretend we're stamping the template contents.
setRootInnerHTML(host.shadyRoot, shadowRootHtml);
// Invoke distribution and verify the resulting tree.
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), expectedHtml);
});
}
@@ -128,10 +128,10 @@ test('Reproject', function() {
function testRender() {
// Simulate the correct ordering as "ready" would fire.
host.distributeContent();
distributeContentNow(host);
// NOTE: needed only for this imperative test that needs
// to simulate distribution from `shadyRoot`
p.distributeContent();
distributeContentNow(p);
assert.strictEqual(getComposedHTML(host),
'<x-content-test id="p">a: <a></a>b: <b></b></x-content-test>');
@@ -147,7 +147,7 @@ test('Reproject', function() {
}
testRender();
//testRender();
testRender();
});
@@ -158,15 +158,15 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content>fallback</content>');
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
host.firstChild.textContent = '';
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a></a>');
host.lightChildren = [];
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), 'fallback');
});
@@ -177,15 +177,15 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content><b>after</b>');
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b>after</b>');
host.shadyRoot.lightChildren[1].textContent = '';
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');
host.shadyRoot.lightChildren = [];
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '');
});
@@ -196,19 +196,19 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content select="xxx"><b>fallback</b></content>');
var b = host.shadyRoot.firstChild.firstChild;
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<b>fallback</b>');
b.textContent = '';
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<b></b>');
host.shadyRoot.firstChild.lightChildren = [];
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '');
host.shadyRoot.lightChildren = [];
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '');
});
@@ -218,15 +218,15 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content>fallback</content>');
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
host.firstChild.removeChild(host.firstChild.firstChild);
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a></a>');
host.lightChildren = [];
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), 'fallback');
});
@@ -238,7 +238,7 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content>fallback</content>');
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a></a><b></b>');
Polymer.dom(host).removeChild(b);
@@ -258,19 +258,19 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content><b>after</b>');
var b = host.shadyRoot.lastChild;
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b>after</b>');
b.removeChild(b.firstChild);
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');
host.shadyRoot.lightChildren.splice(1, 1); // remove b
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
host.shadyRoot.lightChildren = []; // remove a
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '');
});
@@ -282,15 +282,15 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content select="b">fallback b</content>' +
'<content select="a">fallback a</content>');
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<b>World</b><a>Hello</a>');
host.shadyRoot.firstChild.setAttribute('select', 'xxx');
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), 'fallback b<a>Hello</a>');
host.shadyRoot.firstChild.setAttribute('select', '');
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b>World</b>fallback a');
});
@@ -300,7 +300,7 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
@@ -315,13 +315,13 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
Polymer.dom(host.shadyRoot).appendChild(b);
Polymer.dom.flush();
//host.distributeContent();
//distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');
});
@@ -332,7 +332,7 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
@@ -348,7 +348,7 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
var content = host.shadyRoot.firstChild;
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
@@ -364,12 +364,12 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
host.lightChildren[0] = b;
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<b></b>');
});
@@ -380,7 +380,7 @@ suite('Mutate light DOM', function() {
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
var content = host.shadyRoot.firstChild;
host.distributeContent();
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
@@ -404,7 +404,7 @@ suite('Mutate light DOM', function() {
syncLightDOM(child);
setRootInnerHTML(child.shadyRoot, '<content></content><span id="sub"></span>');
var childLocalSub = child.shadyRoot.lastChild;
host.distributeContent();
distributeContentNow(host);
// NOTE: needed only for this imperative test that needs
// to simulate distribution from `shadyRoot`
child._distributeContent();
@@ -428,7 +428,7 @@ suite('Mutate light DOM', function() {
var childLightSub = getComposedChildAtIndex(child, 100) ;
syncLightDOM(child);
setRootInnerHTML(child.shadyRoot, '<content></content><span id="sub"></span>');
host.distributeContent();
distributeContentNow(host);
assert.deepEqual(Polymer.dom(host).querySelectorAll('div#main'), [hostLightMain]);
assert.deepEqual(Polymer.dom(host).querySelectorAll('#sub'), []);
assert.deepEqual(Polymer.dom(child).querySelectorAll('div#sub'), [childLightSub]);
@@ -496,6 +496,11 @@ function assertArrayEqual(a, b, msg) {
}
}
function distributeContentNow(node) {
node.distributeContent();
Polymer.dom.flush();
}
</script>
</body>
</html>