mirror of
https://github.com/Polymer/polymer.git
synced 2026-08-19 01:14:44 -05:00
Fixes #3920: adds Polymer.dom(element).observeNodes replacement.
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
<!--
|
||||
@license
|
||||
Copyright (c) 2016 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
|
||||
-->
|
||||
<link rel="import" href="boot.html">
|
||||
<script>
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
function newSplice(index, removed, addedCount) {
|
||||
return {
|
||||
index: index,
|
||||
removed: removed,
|
||||
addedCount: addedCount
|
||||
};
|
||||
}
|
||||
|
||||
const EDIT_LEAVE = 0;
|
||||
const EDIT_UPDATE = 1;
|
||||
const EDIT_ADD = 2;
|
||||
const EDIT_DELETE = 3;
|
||||
|
||||
let ArraySplice = {
|
||||
|
||||
// Note: This function is *based* on the computation of the Levenshtein
|
||||
// "edit" distance. The one change is that "updates" are treated as two
|
||||
// edits - not one. With Array splices, an update is really a delete
|
||||
// followed by an add. By retaining this, we optimize for "keeping" the
|
||||
// maximum array items in the original array. For example:
|
||||
//
|
||||
// 'xxxx123' -> '123yyyy'
|
||||
//
|
||||
// With 1-edit updates, the shortest path would be just to update all seven
|
||||
// characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
|
||||
// leaves the substring '123' intact.
|
||||
calcEditDistances(current, currentStart, currentEnd,
|
||||
old, oldStart, oldEnd) {
|
||||
// "Deletion" columns
|
||||
let rowCount = oldEnd - oldStart + 1;
|
||||
let columnCount = currentEnd - currentStart + 1;
|
||||
let distances = new Array(rowCount);
|
||||
|
||||
// "Addition" rows. Initialize null column.
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
distances[i] = new Array(columnCount);
|
||||
distances[i][0] = i;
|
||||
}
|
||||
|
||||
// Initialize null row
|
||||
for (let j = 0; j < columnCount; j++)
|
||||
distances[0][j] = j;
|
||||
|
||||
for (let i = 1; i < rowCount; i++) {
|
||||
for (let j = 1; j < columnCount; j++) {
|
||||
if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
|
||||
distances[i][j] = distances[i - 1][j - 1];
|
||||
else {
|
||||
let north = distances[i - 1][j] + 1;
|
||||
let west = distances[i][j - 1] + 1;
|
||||
distances[i][j] = north < west ? north : west;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distances;
|
||||
},
|
||||
|
||||
// This starts at the final weight, and walks "backward" by finding
|
||||
// the minimum previous weight recursively until the origin of the weight
|
||||
// matrix.
|
||||
spliceOperationsFromEditDistances(distances) {
|
||||
let i = distances.length - 1;
|
||||
let j = distances[0].length - 1;
|
||||
let current = distances[i][j];
|
||||
let edits = [];
|
||||
while (i > 0 || j > 0) {
|
||||
if (i == 0) {
|
||||
edits.push(EDIT_ADD);
|
||||
j--;
|
||||
continue;
|
||||
}
|
||||
if (j == 0) {
|
||||
edits.push(EDIT_DELETE);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
let northWest = distances[i - 1][j - 1];
|
||||
let west = distances[i - 1][j];
|
||||
let north = distances[i][j - 1];
|
||||
|
||||
let min;
|
||||
if (west < north)
|
||||
min = west < northWest ? west : northWest;
|
||||
else
|
||||
min = north < northWest ? north : northWest;
|
||||
|
||||
if (min == northWest) {
|
||||
if (northWest == current) {
|
||||
edits.push(EDIT_LEAVE);
|
||||
} else {
|
||||
edits.push(EDIT_UPDATE);
|
||||
current = northWest;
|
||||
}
|
||||
i--;
|
||||
j--;
|
||||
} else if (min == west) {
|
||||
edits.push(EDIT_DELETE);
|
||||
i--;
|
||||
current = west;
|
||||
} else {
|
||||
edits.push(EDIT_ADD);
|
||||
j--;
|
||||
current = north;
|
||||
}
|
||||
}
|
||||
|
||||
edits.reverse();
|
||||
return edits;
|
||||
},
|
||||
|
||||
/**
|
||||
* Splice Projection functions:
|
||||
*
|
||||
* A splice map is a representation of how a previous array of items
|
||||
* was transformed into a new array of items. Conceptually it is a list of
|
||||
* tuples of
|
||||
*
|
||||
* <index, removed, addedCount>
|
||||
*
|
||||
* which are kept in ascending index order of. The tuple represents that at
|
||||
* the |index|, |removed| sequence of items were removed, and counting forward
|
||||
* from |index|, |addedCount| items were added.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Lacking individual splice mutation information, the minimal set of
|
||||
* splices can be synthesized given the previous state and final state of an
|
||||
* array. The basic approach is to calculate the edit distance matrix and
|
||||
* choose the shortest path through it.
|
||||
*
|
||||
* Complexity: O(l * p)
|
||||
* l: The length of the current array
|
||||
* p: The length of the old array
|
||||
*/
|
||||
calcSplices(current, currentStart, currentEnd,
|
||||
old, oldStart, oldEnd) {
|
||||
let prefixCount = 0;
|
||||
let suffixCount = 0;
|
||||
let splice;
|
||||
|
||||
let minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
|
||||
if (currentStart == 0 && oldStart == 0)
|
||||
prefixCount = this.sharedPrefix(current, old, minLength);
|
||||
|
||||
if (currentEnd == current.length && oldEnd == old.length)
|
||||
suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
|
||||
|
||||
currentStart += prefixCount;
|
||||
oldStart += prefixCount;
|
||||
currentEnd -= suffixCount;
|
||||
oldEnd -= suffixCount;
|
||||
|
||||
if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
|
||||
return [];
|
||||
|
||||
if (currentStart == currentEnd) {
|
||||
splice = newSplice(currentStart, [], 0);
|
||||
while (oldStart < oldEnd)
|
||||
splice.removed.push(old[oldStart++]);
|
||||
|
||||
return [ splice ];
|
||||
} else if (oldStart == oldEnd)
|
||||
return [ newSplice(currentStart, [], currentEnd - currentStart) ];
|
||||
|
||||
let ops = this.spliceOperationsFromEditDistances(
|
||||
this.calcEditDistances(current, currentStart, currentEnd,
|
||||
old, oldStart, oldEnd));
|
||||
|
||||
splice = undefined;
|
||||
let splices = [];
|
||||
let index = currentStart;
|
||||
let oldIndex = oldStart;
|
||||
for (let i = 0; i < ops.length; i++) {
|
||||
switch(ops[i]) {
|
||||
case EDIT_LEAVE:
|
||||
if (splice) {
|
||||
splices.push(splice);
|
||||
splice = undefined;
|
||||
}
|
||||
|
||||
index++;
|
||||
oldIndex++;
|
||||
break;
|
||||
case EDIT_UPDATE:
|
||||
if (!splice)
|
||||
splice = newSplice(index, [], 0);
|
||||
|
||||
splice.addedCount++;
|
||||
index++;
|
||||
|
||||
splice.removed.push(old[oldIndex]);
|
||||
oldIndex++;
|
||||
break;
|
||||
case EDIT_ADD:
|
||||
if (!splice)
|
||||
splice = newSplice(index, [], 0);
|
||||
|
||||
splice.addedCount++;
|
||||
index++;
|
||||
break;
|
||||
case EDIT_DELETE:
|
||||
if (!splice)
|
||||
splice = newSplice(index, [], 0);
|
||||
|
||||
splice.removed.push(old[oldIndex]);
|
||||
oldIndex++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (splice) {
|
||||
splices.push(splice);
|
||||
}
|
||||
return splices;
|
||||
},
|
||||
|
||||
sharedPrefix(current, old, searchLength) {
|
||||
for (let i = 0; i < searchLength; i++)
|
||||
if (!this.equals(current[i], old[i]))
|
||||
return i;
|
||||
return searchLength;
|
||||
},
|
||||
|
||||
sharedSuffix(current, old, searchLength) {
|
||||
let index1 = current.length;
|
||||
let index2 = old.length;
|
||||
let count = 0;
|
||||
while (count < searchLength && this.equals(current[--index1], old[--index2]))
|
||||
count++;
|
||||
|
||||
return count;
|
||||
},
|
||||
|
||||
calculateSplices(current, previous) {
|
||||
return this.calcSplices(current, 0, current.length, previous, 0,
|
||||
previous.length);
|
||||
},
|
||||
|
||||
equals(currentValue, previousValue) {
|
||||
return currentValue === previousValue;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Polymer.calculateSplices = (current, previous) => {
|
||||
return ArraySplice.calculateSplices(current, previous);
|
||||
}
|
||||
|
||||
})();
|
||||
</script>
|
||||
+151
-2
@@ -7,9 +7,153 @@ The complete set of contributors may be found at http://polymer.github.io/CONTRI
|
||||
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
|
||||
-->
|
||||
<link rel="import" href="boot.html">
|
||||
<link rel="import" href="array-splice.html">
|
||||
<script>
|
||||
(function() {
|
||||
|
||||
class DistributedNodesObserver {
|
||||
|
||||
static get observers() {
|
||||
if (!this._observers) {
|
||||
this._observers = new Set;
|
||||
}
|
||||
return this._observers;
|
||||
}
|
||||
|
||||
static flush() {
|
||||
for (let observer of this._observers) {
|
||||
observer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
constructor(target, callback) {
|
||||
this.target = target;
|
||||
this.callback = callback;
|
||||
this.effectiveNodes = [];
|
||||
this.observer = null;
|
||||
this.scheduled = false;
|
||||
this._boundSchedule = () => {
|
||||
this.schedule();
|
||||
}
|
||||
this.connect();
|
||||
this.schedule();
|
||||
}
|
||||
|
||||
connect() {
|
||||
if (this.isSlot(this.target)) {
|
||||
this.observeSlots([this.target]);
|
||||
} else {
|
||||
this.observeSlots(this.target.children);
|
||||
if (window.ShadyDOM) {
|
||||
ShadyDOM.observeChildren(this.target, this._boundSchedule);
|
||||
} else {
|
||||
this.observer = new MutationObserver(this._boundSchedule);
|
||||
this.observer.observe(this.target, {childList: true});
|
||||
}
|
||||
}
|
||||
this.connected = true;
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.isSlot(this.target)) {
|
||||
this.observeSlots([this.target]);
|
||||
} else {
|
||||
this.unobserveSlots(this.target.children);
|
||||
if (window.ShadyDOM) {
|
||||
ShadyDOM.unobserveChildren(this.target);
|
||||
} else {
|
||||
this.observer.disconnect();
|
||||
this.observer = null;
|
||||
}
|
||||
}
|
||||
this.connected = false;
|
||||
}
|
||||
|
||||
isSlot(node) {
|
||||
return (node.nodeType === Node.ELEMENT_NODE && node.localName === 'slot');
|
||||
}
|
||||
|
||||
slotsFromNodeList(nodeList) {
|
||||
return Array.from(nodeList).filter(this.isSlot);
|
||||
}
|
||||
|
||||
getEffectiveNodes(target) {
|
||||
if (this.isSlot(target)) {
|
||||
return target.assignedNodes({flatten: true});
|
||||
} else {
|
||||
return Array.from(target.childNodes)
|
||||
.map(node => {
|
||||
if (this.isSlot(node)) {
|
||||
return node.assignedNodes({flatten: true});
|
||||
} else {
|
||||
return [node];
|
||||
}
|
||||
})
|
||||
.reduce((a, b) => a.concat(b), []);
|
||||
}
|
||||
}
|
||||
|
||||
schedule() {
|
||||
if (!this.scheduled) {
|
||||
this.scheduled = true;
|
||||
Promise.resolve().then(() => {
|
||||
this.flush();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
flush() {
|
||||
if (!this.connected) {
|
||||
return;
|
||||
}
|
||||
Polymer.dom.flush();
|
||||
if (this.observer) {
|
||||
this.observer.takeRecords();
|
||||
}
|
||||
this.scheduled = false;
|
||||
let info = {
|
||||
target: this.target,
|
||||
addedNodes: [],
|
||||
removedNodes: []
|
||||
};
|
||||
let newNodes = this.getEffectiveNodes(this.target);
|
||||
let splices = Polymer.calculateSplices(newNodes, this.effectiveNodes);
|
||||
// process removals
|
||||
for (var i=0, s; (i<splices.length) && (s=splices[i]); i++) {
|
||||
for (var j=0, n; (j < s.removed.length) && (n=s.removed[j]); j++) {
|
||||
info.removedNodes.push(n);
|
||||
}
|
||||
}
|
||||
// process adds
|
||||
for (i=0, s; (i<splices.length) && (s=splices[i]); i++) {
|
||||
for (j=s.index; j < s.index + s.addedCount; j++) {
|
||||
info.addedNodes.push(newNodes[j]);
|
||||
}
|
||||
}
|
||||
// update cache
|
||||
this.effectiveNodes = newNodes;
|
||||
if (info.addedNodes.length || info.removedNodes.length) {
|
||||
this.callback(info);
|
||||
}
|
||||
}
|
||||
|
||||
observeSlots(nodeList) {
|
||||
let slots = this.slotsFromNodeList(nodeList);
|
||||
for (let i=0; i < slots.length; i++) {
|
||||
slots[i].addEventListener('slotchange', this._boundSchedule);
|
||||
}
|
||||
}
|
||||
|
||||
unobserveSlots(nodeList) {
|
||||
let slots = this.slotsFromNodeList(nodeList);
|
||||
for (let i=0; i < slots.length; i++) {
|
||||
slots[i].removeEventListener('slotchange', this._boundSchedule);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO(sorvell): figure out Polymer.dom compat...
|
||||
function decorateElement(e) {
|
||||
if (e.__polymerDecorated) {
|
||||
@@ -17,9 +161,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
}
|
||||
e.__polymerDecorated = true;
|
||||
|
||||
e.observeNodes = function() {};
|
||||
e.observeNodes = function(callback) {
|
||||
Polymer.dom.flush();
|
||||
return new DistributedNodesObserver(e, callback);
|
||||
};
|
||||
|
||||
e.unobserveNodes = function() {};
|
||||
e.unobserveNodes = function(observerHandle) {
|
||||
observerHandle.disconnect();
|
||||
};
|
||||
|
||||
e.deepContains = function(node) {
|
||||
if (this.contains(node)) {
|
||||
|
||||
@@ -0,0 +1,933 @@
|
||||
<!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">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<dom-module id='test-static'>
|
||||
<template>
|
||||
<div>static</div>
|
||||
</template>
|
||||
<script>
|
||||
HTMLImports.whenReady(function() {
|
||||
Polymer({
|
||||
is:'test-static'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id='test-slot'>
|
||||
<template>
|
||||
<span id="slotContainer">[<slot id="slot"></slot>]</span>
|
||||
</template>
|
||||
<script>
|
||||
HTMLImports.whenReady(function() {
|
||||
Polymer({
|
||||
is:'test-slot'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id='test-slot1'>
|
||||
<template>
|
||||
<test-slot id="slot"><slot></slot></test-slot>
|
||||
</template>
|
||||
<script>
|
||||
HTMLImports.whenReady(function() {
|
||||
Polymer({
|
||||
is:'test-slot1'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id='test-slot2'>
|
||||
<template>
|
||||
<test-slot1 id="slot"><slot></slot></test-slot1>
|
||||
</template>
|
||||
<script>
|
||||
HTMLImports.whenReady(function() {
|
||||
Polymer({
|
||||
is:'test-slot2'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id='test-slot3'>
|
||||
<template>
|
||||
<test-slot2 id="slot"><slot></slot></test-slot2>
|
||||
</template>
|
||||
<script>
|
||||
HTMLImports.whenReady(function() {
|
||||
Polymer({
|
||||
is:'test-slot3'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id='test-slot-raw'>
|
||||
<template>
|
||||
<div id="slot"><slot></slot></div>
|
||||
</template>
|
||||
<script>
|
||||
HTMLImports.whenReady(function() {
|
||||
Polymer({
|
||||
is:'test-slot-raw'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id='test-slot-attr'>
|
||||
<template>
|
||||
[<slot id="slot" name="d"></slot>]
|
||||
</template>
|
||||
<script>
|
||||
HTMLImports.whenReady(function() {
|
||||
Polymer({
|
||||
is:'test-slot-attr'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id='test-slot-attr1'>
|
||||
<template>
|
||||
<test-slot-attr id="slot"><slot name="c" slot="d"></slot></test-slot-attr>
|
||||
</template>
|
||||
<script>
|
||||
HTMLImports.whenReady(function() {
|
||||
Polymer({
|
||||
is:'test-slot-attr1'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id='test-slot-attr2'>
|
||||
<template>
|
||||
<test-slot-attr1 id="slot"><slot name="b" slot="c"></slot></test-slot-attr1>
|
||||
</template>
|
||||
<script>
|
||||
HTMLImports.whenReady(function() {
|
||||
Polymer({
|
||||
is:'test-slot-attr2'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id='test-slot-attr3'>
|
||||
<template>
|
||||
<test-slot-attr2 id="slot"><slot name="a" slot="b"></slot></test-slot-attr2>
|
||||
</template>
|
||||
<script>
|
||||
HTMLImports.whenReady(function() {
|
||||
Polymer({
|
||||
is:'test-slot-attr3'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id='test-slot-attr-inside'>
|
||||
<template>
|
||||
<test-slot-attr3 id="slot"><slot name="a" slot="a"></slot></test-slot-attr3>
|
||||
</template>
|
||||
<script>
|
||||
HTMLImports.whenReady(function() {
|
||||
Polymer({
|
||||
is:'test-slot-attr-inside'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
|
||||
<test-slot><div>A</div><div>B</div></test-slot>
|
||||
|
||||
<test-static><div>static A</div><div>static B</div></test-static>
|
||||
|
||||
<div id="staticDiv"></div>
|
||||
|
||||
<script>
|
||||
|
||||
suite('observeNodes', function() {
|
||||
|
||||
test('observe intial state of distributing element', function() {
|
||||
var recordedA;
|
||||
var el = document.querySelector('test-slot');
|
||||
var observer1 = Polymer.dom(el).observeNodes(function(info) {
|
||||
recordedA = info;
|
||||
});
|
||||
observer1.flush();
|
||||
assert.equal(recordedA.addedNodes.length, 2);
|
||||
recordedA = null;
|
||||
var recordedB;
|
||||
var observer2 = Polymer.dom(el).observeNodes(function(info) {
|
||||
recordedB = info;
|
||||
});
|
||||
observer2.flush();
|
||||
assert.equal(recordedA, null);
|
||||
assert.equal(recordedB.addedNodes.length, 2);
|
||||
Polymer.dom(el).unobserveNodes(observer1);
|
||||
Polymer.dom(el).unobserveNodes(observer2);
|
||||
});
|
||||
|
||||
test('observe intial state of non-distributing element', function() {
|
||||
var recordedA;
|
||||
var el = document.querySelector('test-static');
|
||||
var observer1 = Polymer.dom(el).observeNodes(function(info) {
|
||||
recordedA = info;
|
||||
});
|
||||
observer1.flush();
|
||||
assert.equal(recordedA.addedNodes.length, 2);
|
||||
recordedA = null;
|
||||
var recordedB;
|
||||
var observer2 = Polymer.dom(el).observeNodes(function(info) {
|
||||
recordedB = info;
|
||||
});
|
||||
observer2.flush();
|
||||
assert.equal(recordedA, null);
|
||||
assert.equal(recordedB.addedNodes.length, 2);
|
||||
Polymer.dom(el).unobserveNodes(observer1);
|
||||
Polymer.dom(el).unobserveNodes(observer2);
|
||||
});
|
||||
|
||||
test('observe children changes to distributing element', function() {
|
||||
var el = document.createElement('test-slot');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var recorded;
|
||||
var observer = Polymer.dom(el).observeNodes(function(info) {
|
||||
recorded = info;
|
||||
});
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes.length, 0);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// remove
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 0);
|
||||
assert.equal(recorded.removedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes[0], d);
|
||||
assert.equal(recorded.removedNodes[1], d1);
|
||||
// add
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// reset, unobserve and remove
|
||||
recorded = null;
|
||||
Polymer.dom(el).unobserveNodes(observer);
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded, null);
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
|
||||
test('observe children changes to distributing element that provoke additional changes', function() {
|
||||
var el = document.createElement('test-slot');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var recordedInfo, elAddedInObserver;
|
||||
var observerCallCount = 0;
|
||||
var observer = Polymer.dom(el).observeNodes(function(info) {
|
||||
observerCallCount++;
|
||||
recordedInfo = info;
|
||||
if (Polymer.dom(info.target).childNodes.length < 5) {
|
||||
elAddedInObserver = document.createElement('div');
|
||||
Polymer.dom(info.target).appendChild(elAddedInObserver);
|
||||
// TODO(sorvell): support re-entrant flush?
|
||||
observer.flush();
|
||||
}
|
||||
|
||||
});
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
observer.flush();
|
||||
assert.equal(observerCallCount, 5);
|
||||
assert.equal(recordedInfo.addedNodes.length, 1);
|
||||
assert.equal(recordedInfo.addedNodes[0], elAddedInObserver);
|
||||
assert.equal(Polymer.dom(el).childNodes.length, 5);
|
||||
document.body.removeChild(el);
|
||||
Polymer.dom(el).unobserveNodes(observer);
|
||||
});
|
||||
|
||||
test('observe children changes to distributing element (async)', function(done) {
|
||||
var el = document.createElement('test-slot');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var nodes = [];
|
||||
var handle = Polymer.dom(el).observeNodes(function(info) {
|
||||
for (var i=0, at; i < info.removedNodes.length; i++) {
|
||||
at = nodes.indexOf(info.removedNodes[i]);
|
||||
assert.isAbove(at, -1);
|
||||
nodes.splice(at, 1);
|
||||
}
|
||||
nodes = nodes.concat(info.addedNodes);
|
||||
});
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
setTimeout(function() {
|
||||
assert.sameMembers(el.getEffectiveChildNodes(), nodes);
|
||||
// remove
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
setTimeout(function() {
|
||||
assert.sameMembers(el.getEffectiveChildNodes(), nodes);
|
||||
// add
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
setTimeout(function() {
|
||||
assert.sameMembers(el.getEffectiveChildNodes(), nodes);
|
||||
Polymer.dom(el).unobserveNodes(handle);
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
setTimeout(function() {
|
||||
assert.notEqual(nodes.length, el.getEffectiveChildNodes().length);
|
||||
document.body.removeChild(el);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('observe children changes to non-distributing element', function() {
|
||||
var el = document.createElement('test-static');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var recorded;
|
||||
var observer = Polymer.dom(el).observeNodes(function(info) {
|
||||
recorded = info;
|
||||
});
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes.length, 0);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// remove
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 0);
|
||||
assert.equal(recorded.removedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes[0], d);
|
||||
assert.equal(recorded.removedNodes[1], d1);
|
||||
// add
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// reset, unobserve and remove
|
||||
recorded = null;
|
||||
Polymer.dom(el).unobserveNodes(observer);
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded, null);
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
|
||||
test('observe changes to inner node wrapping <slot>', function() {
|
||||
var el = document.createElement('test-slot');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var observedInfo;
|
||||
var observer = Polymer.dom(el.$.slotContainer).observeNodes(function(info) {
|
||||
observedInfo = info;
|
||||
});
|
||||
observer.flush();
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(observedInfo.target, el.$.slotContainer);
|
||||
assert.equal(observedInfo.addedNodes.length, 2);
|
||||
assert.equal(observedInfo.removedNodes.length, 0);
|
||||
// remove
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(observedInfo.addedNodes.length, 0);
|
||||
assert.equal(observedInfo.removedNodes.length, 2);
|
||||
// add
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(observedInfo.addedNodes.length, 2);
|
||||
assert.equal(observedInfo.removedNodes.length, 0);
|
||||
// reset, unobserve and remove
|
||||
observedInfo = null;
|
||||
Polymer.dom(el.$.slotContainer).unobserveNodes(observer);
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(observedInfo, null);
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
|
||||
test('observe changes to <slot>', function() {
|
||||
var el = document.createElement('test-slot');
|
||||
document.body.appendChild(el);
|
||||
var observedInfo;
|
||||
var observer = Polymer.dom(el.$.slot).observeNodes(function(info) {
|
||||
observedInfo = info;
|
||||
});
|
||||
observer.flush();
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(observedInfo.target, el.$.slot);
|
||||
assert.equal(observedInfo.addedNodes.length, 2);
|
||||
assert.equal(observedInfo.removedNodes.length, 0);
|
||||
// remove
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(observedInfo.addedNodes.length, 0);
|
||||
assert.equal(observedInfo.removedNodes.length, 2);
|
||||
// add
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(observedInfo.addedNodes.length, 2);
|
||||
assert.equal(observedInfo.removedNodes.length, 0);
|
||||
// reset, unobserve and remove
|
||||
observedInfo = null;
|
||||
Polymer.dom(el.$.slot).unobserveNodes(observer);
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(observedInfo, null);
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
|
||||
test('observe effective children inside distributing element', function() {
|
||||
var el = document.createElement('test-slot1');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var recorded;
|
||||
var observer = Polymer.dom(el.$.slot).observeNodes(function(info) {
|
||||
recorded = info;
|
||||
});
|
||||
observer.flush();
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes.length, 0);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// remove
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 0);
|
||||
assert.equal(recorded.removedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes[0], d);
|
||||
assert.equal(recorded.removedNodes[1], d1);
|
||||
// add
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// reset, unobserve and remove
|
||||
recorded = null;
|
||||
Polymer.dom(el.$.slot).unobserveNodes(observer);
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded, null);
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
|
||||
test('observe effective children changes when adding to another host', function() {
|
||||
var el = document.createElement('test-slot1');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var recorded;
|
||||
var observer = Polymer.dom(el.$.slot).observeNodes(function(info) {
|
||||
recorded = info;
|
||||
});
|
||||
observer.flush();
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes.length, 0);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// add somewhere else... we should see these as removes
|
||||
Polymer.dom(document.body).appendChild(d);
|
||||
Polymer.dom(document.body).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 0);
|
||||
assert.equal(recorded.removedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes[0], d);
|
||||
assert.equal(recorded.removedNodes[1], d1);
|
||||
// cleanup
|
||||
Polymer.dom(document.body).removeChild(d);
|
||||
Polymer.dom(document.body).removeChild(d1);
|
||||
document.body.removeChild(el);
|
||||
Polymer.dom(el.$.slot).unobserveNodes(observer);
|
||||
});
|
||||
|
||||
test('observe effective children changes in static slot when adding to another host', function() {
|
||||
var el = document.createElement('staticDiv');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var recorded;
|
||||
var observer = Polymer.dom(el).observeNodes(function(info) {
|
||||
recorded = info;
|
||||
});
|
||||
observer.flush();
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes.length, 0);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// add somewhere else... we should see these as removes
|
||||
Polymer.dom(document.body).appendChild(d);
|
||||
Polymer.dom(document.body).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 0);
|
||||
assert.equal(recorded.removedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes[0], d);
|
||||
assert.equal(recorded.removedNodes[1], d1);
|
||||
// cleanup
|
||||
Polymer.dom(document.body).removeChild(d);
|
||||
Polymer.dom(document.body).removeChild(d1);
|
||||
document.body.removeChild(el);
|
||||
Polymer.dom(el).unobserveNodes(observer);
|
||||
});
|
||||
|
||||
test('observe effective children inside deep distributing element', function() {
|
||||
var el = document.createElement('test-slot3');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var recorded;
|
||||
var slot = el.$.slot.$.slot.$.slot;
|
||||
var observer = Polymer.dom(slot).observeNodes(function(info) {
|
||||
recorded = info;
|
||||
});
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes.length, 0);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// remove
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 0);
|
||||
assert.equal(recorded.removedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes[0], d);
|
||||
assert.equal(recorded.removedNodes[1], d1);
|
||||
// add
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// reset, unobserve and remove
|
||||
recorded = null;
|
||||
Polymer.dom(slot).unobserveNodes(observer);
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded, null);
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
|
||||
test('observe <slot> inside deep distributing element', function() {
|
||||
var el = document.createElement('test-slot3');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var recorded;
|
||||
var slot = el.$.slot.$.slot.$.slot.$.slot;
|
||||
assert.equal(slot.localName, 'slot');
|
||||
var observer = Polymer.dom(slot).observeNodes(function(info) {
|
||||
recorded = info;
|
||||
});
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes.length, 0);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// remove
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 0);
|
||||
assert.equal(recorded.removedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes[0], d);
|
||||
assert.equal(recorded.removedNodes[1], d1);
|
||||
// add
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// reset, unobserve and remove
|
||||
recorded = null;
|
||||
Polymer.dom(slot).unobserveNodes(observer);
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded, null);
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
|
||||
test('observe effective children inside deep distributing element (async)', function(done) {
|
||||
var el = document.createElement('test-slot3');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var recorded;
|
||||
var slot = el.$.slot.$.slot.$.slot;
|
||||
var observer = Polymer.dom(slot).observeNodes(function(info) {
|
||||
recorded = info;
|
||||
});
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes.length, 0);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// remove
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded.addedNodes.length, 0);
|
||||
assert.equal(recorded.removedNodes.length, 2);
|
||||
assert.equal(recorded.removedNodes[0], d);
|
||||
assert.equal(recorded.removedNodes[1], d1);
|
||||
// add
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded.addedNodes.length, 2);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
assert.equal(recorded.addedNodes[1], d1);
|
||||
// reset, unobserve and remove
|
||||
recorded = null;
|
||||
Polymer.dom(slot).unobserveNodes(observer);
|
||||
Polymer.dom(el).removeChild(d);
|
||||
Polymer.dom(el).removeChild(d1);
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded, null);
|
||||
document.body.removeChild(el);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test('observe effective children attr changes inside deep distributing element (async)', function(done) {
|
||||
var el = document.createElement('test-slot-attr3');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var recorded;
|
||||
var slot = el.$.slot.$.slot.$.slot;
|
||||
var observer = Polymer.dom(slot).observeNodes(function(info) {
|
||||
recorded = info;
|
||||
});
|
||||
observer.flush();
|
||||
recorded = null;
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded, null);
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded, null);
|
||||
Polymer.dom(d).setAttribute('slot', 'a');
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded.addedNodes.length, 1);
|
||||
assert.equal(recorded.removedNodes.length, 0);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
Polymer.dom(d).removeAttribute('slot');
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded.addedNodes.length, 0);
|
||||
assert.equal(recorded.removedNodes.length, 1);
|
||||
assert.equal(recorded.removedNodes[0], d);
|
||||
recorded = null;
|
||||
Polymer.dom(slot).unobserveNodes(observer);
|
||||
Polymer.dom(d).setAttribute('slot', 'a');
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded, null);
|
||||
document.body.removeChild(el);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('observe effective children attr changes inside deep distributing element without outer select (async)', function(done) {
|
||||
var el = document.createElement('test-slot-attr-inside');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var recorded;
|
||||
var slot = el.$.slot.$.slot.$.slot.$.slot;
|
||||
var observer = Polymer.dom(slot).observeNodes(function(info) {
|
||||
recorded = info;
|
||||
});
|
||||
observer.flush();
|
||||
recorded = null;
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
var d1 = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
Polymer.dom(el).appendChild(d1);
|
||||
observer.flush();
|
||||
assert.equal(recorded, null);
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded, null);
|
||||
Polymer.dom(d).setAttribute('slot', 'a');
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded.addedNodes.length, 1);
|
||||
assert.equal(recorded.removedNodes.length, 0);
|
||||
assert.equal(recorded.addedNodes[0], d);
|
||||
Polymer.dom(d).removeAttribute('slot');
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded.addedNodes.length, 0);
|
||||
assert.equal(recorded.removedNodes.length, 1);
|
||||
assert.equal(recorded.removedNodes[0], d);
|
||||
recorded = null;
|
||||
Polymer.dom(slot).unobserveNodes(observer);
|
||||
Polymer.dom(d).setAttribute('slot', 'a');
|
||||
setTimeout(function() {
|
||||
assert.equal(recorded, null);
|
||||
document.body.removeChild(el);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('add/remove multiple observers', function() {
|
||||
var el = document.createElement('test-slot1');
|
||||
document.body.appendChild(el);
|
||||
if (customElements.flush) {
|
||||
customElements.flush();
|
||||
}
|
||||
|
||||
var r1 = 0;
|
||||
var h1 = Polymer.dom(el.$.slot).observeNodes(function() {
|
||||
r1++;
|
||||
});
|
||||
var r2 = 0;
|
||||
var h2 = Polymer.dom(el.$.slot).observeNodes(function() {
|
||||
r2++;
|
||||
});
|
||||
var r3 = 0;
|
||||
var h3 = Polymer.dom(el.$.slot).observeNodes(function() {
|
||||
r3++;
|
||||
});
|
||||
// add
|
||||
var d = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
h1.flush();
|
||||
h2.flush();
|
||||
h3.flush();
|
||||
assert.equal(r1, 1);
|
||||
assert.equal(r2, 1);
|
||||
assert.equal(r3, 1);
|
||||
Polymer.dom(el.$.slot).unobserveNodes(h1);
|
||||
d = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
h1.flush();
|
||||
h2.flush();
|
||||
h3.flush();
|
||||
assert.equal(r1, 1);
|
||||
assert.equal(r2, 2);
|
||||
assert.equal(r3, 2);
|
||||
Polymer.dom(el.$.slot).unobserveNodes(h2);
|
||||
d = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
h1.flush();
|
||||
h2.flush();
|
||||
h3.flush();
|
||||
assert.equal(r1, 1);
|
||||
assert.equal(r2, 2);
|
||||
assert.equal(r3, 3);
|
||||
Polymer.dom(el.$.slot).unobserveNodes(h3);
|
||||
d = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
h1.flush();
|
||||
h2.flush();
|
||||
h3.flush();
|
||||
assert.equal(r1, 1);
|
||||
assert.equal(r2, 2);
|
||||
assert.equal(r3, 3);
|
||||
h1 = Polymer.dom(el.$.slot).observeNodes(h1.callback);
|
||||
h2 = Polymer.dom(el.$.slot).observeNodes(h2.callback);
|
||||
h3 = Polymer.dom(el.$.slot).observeNodes(h3.callback);
|
||||
h1.flush();
|
||||
h2.flush();
|
||||
h3.flush();
|
||||
assert.equal(r1, 2);
|
||||
assert.equal(r2, 3);
|
||||
assert.equal(r3, 4);
|
||||
d = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
h1.flush();
|
||||
h2.flush();
|
||||
h3.flush();
|
||||
assert.equal(r1, 3);
|
||||
assert.equal(r2, 4);
|
||||
assert.equal(r3, 5);
|
||||
Polymer.dom(el.$.slot).unobserveNodes(h3);
|
||||
d = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
h1.flush();
|
||||
h2.flush();
|
||||
h3.flush();
|
||||
assert.equal(r1, 4);
|
||||
assert.equal(r2, 5);
|
||||
assert.equal(r3, 5);
|
||||
Polymer.dom(el.$.slot).unobserveNodes(h2);
|
||||
d = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
h1.flush();
|
||||
h2.flush();
|
||||
h3.flush();
|
||||
assert.equal(r1, 5);
|
||||
assert.equal(r2, 5);
|
||||
assert.equal(r3, 5);
|
||||
Polymer.dom(el.$.slot).unobserveNodes(h1);
|
||||
d = document.createElement('div');
|
||||
Polymer.dom(el).appendChild(d);
|
||||
h1.flush();
|
||||
h2.flush();
|
||||
h3.flush();
|
||||
assert.equal(r1, 5);
|
||||
assert.equal(r2, 5);
|
||||
assert.equal(r3, 5);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user