From f34fb45b7fdd22c32e4a60abec6ce936c7bdf9a5 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 3 Aug 2015 16:11:05 -0700 Subject: [PATCH 001/268] Adds `getEffectiveChildNodes`, `getEffectiveChildren`, `getEffectiveTextContent` --- src/lib/dom-api.html | 26 ++++++++-------- src/standard/utils.html | 57 +++++++++++++++++++++++++++++++++++ test/unit/polymer-dom.js | 9 ++++++ test/unit/utils-content.html | 26 ++++++++++++++++ test/unit/utils-elements.html | 40 +++++++++++++++++------- 5 files changed, 134 insertions(+), 24 deletions(-) diff --git a/src/lib/dom-api.html b/src/lib/dom-api.html index b18e6960..c46cb582 100644 --- a/src/lib/dom-api.html +++ b/src/lib/dom-api.html @@ -405,28 +405,28 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN points. */ queryDistributedElements: function(selector) { - var c$ = this.childNodes; + var c$ = this.getEffectiveChildNodes(); var list = []; - this._distributedFilter(selector, c$, list); for (var i=0, l=c$.length, c; (i` elements are replaced with the list of nodes distributed + * to the ``, the result of its `getDistributedNodes` method. + * + * @method getEffectiveChildNodes + * @return {Array} List of effctive child nodes. + */ + getEffectiveChildNodes: function() { + return Polymer.dom(this).getEffectiveChildNodes(); + }, + + /** + * Returns a list of elements that are the effective children. The effective + * children list is the same as the element's children except that + * any `` elements are replaced with the list of elements + * distributed to the ``. + * + * @method getEffectiveChildren + * @return {Array} List of effctive children. + */ + getEffectiveChildren: function() { + var list = Polymer.dom(this).getEffectiveChildNodes(); + return list.filter(function(n) { + return (n.nodeType === Node.ELEMENT_NODE); + }); + }, + + /** + * Returns a string of text content that is the concatenation of the + * text content's of the element's effective childNodes (the elements + * returned by +
b
+
d
+ + - - + + - \ No newline at end of file + + + + + + \ No newline at end of file From 6499e83ee767d93cd1d89175589ebd0bc16826d5 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Tue, 4 Aug 2015 14:06:18 -0700 Subject: [PATCH 002/268] Adds `Polymer.dom(element).observeChildren(callback)` api --- src/lib/dom-api.html | 145 +++++++++++++++++++++++++++++++- src/mini/shady.html | 7 ++ test/smoke/observeChildren.html | 82 ++++++++++++++++++ 3 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 test/smoke/observeChildren.html diff --git a/src/lib/dom-api.html b/src/lib/dom-api.html index c46cb582..dd4443b2 100644 --- a/src/lib/dom-api.html +++ b/src/lib/dom-api.html @@ -26,6 +26,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var DomApi = function(node) { this.node = node; + this._observers = []; + this._addedNodes = []; + this._removedNodes = [] if (this.patch) { this.patch(); } @@ -65,6 +68,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // 3. node is (host of container needs distribution) appendChild: function(node) { var handled; + this._recordMutationRemoveFromParent(node); this._removeNodeFromHost(node, true); if (this._nodeIsInLogicalTree(this.node)) { this._addLogicalInfo(node, this.node); @@ -78,6 +82,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN addToComposedParent(container, node); nativeAppendChild.call(container, node); } + this._recordMutationAdd(node); return node; }, @@ -86,6 +91,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return this.appendChild(node); } var handled; + this._recordMutationRemoveFromParent(node); this._removeNodeFromHost(node, true); if (this._nodeIsInLogicalTree(this.node)) { saveLightChildrenIfNeeded(this.node); @@ -109,6 +115,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN addToComposedParent(container, node, ref_node); nativeInsertBefore.call(container, node, ref_node); } + this._recordMutationAdd(node); return node; }, @@ -136,6 +143,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN nativeRemoveChild.call(container, node); } } + this._recordMutationRemove(node); return node; }, @@ -251,7 +259,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN root.host._elementRemove(node); hostNeedsDist = this._removeDistributedChildren(root, node); } - this._removeLogicalInfo(node, node._lightParent); + this._removeLogicalInfo(node, parent); } this._removeOwnerShadyRoot(node); if (root && hostNeedsDist) { @@ -478,6 +486,69 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } } return n; + }, + + observeChildren: function(callback) { + return this._observers.push(callback); + }, + + unobserveChildren: function(handle) { + this._observers.splice(handle - 1, 1); + }, + + _hasObservers: function() { + return Boolean(this._observers.length); + }, + + _recordMutationAdd: function(node) { + if (this._hasObservers()) { + this._addedNodes.push(node); + this._scheduleMutationNotify(); + } + }, + + _recordMutationRemove: function(node) { + if (this._hasObservers()) { + this._removedNodes.push(node); + this._scheduleMutationNotify(); + } + }, + + _recordMutationAddAll: function() { + if (this._hasObservers()) { + var c$ = this.childNodes; + for (var i=0, c; (i < c$.length) && (c=c$[i]); i++) { + this._recordMutationAdd(c); + } + } + }, + + _recordMutationRemoveFromParent: function(node) { + var parent = node._lightParent; + if (parent) { + factory(parent)._recordMutationRemove(node); + } + }, + + _scheduleMutationNotify: function() { + this._mutationDebouncer = Polymer.Debounce(this._mutationDebouncer, + this._notifyObservers); + this._mutationDebouncer.context = this; + Polymer.dom.addDebouncer(this._mutationDebouncer); + }, + + _notifyObservers: function(mxns) { + var info = { + target: this.node, + addedNodes: this._addedNodes, + removedNodes: this._removedNodes + } + var o$ = this._observers; + for (var i=0, o; (i < o$.length) && (o=o$[i]); i++) { + o.call(null, info); + } + this._addedNodes = []; + this._removedNodes = []; } }; @@ -718,7 +789,68 @@ 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() {} + DomApi.prototype._distributeParent = function() {}; + + DomApi.prototype.observeChildren = function(callback) { + if (!this._mo) { + this._mo = new MutationObserver(this._notifyObservers.bind(this)); + this._mo.observe(this.node, {childList: true}); + // make sure to notify initial state... + this._mutationDebouncer = Polymer.Debounce(this._mutationDebouncer, + function() { + this._notifyObservers([{ + target: this.node, + addedNodes: this.childNodes.slice() + }]); + } + ); + this._mutationDebouncer.context = this; + Polymer.dom.addDebouncer(this._mutationDebouncer); + } + return this._observers.push(callback); + }; + + DomApi.prototype._notifyObservers = function(mxns) { + var info = { + target: this.node, + addedNodes: [], + removedNodes: [] + }; + mxns.forEach(function(m) { + if (m.addedNodes) { + for (var i=0; i < m.addedNodes.length; i++) { + info.addedNodes.push(m.addedNodes[i]); + } + } + if (m.removedNodes) { + for (var i=0; i < m.removedNodes.length; i++) { + info.removedNodes.push(m.removedNodes[i]); + } + } + }); + if (info.addedNodes.length || info.removedNodes.length) { + var o$ = this._observers; + for (var i=0, o; (i < o$.length) && (o=o$[i]); i++) { + o.call(null, info); + } + } + }; + + DomApi.prototype.flush = function() { + if (this._mo) { + this._notifyObservers(this._mo.takeRecords()); + } + Polymer.dom.flush(); + } + + var nativeForwards = ['appendChild', 'insertBefore', + 'removeChild', 'replaceChild']; + + nativeForwards.forEach(function(forward) { + DomApi.prototype[forward] = function() { + return this.node[forward].apply(this.node, arguments); + }; + }); Object.defineProperties(DomApi.prototype, { @@ -776,7 +908,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var CONTENT = 'content'; - var factory = function(node, patch) { + function factory(node, patch) { node = node || document; if (!node.__domApi) { node.__domApi = new DomApi(node, patch); @@ -784,6 +916,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return node.__domApi; }; + function hasDomApi(node) { + return Boolean(node.__domApi); + } + Polymer.dom = function(obj, patch) { if (obj instanceof Event) { return Polymer.EventApi.factory(obj); @@ -928,7 +1064,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN matchesSelector: matchesSelector, hasInsertionPoint: hasInsertionPoint, ctor: DomApi, - factory: factory + factory: factory, + hasDomApi: hasDomApi }; })(); diff --git a/src/mini/shady.html b/src/mini/shady.html index 8d96fc7b..fff1b319 100644 --- a/src/mini/shady.html +++ b/src/mini/shady.html @@ -18,6 +18,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN polyfill across browsers. */ + + var hasDomApi = Polymer.DomApi.hasDomApi; + Polymer.Base._addFeature({ _prepShady: function() { @@ -149,7 +152,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this._updateChildNodes(this, children); } } + var hasDistributed = this.shadyRoot._hasDistributed; this.shadyRoot._hasDistributed = true; + if (!hasDistributed && hasDomApi(this)) { + Polymer.dom(this)._recordMutationAddAll(); + } } }, diff --git a/test/smoke/observeChildren.html b/test/smoke/observeChildren.html new file mode 100644 index 00000000..0b9624f4 --- /dev/null +++ b/test/smoke/observeChildren.html @@ -0,0 +1,82 @@ + + + + + observeChildren + + + + + + + + + + + + + + + + + + + + + +
content A
+
content B
+
+ +

+ +
static A
static B
+ + + + + From effedcb23a0c32748ca5521a1371486987242173 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 10 Aug 2015 10:43:55 -0700 Subject: [PATCH 003/268] Factor dom-api's into separate helpers. --- src/lib/dom-api-classlist.html | 54 +++++++ src/lib/dom-api-event.html | 93 +++++++++++ src/lib/dom-api-flush.html | 68 ++++++++ src/lib/dom-api-mutation-content.html | 129 ++++++++++++++++ src/lib/dom-api-mutation.html | 215 ++++++++++++++++++++++++++ src/lib/dom-api.html | 188 +++------------------- src/lib/event-api.html | 92 ----------- src/mini/shady.html | 8 +- 8 files changed, 587 insertions(+), 260 deletions(-) create mode 100644 src/lib/dom-api-classlist.html create mode 100644 src/lib/dom-api-event.html create mode 100644 src/lib/dom-api-flush.html create mode 100644 src/lib/dom-api-mutation-content.html create mode 100644 src/lib/dom-api-mutation.html delete mode 100644 src/lib/event-api.html diff --git a/src/lib/dom-api-classlist.html b/src/lib/dom-api-classlist.html new file mode 100644 index 00000000..7b405ad1 --- /dev/null +++ b/src/lib/dom-api-classlist.html @@ -0,0 +1,54 @@ + + \ No newline at end of file diff --git a/src/lib/dom-api-event.html b/src/lib/dom-api-event.html new file mode 100644 index 00000000..fff14f98 --- /dev/null +++ b/src/lib/dom-api-event.html @@ -0,0 +1,93 @@ + + + diff --git a/src/lib/dom-api-flush.html b/src/lib/dom-api-flush.html new file mode 100644 index 00000000..8c0ae43b --- /dev/null +++ b/src/lib/dom-api-flush.html @@ -0,0 +1,68 @@ + + \ No newline at end of file diff --git a/src/lib/dom-api-mutation-content.html b/src/lib/dom-api-mutation-content.html new file mode 100644 index 00000000..438f5fc9 --- /dev/null +++ b/src/lib/dom-api-mutation-content.html @@ -0,0 +1,129 @@ + + + \ No newline at end of file diff --git a/src/lib/dom-api-mutation.html b/src/lib/dom-api-mutation.html new file mode 100644 index 00000000..cd8e825c --- /dev/null +++ b/src/lib/dom-api-mutation.html @@ -0,0 +1,215 @@ + + + \ No newline at end of file diff --git a/src/lib/dom-api.html b/src/lib/dom-api.html index dd4443b2..9439668a 100644 --- a/src/lib/dom-api.html +++ b/src/lib/dom-api.html @@ -8,7 +8,6 @@ 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 --> - diff --git a/src/mini/shady.html b/src/mini/shady.html index fff1b319..daa2357b 100644 --- a/src/mini/shady.html +++ b/src/mini/shady.html @@ -9,6 +9,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN --> + + + + + + + + + + + + + + + + + + + + +
content A
+
content B
+
+ +

+ +
static A
static B
+ + + + + diff --git a/test/smoke/observeChildren.html b/test/smoke/observeNodes.html similarity index 75% rename from test/smoke/observeChildren.html rename to test/smoke/observeNodes.html index 0b9624f4..957a17cc 100644 --- a/test/smoke/observeChildren.html +++ b/test/smoke/observeNodes.html @@ -2,7 +2,7 @@ - observeChildren + observeNodes @@ -21,7 +21,7 @@ Polymer({ is:'test-content', created: function() { - Polymer.dom(this).observeChildren(function(info) { + Polymer.dom(this).observeNodes(function(info) { console.log('test-content', info); }); } @@ -37,7 +37,7 @@ Polymer({ is:'test-static', created: function() { - Polymer.dom(this).observeChildren(function(info) { + Polymer.dom(this).observeNodes(function(info) { console.log('test-static', info); }); } @@ -58,11 +58,11 @@ Polymer.dom(content).flush(); Polymer.dom(stat).flush(); console.group('test dynamic'); - function obs(mxns) { - console.log('custom observer', mxns); + function obs(info) { + console.log('custom observer', info); } - var hc = Polymer.dom(content).observeChildren(obs); - var hs = Polymer.dom(stat).observeChildren(obs); + var hc = Polymer.dom(content).observeNodes(obs); + var hs = Polymer.dom(stat).observeNodes(obs); var d = document.createElement('div'); d.id = 'foo'; @@ -71,8 +71,8 @@ Polymer.dom(stat).appendChild(d); Polymer.dom(content).flush(); Polymer.dom(stat).flush(); - Polymer.dom(content).unobserveChildren(hc); - Polymer.dom(stat).unobserveChildren(hs); + Polymer.dom(content).unobserveNodes(hc); + Polymer.dom(stat).unobserveNodes(hs); Polymer.dom(stat).removeChild(d); Polymer.dom(stat).flush(); console.groupEnd('test dynamic'); diff --git a/test/smoke/observeReNodes.html b/test/smoke/observeReNodes.html new file mode 100644 index 00000000..336d04d9 --- /dev/null +++ b/test/smoke/observeReNodes.html @@ -0,0 +1,98 @@ + + + + + observeReNodes + + + + + + + + + + + + + + + + + + + + + +
content A
+
content B
+
+ +

+ + + + + From 07261e4b8ef797b9916ced21b718390fe2a79c61 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Thu, 13 Aug 2015 15:31:29 -0700 Subject: [PATCH 005/268] Add `Polymer.dom().notifyObservers` method to 'kick' observers, for example, when attributes change under Shadow DOM. --- src/lib/dom-api-mutation-content.html | 4 +- src/lib/dom-api-mutation.html | 18 +++- src/lib/dom-api.html | 66 ++++---------- src/mini/shady.html | 34 ++++--- test/smoke/observeReNodes.html | 29 +++++- test/smoke/observeReNodes2.html | 126 ++++++++++++++++++++++++++ 6 files changed, 205 insertions(+), 72 deletions(-) create mode 100644 test/smoke/observeReNodes2.html diff --git a/src/lib/dom-api-mutation-content.html b/src/lib/dom-api-mutation-content.html index bf13de01..b603d91c 100644 --- a/src/lib/dom-api-mutation-content.html +++ b/src/lib/dom-api-mutation-content.html @@ -30,7 +30,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return h; }, - notifyIfNeeded: function() { + notify: function() { if (this._hasListeners()) { this._scheduleNotify(); } @@ -82,7 +82,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var host = root && root.host; if (host) { this._observer = Polymer.dom(host).observeNodes( - this.notifyIfNeeded.bind(this)); + this.notify.bind(this)); } }, diff --git a/src/lib/dom-api-mutation.html b/src/lib/dom-api-mutation.html index 5d0f6dc4..1d3b16fd 100644 --- a/src/lib/dom-api-mutation.html +++ b/src/lib/dom-api-mutation.html @@ -14,6 +14,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var DomApi = Polymer.DomApi.ctor; var Settings = Polymer.Settings; + var hasDomApi = Polymer.DomApi.hasDomApi; DomApi.Mutation = function(domApi) { this.domApi = domApi; @@ -100,7 +101,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _observeContentElements: function(elements) { for (var i=0, h, n; (i < elements.length) && (n=elements[i]); i++) { - if (n.localName === 'content') { + if (this._isContent(n)) { n.__observeNodesMap = n.__observeNodesMap || new WeakMap(); if (n.__observeNodesMap.get(this) === undefined) { h = Polymer.dom(n).observeNodes( @@ -113,7 +114,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _unobserveContentElements: function(elements) { for (var i=0, n, h; (i < elements.length) && (n=elements[i]); i++) { - if (n.localName === 'content') { + if (this._isContent(n)) { h = n.__observeNodesMap.get(this); if (h) { Polymer.dom(n).unobserveNodes(h); @@ -122,6 +123,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } }, + _isContent: function(node) { + return (node.localName === 'content'); + }, + _callListeners: function(info) { var o$ = this._listeners; for (var i=0, o; (i < o$.length) && (o=o$[i]); i++) { @@ -151,10 +156,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this._debouncer.context = this; Polymer.dom.addDebouncer(this._debouncer); this._preflush = this._flush.bind(this); - Polymer.dom.addPreflush(this._preflush); + + } + if (!this._hasListeners()) { + Polymer.dom.addPreflush(this._preflush); + // note: doing this > 1x is a no-op + this._observer.observe(this.node, {childList: true}); } - // note: doing this > 1x is a no-op - this._observer.observe(this.node, {childList: true}); }, _cleanupObserver: function() { diff --git a/src/lib/dom-api.html b/src/lib/dom-api.html index 906ca167..91b8e92d 100644 --- a/src/lib/dom-api.html +++ b/src/lib/dom-api.html @@ -538,7 +538,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (this.observer) { this.observer.removeListener(handle); } - } + }, + + // abstract, intended as public 'kick' mehanism + notifyObservers: function() {} }; @@ -744,58 +747,25 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN DomApi.prototype._distributeParent = function() {}; - DomApi.prototype.observeChildren = function(callback) { - if (!this._mo) { - this._mo = new MutationObserver(this._notifyObservers.bind(this)); - this._mo.observe(this.node, {childList: true}); - // make sure to notify initial state... - this._mutationDebouncer = Polymer.Debounce(this._mutationDebouncer, - function() { - this._notifyObservers([{ - target: this.node, - addedNodes: this.childNodes.slice() - }]); - } - ); - this._mutationDebouncer.context = this; - Polymer.dom.addDebouncer(this._mutationDebouncer); - } - return this._observers.push(callback); - }; - - DomApi.prototype._notifyObservers = function(mxns) { - var info = { - target: this.node, - addedNodes: [], - removedNodes: [] - }; - mxns.forEach(function(m) { - if (m.addedNodes) { - for (var i=0; i < m.addedNodes.length; i++) { - info.addedNodes.push(m.addedNodes[i]); + DomApi.prototype.notifyObservers = function() { + if (this.node.shadowRoot) { + var ip$ = this.node.shadowRoot.querySelectorAll('content'); + for (var i=0, c; (i @@ -68,8 +78,8 @@ Polymer.dom.flush(); - - // setTimeout(function() { + + function test() { console.group('test dynamic'); var d = makeNode('dynamic!'); Polymer.dom.flush(); @@ -91,7 +101,18 @@ Polymer.dom(content).removeChild(Polymer.dom(content).lastChild); Polymer.dom.flush(); console.groupEnd('test dynamic'); - // }, 1000); + } + test(); + content.$.inner.unobserve(); + test(); + content.$.inner.observe(); + test(); + content.$.inner.unobserve(); + test(); + content.$.inner.observe(); + test(); + + diff --git a/test/smoke/observeReNodes2.html b/test/smoke/observeReNodes2.html new file mode 100644 index 00000000..e9477e1f --- /dev/null +++ b/test/smoke/observeReNodes2.html @@ -0,0 +1,126 @@ + + + + + observeReNodes + + + + + + + + + + + + + + + + + + + + + +
content A
+
content B
+
+ +

+ + + + + From 8242a98e38690b94030ab57b36ed9cf03b398c02 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Tue, 25 Aug 2015 10:31:57 -0700 Subject: [PATCH 006/268] Add optional attribute tracking to support better distributed node notifications under shadow dom. --- src/lib/dom-api-mutation-content.html | 29 +++-- src/lib/dom-api-mutation.html | 117 ++++++++++++++---- src/lib/dom-api.html | 2 +- ...ReNodes2.html => observeReNodes-attr.html} | 46 +++++-- 4 files changed, 153 insertions(+), 41 deletions(-) rename test/smoke/{observeReNodes2.html => observeReNodes-attr.html} (74%) diff --git a/src/lib/dom-api-mutation-content.html b/src/lib/dom-api-mutation-content.html index b603d91c..f458046e 100644 --- a/src/lib/dom-api-mutation-content.html +++ b/src/lib/dom-api-mutation-content.html @@ -23,13 +23,17 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.Base.extend(DomApi.MutationContent.prototype, { - addListener: function(callback, includeChanges) { - this._includeChanges = includeChanges; - var h = DomApi.Mutation.prototype.addListener.call(this, callback); + addListener: function(callback, options) { + var h = DomApi.Mutation.prototype.addListener.call(this, callback, + options); this._scheduleNotify(); return h; }, + _ensureSetup: function(options) { + this._describeChanges = options && options.changes; + }, + notify: function() { if (this._hasListeners()) { this._scheduleNotify(); @@ -37,7 +41,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _notify: function() { - var info = this._includeChanges ? this._calcChanges() : {}; + var info = this._describeChanges ? this._calcChanges() : {}; if (info) { info.target = this.node; this._callListeners(info); @@ -75,20 +79,29 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (Settings.useShadow) { + var ensureSetup = DomApi.MutationContent.prototype._ensureSetup; + Polymer.Base.extend(DomApi.MutationContent.prototype, { - _ensureObserver: function() { + _ensureSetup: function(options) { + ensureSetup.call(this, options); + this._trackAttributes = this._trackAttributes || + options && options.attributes; var root = this.domApi.getOwnerRoot(); var host = root && root.host; if (host) { this._observer = Polymer.dom(host).observeNodes( - this.notify.bind(this)); + this.notify.bind(this), {attributes: this._trackAttributes}); } }, - _cleanupObserver: function() { + _ensureCleanup: function() { if (this._observer) { - Polymer.dom(host).unobserveNodes(this._observer); + var root = this.domApi.getOwnerRoot(); + var host = root && root.host; + if (host) { + Polymer.dom(host).unobserveNodes(this._observer); + } } } diff --git a/src/lib/dom-api-mutation.html b/src/lib/dom-api-mutation.html index 1d3b16fd..802355c6 100644 --- a/src/lib/dom-api-mutation.html +++ b/src/lib/dom-api-mutation.html @@ -26,24 +26,23 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN DomApi.Mutation.prototype = { - addListener: function(callback) { - this._ensureObserver(); - return this._listeners.push(callback); + addListener: function(callback, options) { + this._ensureSetup(options); + return this._listeners.push({fn: callback, options: options}); }, removeListener: function(handle) { this._listeners.splice(handle - 1, 1); if (!this._hasListeners()) { - this._cleanupObserver(); + this._ensureCleanup(); } }, - _ensureObserver: function() { + _ensureSetup: function(options) { this._observeContentElements(this.domApi.childNodes); }, - // TODO(sorvell): unobserver content? - _cleanupObserver: function() {}, + _ensureCleanup: function() {}, // abstract _hasListeners: function() { return Boolean(this._listeners.length); @@ -83,7 +82,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _notify: function(mxns) { - var info = { + var info = mxns || { target: this.node, addedNodes: this._addedNodes, removedNodes: this._removedNodes @@ -103,20 +102,26 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN for (var i=0, h, n; (i < elements.length) && (n=elements[i]); i++) { if (this._isContent(n)) { n.__observeNodesMap = n.__observeNodesMap || new WeakMap(); - if (n.__observeNodesMap.get(this) === undefined) { - h = Polymer.dom(n).observeNodes( - this._callListeners.bind(this), true); + if (n.__observeNodesMap.get(this) == null) { + h = this._observeContent(n); n.__observeNodesMap.set(this, h); } } } }, + _observeContent: function(content) { + return Polymer.dom(content).observeNodes(this._notify.bind(this), { + changes: true + }); + }, + _unobserveContentElements: function(elements) { for (var i=0, n, h; (i < elements.length) && (n=elements[i]); i++) { if (this._isContent(n)) { h = n.__observeNodesMap.get(this); if (h) { + n.__observeNodesMap.set(this, null); Polymer.dom(n).unobserveNodes(h); } } @@ -127,10 +132,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return (node.localName === 'content'); }, - _callListeners: function(info) { + _callListeners: function(info, filter) { var o$ = this._listeners; for (var i=0, o; (i < o$.length) && (o=o$[i]); i++) { - o.call(this.node, info); + if (!filter || filter(o.options)) { + o.fn.call(this.node, info); + } } } @@ -140,7 +147,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.Base.extend(DomApi.Mutation.prototype, { - _ensureObserver: function() { + _ensureSetup: function(options) { + this._trackAttributes = this._trackAttributes || + options && options.attributes; if (!this._observer) { this._observer = new MutationObserver(this._notify.bind(this)); @@ -165,7 +174,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } }, - _cleanupObserver: function() { + _ensureCleanup: function() { this._observer.disconnect(); Polymer.dom.removePreflush(this._preflush); }, @@ -176,20 +185,30 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN addedNodes: [], removedNodes: [] }; - mxns.forEach(function(m) { - if (m.addedNodes) { - for (var i=0; i < m.addedNodes.length; i++) { - info.addedNodes.push(m.addedNodes[i]); + // collapse multiple mutations into one view + if (Array.isArray(mxns)) { + Array.prototype.forEach.call(mxns, function(m) { + if (m.addedNodes) { + for (var i=0; i < m.addedNodes.length; i++) { + info.addedNodes.push(m.addedNodes[i]); + } } - } - if (m.removedNodes) { - for (var i=0; i < m.removedNodes.length; i++) { - info.removedNodes.push(m.removedNodes[i]); + if (m.removedNodes) { + for (var i=0; i < m.removedNodes.length; i++) { + info.removedNodes.push(m.removedNodes[i]); + } } - } - }); + }); + } else if (mxns) { + info = mxns; + } if (info.addedNodes.length || info.removedNodes.length) { this._updateContentElements(info); + // attribute tracking helps us notice distributed nodes changes + // needed only with shadow dom. + if (this._trackAttributes) { + this._updateAttributeObservers(info); + } this._callListeners(info); } }, @@ -198,6 +217,54 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (this._observer) { this._notify(this._observer.takeRecords()); } + }, + + _observeContent: function(content) { + return Polymer.dom(content).observeNodes(this._notify.bind(this), { + changes: true, + attributes: this._trackAttributes + }); + }, + + _updateAttributeObservers: function(info) { + this._observeAttributes(info.addedNodes); + this._unobserveAttributes(info.removedNodes); + }, + + _observeAttributes: function(elements) { + for (var i=0, h, n; (i < elements.length) && (n=elements[i]); i++) { + if (n.nodeType === Node.ELEMENT_NODE) { + this._ensureElementAttrObserver(n); + } + } + }, + + _ensureElementAttrObserver: function(element) { + this._attrObservers = this._attrObservers || new WeakMap(); + if (!this._attrObservers.get(element)) { + var self = this; + this._attrObservers.set(element, new MutationObserver( + function(mxns) { + self._callListeners(mxns, function(options) { + return Boolean(options && options.attributes); + }); + } + )); + this._attrObservers.get(element) + .observe(element, {attributes: true}); + } + }, + + _unobserveAttributes: function(elements) { + for (var i=0, h, n; (i < elements.length) && (n=elements[i]); i++) { + if (n.nodeType === Node.ELEMENT_NODE) { + h = this._attrObservers.get(n); + if (h) { + h.disconnect(n); + } + this._attrObservers.set(n, null); + } + } } }); diff --git a/src/lib/dom-api.html b/src/lib/dom-api.html index 388f84b9..f697088e 100644 --- a/src/lib/dom-api.html +++ b/src/lib/dom-api.html @@ -525,7 +525,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return n; }, - observeNodes: function(callback) { + observeNodes: function(callback, options) { if (!this.observer) { this.observer = this.node.localName === CONTENT ? new DomApi.MutationContent(this) : diff --git a/test/smoke/observeReNodes2.html b/test/smoke/observeReNodes-attr.html similarity index 74% rename from test/smoke/observeReNodes2.html rename to test/smoke/observeReNodes-attr.html index e9477e1f..d53a5097 100644 --- a/test/smoke/observeReNodes2.html +++ b/test/smoke/observeReNodes-attr.html @@ -25,6 +25,7 @@ }, observe: function() { + console.warn('observeNodes', this.localName); this._childObserver = Polymer.dom(this).observeNodes(function(info) { info.addedNodes.forEach(function(n) { if (n.nodeType === Node.ELEMENT_NODE) { @@ -36,7 +37,7 @@ console.log('removed:', n.localName, n.textContent); } }); - }); + }, {changes: true, attributes: true}); this._contentObserver = Polymer.dom(this.$.c).observeNodes(function(info) { info.addedNodes.forEach(function(n) { if (n.nodeType === Node.ELEMENT_NODE) { @@ -48,12 +49,13 @@ console.log('%c content removed:', 'color: blue;', n.localName, n.textContent); } }); - }, true); + }, {changes: true, attributes: true}); }, unobserve: function() { + console.warn('unobserveNodes', this.localName); Polymer.dom(this).unobserveNodes(this._childObserver); - Polymer.dom(this).unobserveNodes(this._contentObserver); + Polymer.dom(this.$.c).unobserveNodes(this._contentObserver); } }); @@ -90,7 +92,7 @@ Polymer.dom.flush(); - // setTimeout(function() { + function test(done) { console.group('test dynamic'); var d = makeNode('dynamic!'); Polymer.dom.flush(); @@ -103,7 +105,7 @@ Polymer.dom(content).appendChild(d); Polymer.dom.flush(); Polymer.dom(d).classList.add('a'); - Polymer.dom(Polymer.dom(d).parentNode).notifyObservers(); + //Polymer.dom(Polymer.dom(d).parentNode).notifyObservers(); Polymer.dom(content.$.inner).appendChild(makeNode('2')); Polymer.dom.flush(); d = makeNode('-1'); @@ -118,8 +120,38 @@ Polymer.dom(content).removeChild(Polymer.dom(content).firstChild); Polymer.dom(content).removeChild(Polymer.dom(content).lastChild); Polymer.dom.flush(); - console.groupEnd('test dynamic'); - // }, 1000); + + var d1 = makeNode('dynamic2!'); + Polymer.dom(content).appendChild(d1); + + setTimeout(function() { + Polymer.dom(d1).classList.add('a'); + Polymer.dom(d1).classList.add('b'); + setTimeout(function() { + //Polymer.dom(content).notifyObservers(); + console.groupEnd('test dynamic'); + if (done) { + done(); + } + }); + }); + } + + + test(function() { + content.$.inner.unobserve(); + test(function() { + content.$.inner.observe(); + test(function() { + content.$.inner.unobserve(); + test(function() { + content.$.inner.observe(); + test(); + }); + }); + }); + }); + From bd90b5704e05d8d539c05fcd620a16bd9293449b Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 31 Aug 2015 18:41:33 -0700 Subject: [PATCH 007/268] add `observeNodes` tests. --- src/lib/dom-api-mutation-content.html | 23 +- src/lib/dom-api-mutation.html | 64 ++-- test/runner.html | 1 + test/unit/polymer-dom-observeNodes.html | 467 ++++++++++++++++++++++++ 4 files changed, 512 insertions(+), 43 deletions(-) create mode 100644 test/unit/polymer-dom-observeNodes.html diff --git a/src/lib/dom-api-mutation-content.html b/src/lib/dom-api-mutation-content.html index f458046e..5683c4b5 100644 --- a/src/lib/dom-api-mutation-content.html +++ b/src/lib/dom-api-mutation-content.html @@ -30,9 +30,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return h; }, - _ensureSetup: function(options) { - this._describeChanges = options && options.changes; - }, + _ensureSetup: function(options) {}, notify: function() { if (this._hasListeners()) { @@ -41,7 +39,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _notify: function() { - var info = this._describeChanges ? this._calcChanges() : {}; + var info = this._suspendChangeInfo ? {} : this._calcChanges(); if (info) { info.target = this.node; this._callListeners(info); @@ -79,19 +77,18 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (Settings.useShadow) { - var ensureSetup = DomApi.MutationContent.prototype._ensureSetup; - Polymer.Base.extend(DomApi.MutationContent.prototype, { _ensureSetup: function(options) { - ensureSetup.call(this, options); this._trackAttributes = this._trackAttributes || - options && options.attributes; - var root = this.domApi.getOwnerRoot(); - var host = root && root.host; - if (host) { - this._observer = Polymer.dom(host).observeNodes( - this.notify.bind(this), {attributes: this._trackAttributes}); + options.attributes; + if (!this._observer) { + var root = this.domApi.getOwnerRoot(); + var host = root && root.host; + if (host) { + this._observer = Polymer.dom(host).observeNodes( + this.notify.bind(this), {attributes: this._trackAttributes}); + } } }, diff --git a/src/lib/dom-api-mutation.html b/src/lib/dom-api-mutation.html index 802355c6..830cad73 100644 --- a/src/lib/dom-api-mutation.html +++ b/src/lib/dom-api-mutation.html @@ -27,8 +27,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN DomApi.Mutation.prototype = { addListener: function(callback, options) { + options = options || {}; this._ensureSetup(options); - return this._listeners.push({fn: callback, options: options}); + var listener = {fn: callback, options: options}; + this._notifyInitial(listener); + return this._listeners.push(listener); }, removeListener: function(handle) { @@ -39,7 +42,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _ensureSetup: function(options) { - this._observeContentElements(this.domApi.childNodes); + if (!this._isSetup) { + this._isSetup = true; + this._observeContentElements(this.domApi.childNodes); + } }, _ensureCleanup: function() {}, // abstract @@ -62,8 +68,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } }, - addAllNodes: function() { - if (this._hasListeners()) { + addAllNodes: function(force) { + if (this._hasListeners() || force) { var c$ = this.domApi.childNodes; if (c$.length) { for (var i=0, c; (i < c$.length) && (c=c$[i]); i++) { @@ -93,6 +99,15 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this._removedNodes = []; }, + _notifyInitial: function(listener) { + var info = { + target: this.node, + addedNodes: this.domApi.childNodes, + removedNodes: [] + }; + this._callListener(listener, info); + }, + _updateContentElements: function(info) { this._observeContentElements(info.addedNodes); this._unobserveContentElements(info.removedNodes); @@ -111,9 +126,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _observeContent: function(content) { - return Polymer.dom(content).observeNodes(this._notify.bind(this), { - changes: true - }); + return Polymer.dom(content).observeNodes(this._notify.bind(this)); }, _unobserveContentElements: function(elements) { @@ -136,42 +149,34 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var o$ = this._listeners; for (var i=0, o; (i < o$.length) && (o=o$[i]); i++) { if (!filter || filter(o.options)) { - o.fn.call(this.node, info); + this._callListener(o, info); } } + }, + + _callListener: function(listener, info) { + return listener.fn.call(this.node, info); } }; if (Settings.useShadow) { + var ensureSetup = DomApi.Mutation.prototype._ensureSetup; + Polymer.Base.extend(DomApi.Mutation.prototype, { _ensureSetup: function(options) { this._trackAttributes = this._trackAttributes || - options && options.attributes; + options.attributes; if (!this._observer) { - this._observer = - new MutationObserver(this._notify.bind(this)); - // make sure to notify initial state... - this._debouncer = Polymer.Debounce(this._debouncer, - function() { - this._notify([{ - target: this.node, - addedNodes: this.domApi.childNodes.slice() - }]); - } - ); - this._debouncer.context = this; - Polymer.dom.addDebouncer(this._debouncer); + this._observer = new MutationObserver(this._notify.bind(this)); this._preflush = this._flush.bind(this); - - } - if (!this._hasListeners()) { - Polymer.dom.addPreflush(this._preflush); - // note: doing this > 1x is a no-op - this._observer.observe(this.node, {childList: true}); + Polymer.dom.addPreflush(this._preflush); + // note: doing this > 1x is a no-op + this._observer.observe(this.node, {childList: true}); } + ensureSetup.call(this, options); }, _ensureCleanup: function() { @@ -221,7 +226,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _observeContent: function(content) { return Polymer.dom(content).observeNodes(this._notify.bind(this), { - changes: true, attributes: this._trackAttributes }); }, @@ -246,7 +250,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this._attrObservers.set(element, new MutationObserver( function(mxns) { self._callListeners(mxns, function(options) { - return Boolean(options && options.attributes); + return Boolean(options.attributes); }); } )); diff --git a/test/runner.html b/test/runner.html index 0d78dec5..92455607 100644 --- a/test/runner.html +++ b/test/runner.html @@ -33,6 +33,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN 'unit/polymer-dom.html', 'unit/polymer-dom-shadow.html', 'unit/polymer-dom-content.html', + 'unit/polymer-dom-observeNodes.html', 'unit/bind.html', 'unit/bind.html?dom=shadow', 'unit/notify-path.html', diff --git a/test/unit/polymer-dom-observeNodes.html b/test/unit/polymer-dom-observeNodes.html new file mode 100644 index 00000000..d1b6d996 --- /dev/null +++ b/test/unit/polymer-dom-observeNodes.html @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
A
B
+ +
static A
static B
+ + + + + From 9ff2ee4d292afe9cd6e6bae8991cc5907d47e96a Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 31 Aug 2015 18:59:50 -0700 Subject: [PATCH 008/268] make tests work on polyfill. --- test/unit/polymer-dom-observeNodes.html | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/unit/polymer-dom-observeNodes.html b/test/unit/polymer-dom-observeNodes.html index d1b6d996..72405774 100644 --- a/test/unit/polymer-dom-observeNodes.html +++ b/test/unit/polymer-dom-observeNodes.html @@ -22,9 +22,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
static
@@ -33,9 +35,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN [] @@ -44,9 +48,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN @@ -55,9 +61,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN @@ -66,9 +74,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN @@ -77,9 +87,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN [] @@ -88,9 +100,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN @@ -99,9 +113,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN @@ -110,9 +126,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN From b2f8e8fe6cf81ef77402b9681c88ace525c966e9 Mon Sep 17 00:00:00 2001 From: Justin Fagnani Date: Thu, 3 Sep 2015 14:03:45 -0700 Subject: [PATCH 009/268] Remove redundant assign to window.Polymer --- src/lib/polymer-bootstrap.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lib/polymer-bootstrap.html b/src/lib/polymer-bootstrap.html index 3386d515..1b9a5fb9 100644 --- a/src/lib/polymer-bootstrap.html +++ b/src/lib/polymer-bootstrap.html @@ -56,8 +56,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return prototype.constructor; }; - window.Polymer = Polymer; - if (userPolymer) { for (var i in userPolymer) { Polymer[i] = userPolymer[i]; @@ -94,4 +92,3 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }; - From 338574dfe8f63708c048cc7a99d9d30f4838badd Mon Sep 17 00:00:00 2001 From: ikeagold Date: Fri, 25 Sep 2015 23:49:56 +0300 Subject: [PATCH 010/268] added missing semicolons, removed some unused variables --- src/lib/css-parse.html | 4 ++-- src/lib/dom-api.html | 8 ++++---- src/lib/dom-innerHTML.html | 2 +- src/lib/dom-module.html | 2 +- src/lib/experimental/sinspect.html | 2 +- src/lib/style-cache.html | 2 +- src/lib/style-transformer.html | 2 +- src/micro/tag.html | 2 +- src/mini/shady.html | 2 +- src/standard/gestures.html | 1 - src/standard/x-styling.html | 2 +- 11 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/lib/css-parse.html b/src/lib/css-parse.html index a176d7c1..dcb80659 100644 --- a/src/lib/css-parse.html +++ b/src/lib/css-parse.html @@ -31,7 +31,7 @@ Polymer.CssParse = (function() { _lex: function(text) { var root = {start: 0, end: text.length}; var n = root; - for (var i=0, s=0, l=text.length; i < l; i++) { + for (var i=0, l=text.length; i < l; i++) { switch (text[i]) { case this.OPEN_BRACE: //console.group(i); @@ -161,7 +161,7 @@ Polymer.CssParse = (function() { mixinProp: /(?:^|[\s;])--[^;{]*?:[^{;]*?{[^}]*?}(?:[;\n]|$)?/gim, mixinApply: /@apply[\s]*\([^)]*?\)[\s]*(?:[;\n]|$)?/gim, varApply: /[^;:]*?:[^;]*var[^;]*(?:[;\n]|$)?/gim, - keyframesRule: /^@[^\s]*keyframes/, + keyframesRule: /^@[^\s]*keyframes/ }, VAR_START: '--', diff --git a/src/lib/dom-api.html b/src/lib/dom-api.html index 944234ea..40e6ab43 100644 --- a/src/lib/dom-api.html +++ b/src/lib/dom-api.html @@ -525,7 +525,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN DomApi.ClassList = function(host) { this.domApi = host; this.node = host.node; - } + }; DomApi.ClassList.prototype = { add: function() { @@ -546,7 +546,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return this.node.classList.contains.apply(this.node.classList, arguments); } - } + }; // changes and accessors... if (!Settings.useShadow) { @@ -738,7 +738,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var doc = this.node instanceof Document ? this.node : this.node.ownerDocument; return doc.importNode(externalNode, deep); - } + }; DomApi.prototype.getDestinationInsertionPoints = function() { var n$ = this.node.getDestinationInsertionPoints && @@ -752,7 +752,7 @@ 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() {} + DomApi.prototype._distributeParent = function() {}; Object.defineProperties(DomApi.prototype, { diff --git a/src/lib/dom-innerHTML.html b/src/lib/dom-innerHTML.html index 466bbba6..5586ec9d 100644 --- a/src/lib/dom-innerHTML.html +++ b/src/lib/dom-innerHTML.html @@ -29,7 +29,7 @@ Polymer.domInnerHTML = (function() { case '>': return '>'; case '"': - return '"' + return '"'; case '\u00A0': return ' '; } diff --git a/src/lib/dom-module.html b/src/lib/dom-module.html index 0d532565..97617c95 100644 --- a/src/lib/dom-module.html +++ b/src/lib/dom-module.html @@ -6,7 +6,7 @@ var lcModules = {}; var findModule = function(id) { return modules[id] || lcModules[id.toLowerCase()]; - } + }; /** * The `dom-module` element registers the dom it contains to the name given diff --git a/src/lib/experimental/sinspect.html b/src/lib/experimental/sinspect.html index 009653a2..0e0b33c9 100644 --- a/src/lib/experimental/sinspect.html +++ b/src/lib/experimental/sinspect.html @@ -193,7 +193,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // remote api - shadowize = function() { + var shadowize = function() { var idx = Number(this.attributes.idx.value); //alert(idx); var node = drillable[idx]; diff --git a/src/lib/style-cache.html b/src/lib/style-cache.html index 02dabc83..8b2f1ff6 100644 --- a/src/lib/style-cache.html +++ b/src/lib/style-cache.html @@ -12,7 +12,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.StyleCache = function() { this.cache = {}; - } + }; Polymer.StyleCache.prototype = { diff --git a/src/lib/style-transformer.html b/src/lib/style-transformer.html index fe205707..6ffb33d9 100644 --- a/src/lib/style-transformer.html +++ b/src/lib/style-transformer.html @@ -97,7 +97,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN elementStyles: function(element, callback) { var styles = element._styles; var cssText = ''; - for (var i=0, l=styles.length, s, text; (i Date: Wed, 30 Sep 2015 12:15:39 -0700 Subject: [PATCH 011/268] added request to submit an issue before sending a PR --- CONTRIBUTING.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 26ec2bf6..0c0fc070 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,13 +46,23 @@ We love examples for addressing issues - issues with a Plunkr, jsFiddle, or jsBi Occasionally we'll close issues if they appear stale or are too vague - please don't take this personally! Please feel free to re-open issues we've closed if there's something we've missed and they still need to be addressed. -## Contributing Code to Elements +## Contributing Pull Requests + +PR's are even better than issues. We gladly accept community pull requests. In general across the core library and all of the elements, there are a few necessary steps before we can accept a pull request: + +- Open an issue describing the problem that you are looking to solve in your PR. This makes it easier to have a conversation around the best general approach for solving your problem, outside of the code itself. +- Sign the [CLA](https://cla.developers.google.com/clas), as described above. +- Submit your PR, making sure it references the issue you created. + +If you've completed all of these steps the core team will do its best to respond to the PR as soon as possible. + +### Contributing Code to Elements Though the aim of the Polymer library is to allow lots of flexibility and not get in your way, we work to standardize our elements to make them as toolable and easy to maintain as possible. All elements should follow the [Polymer element style guide](http://polymerelements.github.io/style-guide/), which defines how to specify properties, documentation, and more. It's a great guide to follow when building your own elements as well, for maximum standardization and toolability. For instance, structuring elements following the style guide will ensure that they work with the [`iron-component-page`](https://github.com/polymerelements/iron-component-page) element, an incredibly easy way to turn any raw element directly into a documentation page. -## Contributing Code to the Polymer library +### Contributing Code to the Polymer library We follow the most common javascript and HTML style guidelines for how we structure our code - in general, look at the code and you'll know how to contribute! If you'd like a bit more structure, the [Google Javascript Styleguide](https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) is a good place to start. From e18f009740c3a7cfafbd92c247174365effb2bdd Mon Sep 17 00:00:00 2001 From: Arthur Evans Date: Wed, 30 Sep 2015 12:27:07 -0700 Subject: [PATCH 012/268] Added note about including a clear repro case. --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c0fc070..5c86d32a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,6 +53,7 @@ PR's are even better than issues. We gladly accept community pull requests. In g - Open an issue describing the problem that you are looking to solve in your PR. This makes it easier to have a conversation around the best general approach for solving your problem, outside of the code itself. - Sign the [CLA](https://cla.developers.google.com/clas), as described above. - Submit your PR, making sure it references the issue you created. +- Make sure the issue includes clear steps to reproduce the issue so we can test your fix. If you've completed all of these steps the core team will do its best to respond to the PR as soon as possible. From 23c883b10b8ef2ddd9167ec0801da424bd50595b Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Wed, 30 Sep 2015 12:45:27 -0700 Subject: [PATCH 013/268] Parent property values should come from template. Fixes #2504. --- src/lib/template/templatizer.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/template/templatizer.html b/src/lib/template/templatizer.html index b06aa6c0..95dbf34e 100644 --- a/src/lib/template/templatizer.html +++ b/src/lib/template/templatizer.html @@ -87,6 +87,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * @param {HTMLTemplateElement} template The template to process. */ templatize: function(template) { + this._templatized = template; // TODO(sjmiles): supply _alternate_ content reference missing from root // templates (not nested). `_content` exists to provide content sharing // for nested templates. @@ -383,8 +384,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN stamp: function(model) { model = model || {}; if (this._parentProps) { + var templatized = this._templatized; for (var prop in this._parentProps) { - model[prop] = this[this._parentPropPrefix + prop]; + model[prop] = templatized[this._parentPropPrefix + prop]; } } return new this.ctor(model, this); From 2e086fec0d5ebacccd54772ca5df74b48abba160 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Tue, 6 Oct 2015 09:50:58 -0700 Subject: [PATCH 014/268] Add notify-path API to templatized template. Fixes #2505. --- src/lib/template/templatizer.html | 16 +++++++++++++--- src/standard/notify-path.html | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/lib/template/templatizer.html b/src/lib/template/templatizer.html index 95dbf34e..6d209c60 100644 --- a/src/lib/template/templatizer.html +++ b/src/lib/template/templatizer.html @@ -224,6 +224,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // assume that the template is not a Poylmer.Base, so prep it // for binding Polymer.Bind.prepareModel(proto); + Polymer.Base.prepareModelNotifyPath(proto); } // Create accessors for each parent prop that forward the property // to template instances through abstract _forwardParentProp API @@ -240,12 +241,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } } // Instance setup + this._extendTemplate(template, proto); if (template != this) { Polymer.Bind.prepareInstance(template); - template._forwardParentProp = - this._forwardParentProp.bind(this); + template._forwardParentProp = this._forwardParentProp.bind(this); + template._pathEffector = this._pathEffectorTemplate.bind(this); } - this._extendTemplate(template, proto); } }, @@ -312,6 +313,15 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.Base._pathEffector.apply(this, arguments); }, + // Overrides Base notify-path module (for non-PE templates) + _pathEffectorTemplate: function(path, value, fromAbove) { + if (this._forwardParentPath) { + if (path.indexOf(this._parentPropPrefix) === 0) { + this._forwardParentPath(path.substring(8), value); + } + } + }, + _constructorImpl: function(model, host) { this._rootDataHost = host._getRootDataHost(); this._setupConfigure(model); diff --git a/src/standard/notify-path.html b/src/standard/notify-path.html index 8875cf5d..0ec156a8 100644 --- a/src/standard/notify-path.html +++ b/src/standard/notify-path.html @@ -483,6 +483,25 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this._notifySplice(array, path, 0, args.length, []); } return ret; + }, + + // TODO(kschaaf): This is the path analogue to Polymer.Bind.prepareModel, + // which provides API for path-based notification on elements with property + // effects; this should be re-factored along with the Bind lib, either all on + // Base or all in Bind. + prepareModelNotifyPath: function(model) { + this.mixin(model, { + notifyPath: Polymer.Base.notifyPath, + _notifyPath: Polymer.Base._notifyPath, + _pathEffector: Polymer.Base._pathEffector, + _annotationPathEffect: Polymer.Base._annotationPathEffect, + _complexObserverPathEffect: Polymer.Base._complexObserverPathEffect, + _annotatedComputationPathEffect: Polymer.Base._annotatedComputationPathEffect, + _computePathEffect: Polymer.Base._computePathEffect, + _modelForPath: Polymer.Base._modelForPath, + _pathMatchesEffect: Polymer.Base._pathMatchesEffect, + _notifyBoundPaths: Polymer.Base._notifyBoundPaths + }); } }); From 1e9110a6cf57bd8e0a850c1aa4a98cadce5c0cb1 Mon Sep 17 00:00:00 2001 From: Monica Dinculescu Date: Thu, 1 Oct 2015 17:47:14 -0700 Subject: [PATCH 015/268] add util method for shadow children --- src/standard/utils.html | 33 ++++++++++++--- test/unit/utils-content.html | 78 +++++++++++++++++++++++++++++------ test/unit/utils-elements.html | 21 +++++++++- test/unit/utils.html | 2 +- 4 files changed, 115 insertions(+), 19 deletions(-) diff --git a/src/standard/utils.html b/src/standard/utils.html index d0cdab89..cde10497 100644 --- a/src/standard/utils.html +++ b/src/standard/utils.html @@ -150,7 +150,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * payload. * @param {Object=} options Object specifying options. These may include: * `bubbles` (boolean, defaults to `true`), - * `cancelable` (boolean, defaults to false), and + * `cancelable` (boolean, defaults to false), and * `node` on which to fire the event (HTMLElement, defaults to `this`). * @return {CustomEvent} The new event that was fired. */ @@ -199,11 +199,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN /** * Removes an item from an array, if it exists. - * - * If the array is specified by path, a change notification is + * + * If the array is specified by path, a change notification is * generated, so that observers, data bindings and computed - * properties watching that path can update. - * + * properties watching that path can update. + * * If the array is passed directly, **no change * notification is generated**. * @@ -306,6 +306,29 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } } return elt; + }, + + /** + * Checks whether an element is in this element's light DOM tree. + * + * @method isLightDescendant + * @param {HTMLElement=} node The element to be checked. + * @return {Boolean} true if node is in this element's light DOM tree. + */ + isLightDescendant: function(node) { + return this.contains(node) && + Polymer.dom(this).getOwnerRoot() === Polymer.dom(node).getOwnerRoot(); + }, + + /** + * Checks whether an element is in this element's local DOM tree. + * + * @method isLocalDescendant + * @param {HTMLElement=} node The element to be checked. + * @return {Boolean} true if node is in this element's local DOM tree. + */ + isLocalDescendant: function(node) { + return this.root === Polymer.dom(node).getOwnerRoot(); } }); diff --git a/test/unit/utils-content.html b/test/unit/utils-content.html index 18ea1ab0..bbc0492e 100644 --- a/test/unit/utils-content.html +++ b/test/unit/utils-content.html @@ -26,7 +26,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
- +
@@ -37,41 +37,50 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
+ + + + + + + + + - + diff --git a/test/unit/utils-elements.html b/test/unit/utils-elements.html index 4729f91b..bb2503fd 100644 --- a/test/unit/utils-elements.html +++ b/test/unit/utils-elements.html @@ -37,4 +37,23 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer({ is: 'x-content-multi' }); - \ No newline at end of file + + + + + + + + + diff --git a/test/unit/utils.html b/test/unit/utils.html index 7a630e69..4415ce90 100644 --- a/test/unit/utils.html +++ b/test/unit/utils.html @@ -18,7 +18,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN + + + + diff --git a/test/unit/events.html b/test/unit/events.html index 518d4b97..1f8de1d0 100644 --- a/test/unit/events.html +++ b/test/unit/events.html @@ -141,6 +141,36 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN assert.deepEqual(el._removed[3], {target: 'div', event: 'bar'}); }); }); + + suite('Event Listener Cache', function() { + suiteSetup(function() { + el = document.createElement('x-double'); + document.body.appendChild(el); + el.setup(); + }); + + suiteTeardown(function() { + document.body.removeChild(el); + }); + + test('Event handler fires only once', function() { + el.fire('foo'); + assert.equal(el._warned.length, 1, 'event should fire only once'); + }); + + test('listen reuses handler cache', function() { + var expected = el._recallEventHandler(el, 'foo', el, 'missing'); + el.listen(el, 'foo', 'missing'); + var actual = el._recallEventHandler(el, 'foo', el, 'missing'); + assert.equal(actual, expected, 'function was not cached'); + }); + + test('unlisten keeps handler for caching', function() { + el.teardown(); + var fn = el._recallEventHandler(el, 'foo', el, 'missing'); + assert.ok(fn, 'should be cached'); + }); + }); }); From bf2f6941a73105674cd27f24d5ffc9dcd4b46385 Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Tue, 6 Oct 2015 15:07:30 -0700 Subject: [PATCH 018/268] add test to ensure unlisten events do not fire --- test/unit/events.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/unit/events.html b/test/unit/events.html index 1f8de1d0..d771147e 100644 --- a/test/unit/events.html +++ b/test/unit/events.html @@ -170,6 +170,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var fn = el._recallEventHandler(el, 'foo', el, 'missing'); assert.ok(fn, 'should be cached'); }); + + test('once unlistened, no handler fire', function() { + el.fire('foo'); + assert.equal(el._warned.length, 1, 'event should not be handled anymore') + }); }); }); From a2e1e648fd94ffd8a326ed85a2b12a1e75ce22ba Mon Sep 17 00:00:00 2001 From: Trevor Dixon Date: Wed, 7 Oct 2015 12:03:30 -0700 Subject: [PATCH 019/268] Make model param of stamp method optional. Otherwise the compiler requires `this.stamp(null)` or `this.stamp({})`. Might as well make it optional? --- src/lib/template/templatizer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/template/templatizer.html b/src/lib/template/templatizer.html index b06aa6c0..e0c3108b 100644 --- a/src/lib/template/templatizer.html +++ b/src/lib/template/templatizer.html @@ -373,7 +373,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * `stamp`. * * @method stamp - * @param {Object} model An object containing key/values to serve as the + * @param {Object=} model An object containing key/values to serve as the * initial data configuration for the instance. Note that properties * from the host used in the template are automatically copied into * the model. From ec59f57aa49b8b125337bd9f526203f2f9bb8375 Mon Sep 17 00:00:00 2001 From: Trevor Dixon Date: Wed, 7 Oct 2015 14:11:03 -0700 Subject: [PATCH 020/268] Allow any type, not just objects, as the detail for fire. --- src/standard/utils.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/standard/utils.html b/src/standard/utils.html index cde10497..911d2aa1 100644 --- a/src/standard/utils.html +++ b/src/standard/utils.html @@ -146,7 +146,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * * @method fire * @param {String} type Name of event type. - * @param {Object=} detail Detail object containing event-specific + * @param {*=} detail Detail object containing event-specific * payload. * @param {Object=} options Object specifying options. These may include: * `bubbles` (boolean, defaults to `true`), From f17be359fb6e1abfc396ebed3091d070431cc1de Mon Sep 17 00:00:00 2001 From: Trevor Dixon Date: Wed, 7 Oct 2015 14:13:15 -0700 Subject: [PATCH 021/268] Use 'value' in place of 'object' when referring to detail. --- src/standard/utils.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/standard/utils.html b/src/standard/utils.html index 911d2aa1..1f8e8855 100644 --- a/src/standard/utils.html +++ b/src/standard/utils.html @@ -142,11 +142,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, /** - * Dispatches a custom event with an optional detail object. + * Dispatches a custom event with an optional detail value. * * @method fire * @param {String} type Name of event type. - * @param {*=} detail Detail object containing event-specific + * @param {*=} detail Detail value containing event-specific * payload. * @param {Object=} options Object specifying options. These may include: * `bubbles` (boolean, defaults to `true`), From 2d97cd7b50d21daa2b52d243ca29827b2b4f6d78 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Wed, 7 Oct 2015 17:34:56 -0700 Subject: [PATCH 022/268] Add templatizer tests. Fix issues from tests. --- src/lib/template/templatizer.html | 14 +- src/standard/notify-path.html | 2 + test/runner.html | 1 + test/unit/templatizer-elements.html | 221 +++++++++++++++++++++++++ test/unit/templatizer.html | 241 ++++++++++++++++++++++++++++ 5 files changed, 473 insertions(+), 6 deletions(-) create mode 100644 test/unit/templatizer-elements.html create mode 100644 test/unit/templatizer.html diff --git a/src/lib/template/templatizer.html b/src/lib/template/templatizer.html index 6d209c60..edc12c1a 100644 --- a/src/lib/template/templatizer.html +++ b/src/lib/template/templatizer.html @@ -109,15 +109,15 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // archetypes do special caching this._customPrepAnnotations(archetype, template); + // forward parent properties to archetype + this._prepParentProperties(archetype, template); + // setup accessors archetype._prepEffects(); this._customPrepEffects(archetype); archetype._prepBehaviors(); archetype._prepBindings(); - // forward parent properties to archetype - this._prepParentProperties(archetype, template); - // boilerplate code archetype._notifyPath = this._notifyPathImpl; archetype._scopeElementClass = this._scopeElementClassImpl; @@ -241,10 +241,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } } // Instance setup - this._extendTemplate(template, proto); if (template != this) { Polymer.Bind.prepareInstance(template); template._forwardParentProp = this._forwardParentProp.bind(this); + } + this._extendTemplate(template, proto); + if (template != this) { template._pathEffector = this._pathEffectorTemplate.bind(this); } } @@ -259,7 +261,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _createHostPropEffector: function(prop) { var prefix = this._parentPropPrefix; return function(source, value) { - this.dataHost[prefix + prop] = value; + this.dataHost._templatized[prefix + prop] = value; }; }, @@ -299,7 +301,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // Call extension point for Templatizer sub-classes dataHost._forwardInstancePath.call(dataHost, this, path, value); if (root in dataHost._parentProps) { - dataHost.notifyPath(dataHost._parentPropPrefix + path, value); + dataHost._templatized.notifyPath(dataHost._parentPropPrefix + path, value); } }, diff --git a/src/standard/notify-path.html b/src/standard/notify-path.html index 0ec156a8..9ba2391a 100644 --- a/src/standard/notify-path.html +++ b/src/standard/notify-path.html @@ -491,7 +491,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // Base or all in Bind. prepareModelNotifyPath: function(model) { this.mixin(model, { + fire: Polymer.Base.fire, notifyPath: Polymer.Base.notifyPath, + _EVENT_CHANGED: Polymer.Base._EVENT_CHANGED, _notifyPath: Polymer.Base._notifyPath, _pathEffector: Polymer.Base._pathEffector, _annotationPathEffect: Polymer.Base._annotationPathEffect, diff --git a/test/runner.html b/test/runner.html index 0d78dec5..03dd0a85 100644 --- a/test/runner.html +++ b/test/runner.html @@ -57,6 +57,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN 'unit/styling-cross-scope-unknown-host.html', 'unit/custom-style.html', 'unit/dynamic-import.html', + 'unit/templatizer.html', 'unit/dom-repeat.html', 'unit/dom-if.html', 'unit/dom-bind.html', diff --git a/test/unit/templatizer-elements.html b/test/unit/templatizer-elements.html new file mode 100644 index 00000000..e11d033f --- /dev/null +++ b/test/unit/templatizer-elements.html @@ -0,0 +1,221 @@ + + + + + + diff --git a/test/unit/templatizer.html b/test/unit/templatizer.html new file mode 100644 index 00000000..ca5b1dab --- /dev/null +++ b/test/unit/templatizer.html @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + From 837e9b811922fe2e97410c7246a1acf184a7a578 Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Wed, 7 Oct 2015 17:55:03 -0700 Subject: [PATCH 023/268] Make sure we only actually call _listen once Gestures have counter code that should not be re-added with multiple identical `listen` calls --- src/standard/events.html | 7 +++++++ test/unit/events.html | 12 +++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/standard/events.html b/src/standard/events.html index 926c31b3..2d7bba14 100644 --- a/src/standard/events.html +++ b/src/standard/events.html @@ -85,7 +85,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (!handler) { handler = this._createEventHandler(node, eventName, methodName); } + // don't call _listen if we are already listening + if (handler._listening) { + return; + } this._listen(node, eventName, handler); + handler._listening = true; }, _boundListenerKey: function(eventName, methodName) { @@ -129,6 +134,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN methodName + '` not defined')); } }; + handler._listening = false; this._recordEventHandler(host, eventName, node, methodName, handler); return handler; }, @@ -148,6 +154,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var handler = this._recallEventHandler(this, eventName, node, methodName); if (handler) { this._unlisten(node, eventName, handler); + handler._listening = false; } }, diff --git a/test/unit/events.html b/test/unit/events.html index d771147e..3ffb4745 100644 --- a/test/unit/events.html +++ b/test/unit/events.html @@ -153,6 +153,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN document.body.removeChild(el); }); + test('listen marks event handler as listening', function() { + var handler = el._recallEventHandler(el, 'foo', el, 'missing'); + assert.equal(handler._listening, true, 'handler should be marked'); + }); + test('Event handler fires only once', function() { el.fire('foo'); assert.equal(el._warned.length, 1, 'event should fire only once'); @@ -171,9 +176,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN assert.ok(fn, 'should be cached'); }); + test('unlisten markes cached handler as not listening', function() { + var handler = el._recallEventHandler(el, 'foo', el, 'missing'); + assert.equal(handler._listening, false, 'handler should not be listening'); + }); + test('once unlistened, no handler fire', function() { el.fire('foo'); - assert.equal(el._warned.length, 1, 'event should not be handled anymore') + assert.equal(el._warned.length, 1, 'event should not be handled anymore'); }); }); }); From 45fcbcf76152e3258bd924e9761b599600c3f07b Mon Sep 17 00:00:00 2001 From: Trevor Dixon Date: Wed, 7 Oct 2015 21:23:08 -0700 Subject: [PATCH 024/268] Missing var keyword --- src/lib/template/array-selector.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/template/array-selector.html b/src/lib/template/array-selector.html index 613b898f..84fe2e05 100644 --- a/src/lib/template/array-selector.html +++ b/src/lib/template/array-selector.html @@ -197,7 +197,7 @@ is false, `selected` is a property representing the last selected item. When } } else { this.push('selected', item); - skey = this._selectedColl.getKey(item); + var skey = this._selectedColl.getKey(item); this.linkPaths('selected.' + skey, 'items.' + key); } } else { From e4c24335b55f193c7c5f29998d1dbc1e510b1655 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Thu, 8 Oct 2015 10:13:18 -0700 Subject: [PATCH 025/268] Add issue link. --- src/standard/notify-path.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/standard/notify-path.html b/src/standard/notify-path.html index 9ba2391a..3c804acd 100644 --- a/src/standard/notify-path.html +++ b/src/standard/notify-path.html @@ -488,7 +488,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // TODO(kschaaf): This is the path analogue to Polymer.Bind.prepareModel, // which provides API for path-based notification on elements with property // effects; this should be re-factored along with the Bind lib, either all on - // Base or all in Bind. + // Base or all in Bind (see issue https://github.com/Polymer/polymer/issues/2547). prepareModelNotifyPath: function(model) { this.mixin(model, { fire: Polymer.Base.fire, From 1a89bcf39eef9290f4266e14e88df757fd325ab3 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Thu, 8 Oct 2015 10:13:36 -0700 Subject: [PATCH 026/268] Clean up templatizer _pathEffectorImpl. --- src/lib/template/templatizer.html | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/lib/template/templatizer.html b/src/lib/template/templatizer.html index edc12c1a..549bb8ee 100644 --- a/src/lib/template/templatizer.html +++ b/src/lib/template/templatizer.html @@ -246,9 +246,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN template._forwardParentProp = this._forwardParentProp.bind(this); } this._extendTemplate(template, proto); - if (template != this) { - template._pathEffector = this._pathEffectorTemplate.bind(this); - } + template._pathEffector = this._pathEffectorImpl.bind(this, template); } }, @@ -306,22 +304,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, // Overrides Base notify-path module - _pathEffector: function(path, value, fromAbove) { + _pathEffectorImpl: function(template, path, value, fromAbove) { if (this._forwardParentPath) { if (path.indexOf(this._parentPropPrefix) === 0) { - this._forwardParentPath(path.substring(8), value); - } - } - Polymer.Base._pathEffector.apply(this, arguments); - }, - - // Overrides Base notify-path module (for non-PE templates) - _pathEffectorTemplate: function(path, value, fromAbove) { - if (this._forwardParentPath) { - if (path.indexOf(this._parentPropPrefix) === 0) { - this._forwardParentPath(path.substring(8), value); + var subPath = path.substring(this._parentPropPrefix.length); + this._forwardParentPath(subPath, value); } } + Polymer.Base._pathEffector.call(template, path, value, fromAbove); }, _constructorImpl: function(model, host) { From 79dfe1fe3c60a302c0f9774f859ab0f71d85767f Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Thu, 8 Oct 2015 10:17:45 -0700 Subject: [PATCH 027/268] Simplify --- src/lib/template/templatizer.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/template/templatizer.html b/src/lib/template/templatizer.html index 549bb8ee..0d006e98 100644 --- a/src/lib/template/templatizer.html +++ b/src/lib/template/templatizer.html @@ -246,7 +246,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN template._forwardParentProp = this._forwardParentProp.bind(this); } this._extendTemplate(template, proto); - template._pathEffector = this._pathEffectorImpl.bind(this, template); + template._pathEffector = this._pathEffectorImpl.bind(this); } }, @@ -304,14 +304,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, // Overrides Base notify-path module - _pathEffectorImpl: function(template, path, value, fromAbove) { + _pathEffectorImpl: function(path, value, fromAbove) { if (this._forwardParentPath) { if (path.indexOf(this._parentPropPrefix) === 0) { var subPath = path.substring(this._parentPropPrefix.length); this._forwardParentPath(subPath, value); } } - Polymer.Base._pathEffector.call(template, path, value, fromAbove); + Polymer.Base._pathEffector.call(this._templatized, path, value, fromAbove); }, _constructorImpl: function(model, host) { From 574855a644bcc25ee26c30e0dd881a395fad67b6 Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Thu, 8 Oct 2015 14:05:54 -0700 Subject: [PATCH 028/268] prepare release 1.1.5 --- bower.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 8bc57dfe..a7d4b0a7 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "polymer", - "version": "1.1.4", + "version": "1.1.5", "main": [ "polymer.html" ], diff --git a/package.json b/package.json index 2143ec81..51733dcd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Polymer", - "version": "1.1.4", + "version": "1.1.5", "description": "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 write", "main": "polymer.html", "directories": { From b2b23c462e8167429d26cdece58ee3881526b567 Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Thu, 8 Oct 2015 14:16:07 -0700 Subject: [PATCH 029/268] update CHANGELOG to 1.1.5 --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3db06504..0e0e0e17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # Change Log +##[v1.1.5](https://github.com/Polymer/polymer/tree/v1.1.5) (2015-10-08) +- Simplify ([commit](https://github.com/Polymer/polymer/commit/79dfe1f)) + +- Clean up templatizer _pathEffectorImpl. ([commit](https://github.com/Polymer/polymer/commit/1a89bcf)) + +- Add issue link. ([commit](https://github.com/Polymer/polymer/commit/e4c2433)) + +- Missing var keyword ([commit](https://github.com/Polymer/polymer/commit/45fcbcf)) + +- Make sure we only actually call _listen once ([commit](https://github.com/Polymer/polymer/commit/837e9b8)) + +- Add templatizer tests. Fix issues from tests. ([commit](https://github.com/Polymer/polymer/commit/2d97cd7)) + +- Use 'value' in place of 'object' when referring to detail. ([commit](https://github.com/Polymer/polymer/commit/f17be35)) + +- Allow any type, not just objects, as the detail for fire. ([commit](https://github.com/Polymer/polymer/commit/ec59f57)) + +- Make model param of stamp method optional. ([commit](https://github.com/Polymer/polymer/commit/a2e1e64)) + +- add test to ensure unlisten events do not fire ([commit](https://github.com/Polymer/polymer/commit/bf2f694)) + +- add tests ([commit](https://github.com/Polymer/polymer/commit/900d82b)) + +- Only one real listener per `listen` call ([commit](https://github.com/Polymer/polymer/commit/8bd380a)) + +- add util method for shadow children ([commit](https://github.com/Polymer/polymer/commit/1e9110a)) + +- Add notify-path API to templatized template. Fixes #2505. ([commit](https://github.com/Polymer/polymer/commit/2e086fe)) + +- Parent property values should come from template. Fixes #2504. ([commit](https://github.com/Polymer/polymer/commit/23c883b)) + +- Added note about including a clear repro case. ([commit](https://github.com/Polymer/polymer/commit/e18f009)) + +- added request to submit an issue before sending a PR ([commit](https://github.com/Polymer/polymer/commit/6ed836f)) + +- update CHANGELOG to 1.1.4 ([commit](https://github.com/Polymer/polymer/commit/c2b7c31)) + ##[v1.1.4](https://github.com/Polymer/polymer/tree/v1.1.4) (2015-09-25) - :memo: Update description ([commit](https://github.com/Polymer/polymer/commit/6afb8be)) From 85d8a3a7276a00c4e6a584bc05826a98540f1492 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Mon, 27 Jul 2015 23:00:48 -0700 Subject: [PATCH 030/268] Denote keys with # to disambiguate from index. Fixes #2007. --- src/lib/collection.html | 20 ++++++++-- src/standard/notify-path.html | 18 +++++++-- test/unit/notify-path-elements.html | 2 + test/unit/notify-path.html | 62 ++++++++++++++++++++++------- 4 files changed, 79 insertions(+), 23 deletions(-) diff --git a/src/lib/collection.html b/src/lib/collection.html index 0e68e38b..e89fc1d2 100644 --- a/src/lib/collection.html +++ b/src/lib/collection.html @@ -46,10 +46,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } else { this.pmap[item] = key; } - return key; + return '#' + key; }, removeKey: function(key) { + key = this._parseKey(key); this._removeFromMap(this.store[key]); delete this.store[key]; }, @@ -70,17 +71,27 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN getKey: function(item) { if (item && typeof item == 'object') { - return this.omap.get(item); + return '#' + this.omap.get(item); } else { - return this.pmap[item]; + return '#' + this.pmap[item]; } }, getKeys: function() { - return Object.keys(this.store); + return Object.keys(this.store).map(function(key) { + return '#' + key; + }); + }, + + _parseKey: function(key) { + if (key[0] == '#') { + return key.slice(1); + } + throw new Error('unexpected key ' + key); }, setItem: function(key, item) { + key = this._parseKey(key); var old = this.store[key]; if (old) { this._removeFromMap(old); @@ -94,6 +105,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, getItem: function(key) { + key = this._parseKey(key); return this.store[key]; }, diff --git a/src/standard/notify-path.html b/src/standard/notify-path.html index 3c804acd..af58b91d 100644 --- a/src/standard/notify-path.html +++ b/src/standard/notify-path.html @@ -195,14 +195,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN get: function(path, root) { var prop = root || this; var parts = this._getPathParts(path); - var last = parts.pop(); - while (parts.length) { - prop = prop[parts.shift()]; + var array; + for (var i=0; i From 85c23e191545b2efb828f198e7c948c41cdfa74f Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Wed, 30 Sep 2015 14:56:39 -0700 Subject: [PATCH 031/268] Fix merge issue. --- test/unit/notify-path.html | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/notify-path.html b/test/unit/notify-path.html index 73d1a25e..2cc0d363 100644 --- a/test/unit/notify-path.html +++ b/test/unit/notify-path.html @@ -1153,7 +1153,6 @@ suite('path API', function() { assert.strictEqual(el.array[3], 'orig3'); }); -<<<<<<< HEAD test('link two objects', function() { var aChanged = 0; var bChanged = 0; From 10021cc51c3f2bb113039d80e6ad1fd35e3f4ed4 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Wed, 30 Sep 2015 17:56:22 -0700 Subject: [PATCH 032/268] Improvements to path API. Fixes #2509. * Allows `set` to take paths with array #keys * Allows `notifyPath` to take paths with array indices * Exposes public notifySplices API --- src/lib/bind/accessors.html | 2 +- src/lib/collection.html | 8 +- src/lib/template/array-selector.html | 1 + src/lib/template/dom-if.html | 2 +- src/lib/template/dom-repeat.html | 6 +- src/lib/template/templatizer.html | 4 +- src/standard/notify-path.html | 139 ++++++++++++++++++++++----- test/unit/array-selector.html | 10 +- test/unit/notify-path.html | 46 +++++++++ 9 files changed, 178 insertions(+), 40 deletions(-) diff --git a/src/lib/bind/accessors.html b/src/lib/bind/accessors.html index 3c769ecc..4d82b56e 100644 --- a/src/lib/bind/accessors.html +++ b/src/lib/bind/accessors.html @@ -212,7 +212,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return function(e, target) { if (!bogusTest(e, target)) { if (e.detail && e.detail.path) { - this.notifyPath(this._fixPath(path, property, e.detail.path), + this._notifyPath(this._fixPath(path, property, e.detail.path), e.detail.value); } else { var value = target[property]; diff --git a/src/lib/collection.html b/src/lib/collection.html index e89fc1d2..fc3bdbe2 100644 --- a/src/lib/collection.html +++ b/src/lib/collection.html @@ -70,10 +70,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, getKey: function(item) { + var key; if (item && typeof item == 'object') { - return '#' + this.omap.get(item); + key = this.omap.get(item); } else { - return '#' + this.pmap[item]; + key = this.pmap[item]; + } + if (key != undefined) { + return '#' + key; } }, diff --git a/src/lib/template/array-selector.html b/src/lib/template/array-selector.html index 84fe2e05..f728e3fd 100644 --- a/src/lib/template/array-selector.html +++ b/src/lib/template/array-selector.html @@ -130,6 +130,7 @@ is false, `selected` is a property representing the last selected item. When } } else { this.unlinkPaths('selected'); + this.unlinkPaths('selectedItem'); } // Initialize selection if (this.multi) { diff --git a/src/lib/template/dom-if.html b/src/lib/template/dom-if.html index 7c5e0491..56ab20a3 100644 --- a/src/lib/template/dom-if.html +++ b/src/lib/template/dom-if.html @@ -160,7 +160,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // notifying parent. path change on each row _forwardParentPath: function(path, value) { if (this._instance) { - this._instance.notifyPath(path, value, true); + this._instance._notifyPath(path, value, true); } } diff --git a/src/lib/template/dom-repeat.html b/src/lib/template/dom-repeat.html index ee3e99ed..0a56ed78 100644 --- a/src/lib/template/dom-repeat.html +++ b/src/lib/template/dom-repeat.html @@ -605,7 +605,7 @@ Then the `observe` property should be configured as follows: // for notifying items.. change up to host _forwardInstancePath: function(inst, path, value) { if (path.indexOf(this.as + '.') === 0) { - this.notifyPath('items.' + inst.__key__ + '.' + + this._notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1), value); } }, @@ -624,7 +624,7 @@ Then the `observe` property should be configured as follows: // notifying parent path change on each inst _forwardParentPath: function(path, value) { this._instances.forEach(function(inst) { - inst.notifyPath(path, value, true); + inst._notifyPath(path, value, true); }, this); }, @@ -639,7 +639,7 @@ Then the `observe` property should be configured as follows: if (inst) { if (dot >= 0) { path = this.as + '.' + path.substring(dot+1); - inst.notifyPath(path, value, true); + inst._notifyPath(path, value, true); } else { inst.__setProperty(this.as, value, true); } diff --git a/src/lib/template/templatizer.html b/src/lib/template/templatizer.html index 37478f59..9466bca2 100644 --- a/src/lib/template/templatizer.html +++ b/src/lib/template/templatizer.html @@ -119,7 +119,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN archetype._prepBindings(); // boilerplate code - archetype._notifyPath = this._notifyPathImpl; + archetype._notifyPathUp = this._notifyPathUpImpl; archetype._scopeElementClass = this._scopeElementClassImpl; archetype.listen = this._listenImpl; archetype._showHideChildren = this._showHideChildrenImpl; @@ -292,7 +292,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // _forwardParentPath: function(path, value) { }, // _forwardParentProp: function(prop, value) { }, - _notifyPathImpl: function(path, value) { + _notifyPathUpImpl: function(path, value) { var dataHost = this.dataHost; var dot = path.indexOf('.'); var root = dot < 0 ? path : path.slice(0, dot); diff --git a/src/standard/notify-path.html b/src/standard/notify-path.html index af58b91d..a8801f6d 100644 --- a/src/standard/notify-path.html +++ b/src/standard/notify-path.html @@ -65,10 +65,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.Base._addFeature({ /** - * Notify that a path has changed. For example: + * Notify that a path has changed. * - * this.item.user.name = 'Bob'; - * this.notifyPath('item.user.name', this.item.user.name); + * Example: + * + * this.item.user.name = 'Bob'; + * this.notifyPath('item.user.name', this.item.user.name); * * @param {string} path Path that should be notified. * @param {*} value Value of the specified path. @@ -79,6 +81,15 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * based on a dirty check of whether the new value was already known. */ notifyPath: function(path, value, fromAbove) { + // Convert any array indicies to keys before notifying path + var info = {}; + path = this.get(path, this, info); + // Notify change to key-based path + this._notifyPath(info.path, value, fromAbove); + }, + + // Note: this implemetation only accepts key-based array paths + _notifyPath: function(path, value, fromAbove) { var old = this._propertySetter(path, value); // manual dirty checking for now... // NaN is always not equal to itself, @@ -94,7 +105,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // is coming from above already (avoid wasted event dispatch) if (!fromAbove) { // TODO(sorvell): should only notify if notify: true? - this._notifyPath(path, value); + this._notifyPathUp(path, value); } // console.groupEnd((this.localName || this.dataHost.id + '-' + this.dataHost.dataHost.index) + '#' + (this.id || this.index) + ' ' + path, value); return true; @@ -146,29 +157,56 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var array; var last = parts[parts.length-1]; if (parts.length > 1) { + // Loop over path parts[0..n-2] and dereference for (var i=0; i Date: Wed, 30 Sep 2015 18:02:39 -0700 Subject: [PATCH 033/268] Fix typo in comments. --- src/standard/notify-path.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/standard/notify-path.html b/src/standard/notify-path.html index a8801f6d..f3913840 100644 --- a/src/standard/notify-path.html +++ b/src/standard/notify-path.html @@ -81,7 +81,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * based on a dirty check of whether the new value was already known. */ notifyPath: function(path, value, fromAbove) { - // Convert any array indicies to keys before notifying path + // Convert any array indices to keys before notifying path var info = {}; path = this.get(path, this, info); // Notify change to key-based path @@ -146,7 +146,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * or an array of path parts (e.g. `['foo.bar', 'baz']`). Note that * bracketed expressions are not supported; string-based path parts * *must* be separated by dots. Note that when dereferencing array - * indicies, the index may be used as a dotted part directly + * indices, the index may be used as a dotted part directly * (e.g. `users.12.name` or `['users', 12, 'name']`). * @param {*} value Value to set at the specified path. * @param {Object=} root Root object from which the path is evaluated. @@ -167,7 +167,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // Get item from simple property dereference prop = prop[part]; if (array && (parseInt(part) == part)) { - // Translate array indicies to collection keys for path notificaiton + // Translate array indices to collection keys for path notificaiton parts[i] = Polymer.Collection.get(array).getKey(prop); } } @@ -185,7 +185,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // Dereference index & lookup collection key var old = prop[last]; var key = coll.getKey(old); - // Translate array indicies to collection keys for path notificaiton + // Translate array indices to collection keys for path notificaiton parts[i] = key; // Replace item associated with key in collection coll.setItem(key, value); @@ -224,11 +224,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * or an array of path parts (e.g. `['foo.bar', 'baz']`). Note that * bracketed expressions are not supported; string-based path parts * *must* be separated by dots. Note that when dereferencing array - * indicies, the index may be used as a dotted part directly + * indices, the index may be used as a dotted part directly * (e.g. `users.12.name` or `['users', 12, 'name']`). * @param {Object=} root Root object from which the path is evaluated. * @param {Object=} info Info object; if supplied, a `path` property - * will be added containing path with array indicies converted to keys + * will be added containing path with array indices converted to keys * @return {*} Value at the path, or `undefined` if any part of the path * is undefined. */ @@ -249,7 +249,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // Part was index; simple dereference prop = prop[part]; if (info && array && (parseInt(part) == part)) { - // Translate array indicies to collection keys for path notificaiton + // Translate array indices to collection keys for path notificaiton parts[i] = Polymer.Collection.get(array).getKey(prop); } } From 883aa5c8be4428e23fa9db08ab8486cecc982cba Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Thu, 20 Aug 2015 02:16:35 +0200 Subject: [PATCH 034/268] Fix for mixins declaration with space before colon. Allow any space character or even `{` and `}` (before and after capturing pattern correspondingly) as pattern boundaries instead of new lines only. In minified sources there might be no space, semicolon or line start, so we need to account that as well. --- src/lib/css-parse.html | 18 +++++------ src/lib/style-properties.html | 34 ++++++++++---------- test/unit/custom-style.html | 60 +++++++++++++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 29 deletions(-) diff --git a/src/lib/css-parse.html b/src/lib/css-parse.html index a176d7c1..33285734 100644 --- a/src/lib/css-parse.html +++ b/src/lib/css-parse.html @@ -43,7 +43,7 @@ Polymer.CssParse = (function() { n = {start: i+1, parent: p, previous: previous}; p.rules.push(n); break; - case this.CLOSE_BRACE: + case this.CLOSE_BRACE: //console.groupEnd(n.start); n.end = i+1; n = n.parent || root; @@ -84,9 +84,9 @@ Polymer.CssParse = (function() { if (r$) { for (var i=0, l=r$.length, r; (i .zazz { - border: 20px solid blue; + border: 20px solid blue; } @@ -126,6 +134,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN + + + +

@@ -180,12 +192,32 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN + + + + + + + + + + \ No newline at end of file + From 1026498e9e870cc11d52ac968f77e38ef3a49d76 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Fri, 31 Jul 2015 21:44:24 -0700 Subject: [PATCH 038/268] Store binding parts in notes. --- src/lib/annotations/annotations.html | 121 ++++++++++++++++----------- src/lib/bind/effects.html | 10 +-- src/standard/annotations.html | 35 +++++--- src/standard/effectBuilder.html | 51 ++++++----- 4 files changed, 133 insertions(+), 84 deletions(-) diff --git a/src/lib/annotations/annotations.html b/src/lib/annotations/annotations.html index c5db7949..790faf21 100644 --- a/src/lib/annotations/annotations.html +++ b/src/lib/annotations/annotations.html @@ -88,26 +88,75 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this._parseElementAnnotations(node, list); }, - _testEscape: function(value) { - var escape = value.slice(0, 2); - if (escape === '{{' || escape === '[[') { - return escape; + _bindingRegex: /([^{[]*)({{|\[\[)([^}\]]*)(?:]]|}})/g, + + _parseBindings: function(text) { + var re = this._bindingRegex; + var parts = []; + var m, lastIndex; + // Example: "literal1{{binding1}}literal2[[binding2]]final" + // Regex matches: + // Iteration 1: Iteration 2: + // m[1]: 'literal1' 'literal2' + // m[2]: '{{' '[[' + // m[3]: 'binding1' 'binding2' + // 'final' is manually substring'ed from end + while ((m = re.exec(text)) !== null) { + // Add literal part + if (m[1]) { + parts.push({literal: m[1]}); + } + // Add binding part + // Mode (one-way or two) + var mode = m[2][0]; + var value = m[3].trim(); + // Negate + var negate = false; + if (value[0] == '!') { + negate = true; + value = value.substring(1); + } + var customEvent, notifyEvent, colon; + if (mode == '{' && (colon = value.indexOf('::')) > 0) { + notifyEvent = value.substring(colon + 2); + value = value.substring(0, colon); + customEvent = true; + } + parts.push({ + compoundIndex: parts.length, + value: value, + mode: mode, + negate: negate, + event: notifyEvent, + customEvent: customEvent + }); + lastIndex = re.lastIndex; + } + // Add a final literal part + if (lastIndex && lastIndex < text.length) { + var literal = text.substring(lastIndex); + if (literal) { + parts.push({ + literal: literal + }); + } + } + if (parts.length) { + return parts; } }, // add annotations gleaned from TextNode `node` to `list` _parseTextNodeAnnotation: function(node, list) { - var v = node.textContent; - var escape = this._testEscape(v); - if (escape) { + var parts = this._parseBindings(node.textContent); + if (parts) { // NOTE: use a space here so the textNode remains; some browsers // (IE) evacipate an empty textNode. node.textContent = ' '; var annote = { bindings: [{ kind: 'text', - mode: escape[0], - value: v.slice(2, -2).trim() + parts: parts }] }; list.push(annote); @@ -152,7 +201,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN !node.hasAttribute('preserve-content')) { this._parseTemplate(node, i, list, annote); } - // collapse adjacent textNodes: fixes an IE issue that can cause + // collapse adjacent textNodes: fixes an IE issue that can cause // text nodes to be inexplicably split =( // note that root.normalize() should work but does not so we do this // manually. @@ -203,13 +252,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // `annotation data` is not as clear as it could be _parseNodeAttributeAnnotations: function(node, annotation) { for (var i=node.attributes.length-1, a; (a=node.attributes[i]); i--) { - var n = a.name, v = a.value; - // id (unless actually an escaped binding annotation) - if (n === 'id' && !this._testEscape(v)) { - annotation.id = v; - } + var n = a.name; + var v = a.value; + var b; // events (on-*) - else if (n.slice(0, 3) === 'on-') { + if (n.slice(0, 3) === 'on-') { node.removeAttribute(n); annotation.events.push({ name: n.slice(3), @@ -217,44 +264,27 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }); } // bindings (other attributes) - else { - var b = this._parseNodeAttributeAnnotation(node, n, v); - if (b) { - annotation.bindings.push(b); - } + else if (b = this._parseNodeAttributeAnnotation(node, n, v)) { + annotation.bindings.push(b); + } + // static id + else if (n === 'id') { + annotation.id = v; } } }, // construct annotation data from a generic attribute, or undefined _parseNodeAttributeAnnotation: function(node, n, v) { - var escape = this._testEscape(v); - if (escape) { - var customEvent; - // Cache name (`n` will be mangled) - var name = n; - // Mode (one-way or two) - var mode = escape[0]; - v = v.slice(2, -2).trim(); - // Negate - var not = false; - if (v[0] == '!') { - v = v.substring(1); - not = true; - } + var parts = this._parseBindings(v); + if (parts) { // Attribute or property + var name = n; var kind = 'property'; if (n[n.length-1] == '$') { name = n.slice(0, -1); kind = 'attribute'; } - // Custom notification event - var notifyEvent, colon; - if (mode == '{' && (colon = v.indexOf('::')) > 0) { - notifyEvent = v.substring(colon + 2); - v = v.substring(0, colon); - customEvent = true; - } // Clear attribute before removing, since IE won't allow removing // `value` attribute if it previously had a value (can't // unconditionally set '' before removing since attributes with `$` @@ -273,12 +303,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } return { kind: kind, - mode: mode, name: name, - value: v, - negate: not, - event: notifyEvent, - customEvent: customEvent + parts: parts, + isCompound: parts.length !== 1 }; } }, diff --git a/src/lib/bind/effects.html b/src/lib/bind/effects.html index eb6a80ac..b6056643 100644 --- a/src/lib/bind/effects.html +++ b/src/lib/bind/effects.html @@ -14,10 +14,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _shouldAddListener: function(effect) { return effect.name && - effect.mode === '{' && - !effect.negate && - effect.kind != 'attribute' - ; + effect.kind != 'attribute' && + !effect.isCompound && + effect.parts[0].mode === '{' && + !effect.parts[0].negate; }, _annotationEffect: function(source, value, effect) { @@ -77,7 +77,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (args) { var fn = this[effect.method]; if (fn) { - this.__setProperty(effect.property, fn.apply(this, args)); + this.__setProperty(effect.name, fn.apply(this, args)); } else { this._warn(this._logf('_computeEffect', 'compute method `' + effect.method + '` not defined')); diff --git a/src/standard/annotations.html b/src/standard/annotations.html index 06f81bd0..4842f713 100644 --- a/src/standard/annotations.html +++ b/src/standard/annotations.html @@ -139,9 +139,14 @@ TODO(sjmiles): this module should produce either syntactic metadata // Parse bindings for methods & path roots (models) for (var j=0; j.on.-changed: = e.detail.value Polymer.Bind._addAnnotatedListener(this, index, - note.name, note.value, note.event); + note.name, note.parts[0].value, note.parts[0].event); } - if (note.signature) { - this._addAnnotatedComputationEffect(note, index); - } else { - // capture the node index - note.index = index; - // add 'annotation' binding effect for property 'model' - this._addPropertyEffect(note.model, 'annotation', note); + for (var i=0; i Date: Fri, 31 Jul 2015 22:56:29 -0700 Subject: [PATCH 039/268] Apply effect value from compound parts. --- src/lib/annotations/annotations.html | 4 +- src/lib/bind/effects.html | 8 +- src/standard/annotations.html | 21 +++++ src/standard/effectBuilder.html | 19 ++++- test/unit/bind-elements.html | 11 +++ test/unit/bind.html | 119 ++++++++++++++++++++++++--- 6 files changed, 162 insertions(+), 20 deletions(-) diff --git a/src/lib/annotations/annotations.html b/src/lib/annotations/annotations.html index 790faf21..663a7ab8 100644 --- a/src/lib/annotations/annotations.html +++ b/src/lib/annotations/annotations.html @@ -156,7 +156,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var annote = { bindings: [{ kind: 'text', - parts: parts + name: 'textContent', + parts: parts, + isCompound: parts.length !== 1 }] }; list.push(annote); diff --git a/src/lib/bind/effects.html b/src/lib/bind/effects.html index b6056643..ceeb3fdf 100644 --- a/src/lib/bind/effects.html +++ b/src/lib/bind/effects.html @@ -20,6 +20,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN !effect.parts[0].negate; }, + _compoundInitializationEffect: function(source, value, effect) { + this._applyEffectValue(effect); + }, + _annotationEffect: function(source, value, effect) { if (source != effect.value) { value = this._get(effect.value); @@ -30,7 +34,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // are used, since the target element may not dirty check (e.g. ) if (!effect.customEvent || this._nodes[effect.index][effect.name] !== calc) { - return this._applyEffectValue(calc, effect); + return this._applyEffectValue(effect, calc); } }, @@ -95,7 +99,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (effect.negate) { computedvalue = !computedvalue; } - this._applyEffectValue(computedvalue, effect); + this._applyEffectValue(effect, computedvalue); } } else { computedHost._warn(computedHost._logf('_annotatedComputationEffect', diff --git a/src/standard/annotations.html b/src/standard/annotations.html index 4842f713..8e969de4 100644 --- a/src/standard/annotations.html +++ b/src/standard/annotations.html @@ -221,6 +221,7 @@ TODO(sjmiles): this module should produce either syntactic metadata // push configuration references at configure time _configureAnnotationReferences: function() { this._configureTemplateContent(); + this._configureCompoundBindings(); }, // nested template contents have been stored prototypically to avoid @@ -236,6 +237,26 @@ TODO(sjmiles): this module should produce either syntactic metadata }, this); }, + // Compound bindings utilize private storage on the node to store + // the current state of each value that will be concatenated to generate + // the final property/attribute/text value + // Here we initialize the private storage array on the node with any + // literal parts that won't change (could get fancy and use WeakMap) + _configureCompoundBindings: function() { + this._notes.forEach(function(note, i) { + var node = this._nodes[i]; + note.bindings.forEach(function(binding) { + if (binding.isCompound) { + var storage = node.__compoundStorage__ || + (node.__compoundStorage__ = {}); + storage[binding.name] = binding.parts.map(function(part) { + return part.literal; + }); + } + }); + }, this); + }, + // construct `$` map (from id annotations) _marshalIdNodes: function() { this.$ = {}; diff --git a/src/standard/effectBuilder.html b/src/standard/effectBuilder.html index b976fefc..cd35fd98 100644 --- a/src/standard/effectBuilder.html +++ b/src/standard/effectBuilder.html @@ -150,6 +150,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }); } } + // We need to ensure compound bindings with literals push the literals + // through regardless of whether annotation dependencies initialized + // this is done with a special compoundInitialization effect which simply + // kicks _applyEffectValue to push the literals through + if (note.isCompound) { + note.index = index; + this._addPropertyEffect('__static__', 'compoundInitialization', note); + } }, _addAnnotatedComputationEffect: function(note, part, index) { @@ -262,11 +270,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.Bind.setupBindListeners(this); }, - _applyEffectValue: function(value, info) { + _applyEffectValue: function(info, value) { var node = this._nodes[info.index]; - // TODO(sorvell): ideally, the info object is normalized for easy - // lookup here. - var property = info.name || 'textContent'; + var property = info.name; + if (info.isCompound) { + var storage = node.__compoundStorage__[property]; + storage[info.compoundIndex] = value; + value = storage.join(''); + } // special processing for 'class' and 'className'; 'class' handled // when attr is serialized. if (info.kind == 'attribute') { diff --git a/test/unit/bind-elements.html b/test/unit/bind-elements.html index 250feae7..129997a7 100644 --- a/test/unit/bind-elements.html +++ b/test/unit/bind-elements.html @@ -24,6 +24,10 @@ computed-from-tricky-literals2='{{computeFromTrickyLiterals(3,"tricky\,'zot'" )}}' computed-from-no-args="{{computeFromNoArgs( )}}" no-computed="{{foobared(noInlineComputed)}}" + compound1="{{cpnd1}}{{ cpnd2 }}{{cpnd3.prop}}{{ computeCompound(cpnd4, cpnd5, 'literal')}}" + compound2="literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literal')}} literal4" + compoundAttr1$="{{cpnd1}}{{ cpnd2 }}{{cpnd3.prop}}{{ computeCompound(cpnd4, cpnd5, 'literal')}}" + compoundAttr2$="literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literal')}} literal4" > Test @@ -31,6 +35,10 @@ {{computeFromTrickyLiterals(3, 'tricky\,\'zot\'')}} +
{{cpnd1}}{{cpnd2}}{{cpnd3.prop}}{{computeCompound(cpnd4, cpnd5, 'literal')}}
+
+ literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literal')}} literal4 +
diff --git a/test/unit/bind.html b/test/unit/bind.html index 3a003841..26164360 100644 --- a/test/unit/bind.html +++ b/test/unit/bind.html @@ -688,22 +688,115 @@ suite('warnings', function() { }); - - - - - From 1035e2db4f222c3f642c416cc6e47c158ba8ed8d Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Fri, 9 Oct 2015 15:53:55 -0700 Subject: [PATCH 040/268] Exclude compound bindings from configure; revisit later. --- src/standard/configure.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/standard/configure.html b/src/standard/configure.html index c6f0551b..62fd8cf1 100644 --- a/src/standard/configure.html +++ b/src/standard/configure.html @@ -131,7 +131,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var fx = fx$[p]; if (fx) { for (var i=0, l=fx.length, x; (i Date: Fri, 9 Oct 2015 19:07:37 -0700 Subject: [PATCH 041/268] Remove compound binding limitation from primer. --- PRIMER.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/PRIMER.md b/PRIMER.md index 3b76f218..51c8c51f 100644 --- a/PRIMER.md +++ b/PRIMER.md @@ -3,7 +3,7 @@
Below is a description of current Polymer features, followed by individual feature guides. -See [the full Polymer.Base API documentation](http://polymer.github.io/polymer/) for details on specific methods and properties. +See [the full Polymer.Base API documentation](http://polymer.github.io/polymer/) for details on specific methods and properties. **Basic Custom Element sugaring** @@ -1085,17 +1085,10 @@ Polymer({ Properties of the custom element may be bound into text content or properties of local DOM elements using binding annotations in the template. -To bind to textContent, the binding annotation must currently span the entire content of the tag: - ```html + + + + + + + + + + From d2c02a9310b816df0a6cda58acb1c8a11eddb22f Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 2 Nov 2015 17:21:56 -0800 Subject: [PATCH 107/268] Avoid using .slice and .forEach --- src/lib/base.html | 5 +++-- src/lib/collection.html | 12 +++++------ src/lib/dom-api.html | 14 ++++--------- src/lib/settings.html | 5 +++-- src/lib/style-util.html | 4 ++-- src/lib/template/dom-bind.html | 2 +- src/lib/template/dom-if.html | 10 ++++----- src/lib/template/dom-repeat.html | 36 +++++++++++++++++--------------- src/standard/annotations.html | 12 +++++------ src/standard/notify-path.html | 9 ++++---- src/standard/styling.html | 8 +++---- 11 files changed, 58 insertions(+), 59 deletions(-) diff --git a/src/lib/base.html b/src/lib/base.html index c7239103..ae84efab 100644 --- a/src/lib/base.html +++ b/src/lib/base.html @@ -78,9 +78,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN */ extend: function(prototype, api) { if (prototype && api) { - Object.getOwnPropertyNames(api).forEach(function(n) { + var n$ = Object.getOwnPropertyNames(api); + for (var i=0, n; (i=0; i--) { @@ -619,18 +619,20 @@ Then the `observe` property should be configured as follows: // Called as side-effect of a host property change, responsible for // notifying parent path change on each inst _forwardParentProp: function(prop, value) { - this._instances.forEach(function(inst) { + var i$ = this._instances; + for (var i=0, inst; (i. path change, diff --git a/src/standard/annotations.html b/src/standard/annotations.html index d162897e..60012335 100644 --- a/src/standard/annotations.html +++ b/src/standard/annotations.html @@ -181,10 +181,10 @@ TODO(sjmiles): this module should produce either syntactic metadata // templates. _discoverTemplateParentProps: function(notes) { var pp = {}; - notes.forEach(function(n) { + for (var i=0, n; (i Date: Mon, 2 Nov 2015 17:23:40 -0800 Subject: [PATCH 108/268] memoize pathFn on effect (note: notifyPath change made in previous commit); avoid forEach. --- src/standard/effectBuilder.html | 43 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/standard/effectBuilder.html b/src/standard/effectBuilder.html index 72d2865a..c96308ff 100644 --- a/src/standard/effectBuilder.html +++ b/src/standard/effectBuilder.html @@ -12,7 +12,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN From a2376b6e953f139d52d2b6caa68dd6700f956881 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 2 Nov 2015 17:24:44 -0800 Subject: [PATCH 109/268] provides support for memoizing pathFn on effect; only process effects/listeners if they exist. --- src/lib/bind/accessors.html | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/lib/bind/accessors.html b/src/lib/bind/accessors.html index 352e8e6d..1b854b98 100644 --- a/src/lib/bind/accessors.html +++ b/src/lib/bind/accessors.html @@ -14,10 +14,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _dataEventCache: {}, // for prototypes (usually) - prepareModel: function(model) { - model._propertyEffects = {}; - model._bindListeners = []; Polymer.Base.mixin(model, this._modelApi); }, @@ -106,6 +103,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // a prepared model can acquire effects ensurePropertyEffects: function(model, property) { + if (!model._propertyEffects) { + model._propertyEffects = {}; + } var fx = model._propertyEffects[property]; if (!fx) { fx = model._propertyEffects[property] = []; @@ -115,11 +115,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN addPropertyEffect: function(model, property, kind, effect) { var fx = this.ensurePropertyEffects(model, property); - fx.push({ + var propEffect = { kind: kind, effect: effect, fn: Polymer.Bind['_' + kind + 'Effect'] - }); + }; + fx.push(propEffect); + return propEffect; }, createBindings: function(model) { @@ -193,6 +195,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _addAnnotatedListener: function(model, index, property, path, event) { + if (!model._bindListeners) { + model._bindListeners = []; + } var fn = this._notedListenerFactory(property, path, this._isStructured(path)); var eventName = event || From 66df196696dffcec76e0cee4fc7f44ef888b36e3 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 2 Nov 2015 17:26:05 -0800 Subject: [PATCH 110/268] lazily create effect objects so we can more easily abort processing. avoid forEach --- src/micro/attributes.html | 23 ++++++++++++-------- src/micro/behaviors.html | 43 ++++++++++++++++++------------------- src/micro/properties.html | 9 +++++--- src/standard/x-styling.html | 4 ++-- 4 files changed, 43 insertions(+), 36 deletions(-) diff --git a/src/micro/attributes.html b/src/micro/attributes.html index 3a5a4b1f..73eadb16 100644 --- a/src/micro/attributes.html +++ b/src/micro/attributes.html @@ -60,18 +60,19 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.Base._addFeature({ - _prepAttributes: function() { - this._aggregatedAttributes = {}; - }, - _addHostAttributes: function(attributes) { + if (!this._aggregatedAttributes) { + this._aggregatedAttributes = {}; + } if (attributes) { this.mixin(this._aggregatedAttributes, attributes); } }, _marshalHostAttributes: function() { - this._applyAttributes(this, this._aggregatedAttributes); + if (this._aggregatedAttributes) { + this._applyAttributes(this, this._aggregatedAttributes); + } }, /* apply attributes to node but avoid overriding existing values */ @@ -83,8 +84,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (!this.hasAttribute(n) && (n !== 'class')) { var v = attr$[n]; this.serializeValueToAttribute(v, n, this); + // TODO(sorvell): this should not be in micro layer. // if necessary, add this value to configuration... - if (!this._clientsReady && this._propertyInfo[n] && + if (!this._clientsReadied && this._propertyInfo[n] && (this._config[n] === undefined)) { this._config[n] = v; } @@ -161,9 +163,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // this._warn(this._logf('serializeValueToAttribute', // 'serializing long attribute values can lead to poor performance', this)); // } - (node || this) - [str === undefined ? 'removeAttribute' : 'setAttribute'] - (attribute, str); + node = node || this; + if (str === undefined) { + node.removeAttribute(attribute); + } else { + node.setAttribute(attribute, str); + } }, /** diff --git a/src/micro/behaviors.html b/src/micro/behaviors.html index ca5ca853..160df135 100644 --- a/src/micro/behaviors.html +++ b/src/micro/behaviors.html @@ -79,7 +79,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _flattenBehaviorsList: function(behaviors) { var flat = []; - behaviors.forEach(function(b) { + for (var i=0; i < behaviors.length; i++) { + var b = behaviors[i]; if (b instanceof Array) { flat = flat.concat(this._flattenBehaviorsList(b)); } @@ -89,32 +90,17 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } else { this._warn(this._logf('_flattenBehaviorsList', 'behavior is null, check for missing or 404 import')); } - }, this); + } return flat; }, _mixinBehavior: function(b) { - Object.getOwnPropertyNames(b).forEach(function(n) { - switch (n) { - case 'hostAttributes': - case 'registered': - case 'properties': - case 'observers': - case 'listeners': - case 'created': - case 'attached': - case 'detached': - case 'attributeChanged': - case 'configure': - case 'ready': - break; - default: - if (!this.hasOwnProperty(n)) { - this.copyOwnProperty(n, b, this); - } - break; + var n$ = Object.getOwnPropertyNames(b); + for (var i=0, n; (i diff --git a/src/micro/properties.html b/src/micro/properties.html index 92156c32..2b4633a5 100644 --- a/src/micro/properties.html +++ b/src/micro/properties.html @@ -108,9 +108,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN getPropertyInfo: function(property) { var info = this._getPropertyInfo(property, this.properties); if (!info) { - this.behaviors.some(function(b) { - return info = this._getPropertyInfo(property, b.properties); - }, this); + for (var i=0; i < this.behaviors.length; i++) { + info = this._getPropertyInfo(property, this.behaviors[i].properties); + if (info) { + return info; + } + }; } return info || Polymer.nob; }, diff --git a/src/standard/x-styling.html b/src/standard/x-styling.html index 2975eeb9..aeb6543f 100644 --- a/src/standard/x-styling.html +++ b/src/standard/x-styling.html @@ -31,7 +31,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // if it has any _stylePropertyNames this._ownStylePropertyNames = this._styles ? propertyUtils.decorateStyles(this._styles) : - []; + null; }, /** @@ -40,7 +40,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * (analogous to setting `style`) and then calling `updateStyles()`. * */ - customStyle: {}, + customStyle: null, // here we have an instance time spot to put custom property data _setupStyleProperties: function() { From e0fbfbe688e00293117dbc8c6a811668d3c1ea1f Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 2 Nov 2015 17:26:58 -0800 Subject: [PATCH 111/268] avoid configuration work when unnecessary --- polymer-micro.html | 2 -- polymer-mini.html | 21 +++++++++--------- polymer.html | 33 ++++++++++++++------------- src/lib/template/templatizer.html | 8 ++++--- src/mini/ready.html | 37 +++++++++++++++++-------------- src/standard/configure.html | 4 +++- 6 files changed, 57 insertions(+), 48 deletions(-) diff --git a/polymer-micro.html b/polymer-micro.html index f443f865..3914a91e 100644 --- a/polymer-micro.html +++ b/polymer-micro.html @@ -27,8 +27,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _registerFeatures: function() { // identity this._prepIs(); - // attributes - this._prepAttributes(); // shared behaviors this._prepBehaviors(); // factory diff --git a/polymer-mini.html b/polymer-mini.html index 668fb545..cfd2b47c 100644 --- a/polymer-mini.html +++ b/polymer-mini.html @@ -24,8 +24,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _registerFeatures: function() { // identity this._prepIs(); - // attributes - this._prepAttributes(); // shared behaviors this._prepBehaviors(); // factory @@ -43,14 +41,17 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _initFeatures: function() { - // manage local dom - this._poolContent(); - // host stack - this._pushHost(); - // instantiate template - this._stampTemplate(); - // host stack - this._popHost(); + this._calcHost(); + if (this._template) { + // manage local dom + this._poolContent(); + // host stack + this._beginHost(); + // instantiate template + this._stampTemplate(); + // host stack + this._popHost(); + } // install host attributes this._marshalHostAttributes(); // setup debouncers diff --git a/polymer.html b/polymer.html index 823d8906..46b62ff9 100644 --- a/polymer.html +++ b/polymer.html @@ -28,8 +28,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _registerFeatures: function() { // identity this._prepIs(); - // attributes - this._prepAttributes(); // factory this._prepConstructor(); // template @@ -59,37 +57,42 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _initFeatures: function() { - // manage local dom - this._poolContent(); // manage configuration this._setupConfigure(); // setup style properties this._setupStyleProperties(); - // host stack - this._pushHost(); - // instantiate template - this._stampTemplate(); - // host stack - this._popHost(); - // concretize template references - this._marshalAnnotationReferences(); // setup debouncers this._setupDebouncers(); + this._calcHost(); + if (this._template) { + // manage local dom + this._poolContent(); + // host stack + this._beginHost(); + // instantiate template + this._stampTemplate(); + // host stack + this._popHost(); + // concretize template references + this._marshalAnnotationReferences(); + } // concretize effects on instance this._marshalInstanceEffects(); // acquire instance behaviors this._marshalBehaviors(); - // install host attributes - this._marshalHostAttributes(); // acquire initial instance attribute values this._marshalAttributes(); + // install host attributes + this._marshalHostAttributes(); // top-down initial distribution, configuration, & ready callback this._tryReady(); }, _marshalBehavior: function(b) { // establish listeners on instance - this._listenListeners(b.listeners); + if (b.listeners) { + this._listenListeners(b.listeners); + } } }); diff --git a/src/lib/template/templatizer.html b/src/lib/template/templatizer.html index dd35ccfa..b8bf0c7b 100644 --- a/src/lib/template/templatizer.html +++ b/src/lib/template/templatizer.html @@ -288,14 +288,15 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // Similar to Polymer.Base.extend, but retains any previously set instance // values (_propertySetter back on instance once accessor is installed) _extendTemplate: function(template, proto) { - Object.getOwnPropertyNames(proto).forEach(function(n) { + var n$ = Object.getOwnPropertyNames(proto); + for (var i=0, n; (i Date: Tue, 3 Nov 2015 03:07:52 +0100 Subject: [PATCH 112/268] Fix for multiple consequent spaces present in CSS selectors, fixes #2670 --- src/lib/css-parse.html | 2 ++ test/unit/css-parse.html | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/lib/css-parse.html b/src/lib/css-parse.html index 33285734..74e4dd07 100644 --- a/src/lib/css-parse.html +++ b/src/lib/css-parse.html @@ -60,6 +60,7 @@ Polymer.CssParse = (function() { if (node.parent) { var ss = node.previous ? node.previous.end : node.parent.start; t = text.substring(ss, node.start-1); + t = t.replace(this._rx.multipleSpaces, ' '); // TODO(sorvell): ad hoc; make selector include only after last ; // helps with mixin syntax t = t.substring(t.lastIndexOf(';')+1); @@ -162,6 +163,7 @@ Polymer.CssParse = (function() { mixinApply: /@apply[\s]*\([^)]*?\)[\s]*(?:[;\n]|$)?/gim, varApply: /[^;:]*?:[^;]*var[^;]*(?:[;\n]|$)?/gim, keyframesRule: /^@[^\s]*keyframes/, + multipleSpaces: /\s+/g }, VAR_START: '--', diff --git a/test/unit/css-parse.html b/test/unit/css-parse.html index 36172ae7..39d6444b 100644 --- a/test/unit/css-parse.html +++ b/test/unit/css-parse.html @@ -60,6 +60,15 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } /* comment */ + + From 05a1e9583df3d4ca8490f5b0d0cc89a02ac8b522 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Tue, 3 Nov 2015 12:37:24 +0100 Subject: [PATCH 113/268] Fix using value$ on input element --- src/lib/annotations/annotations.html | 2 +- test/unit/bind-elements.html | 36 ++++++++++++++++------------ test/unit/bind.html | 12 +++++++++- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/lib/annotations/annotations.html b/src/lib/annotations/annotations.html index fe03ea65..8b23976c 100644 --- a/src/lib/annotations/annotations.html +++ b/src/lib/annotations/annotations.html @@ -313,7 +313,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // `value` attribute if it previously had a value (can't // unconditionally set '' before removing since attributes with `$` // can't be set using setAttribute) - if (node.localName == 'input' && name == 'value') { + if (node.localName === 'input' && origName === 'value') { node.setAttribute(origName, ''); } // Remove annotation diff --git a/test/unit/bind-elements.html b/test/unit/bind-elements.html index 1c5b36c4..1ff37417 100644 --- a/test/unit/bind-elements.html +++ b/test/unit/bind-elements.html @@ -434,20 +434,26 @@ - - + + - + } + }); + + + + + diff --git a/test/unit/bind.html b/test/unit/bind.html index 842b0073..6769651b 100644 --- a/test/unit/bind.html +++ b/test/unit/bind.html @@ -16,7 +16,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN - + + + + diff --git a/test/unit/gestures.html b/test/unit/gestures.html index e77a45e3..5165ea95 100644 --- a/test/unit/gestures.html +++ b/test/unit/gestures.html @@ -12,7 +12,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN - + @@ -386,6 +386,26 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }); }); }); + + suite('SD Polyfill', function() { + var el; + setup(function() { + el = document.createElement('x-document-listener'); + document.body.appendChild(el); + el.setup(); + }); + + teardown(function() { + el.teardown(); + document.body.removeChild(el); + }); + + test('document listener works in SD polyfill', function() { + var ev = new CustomEvent('mousedown', {bubbles: true}); + el.dispatchEvent(ev); + assert.equal(el.stream.length, 1); + }); + }); From d82840b17fa41e1eb1c1ebba8024ee255e555714 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Wed, 4 Nov 2015 16:07:31 -0800 Subject: [PATCH 115/268] rename host functions fix typos afterFirstRender is now raf+setTimeout dom-repeat: remove cruft --- polymer-mini.html | 6 +++--- polymer.html | 6 +++--- src/lib/bind/accessors.html | 17 +++++++++++++---- src/lib/collection.html | 6 +++--- src/lib/dom-api.html | 7 +------ src/lib/render-status.html | 9 ++------- src/lib/style-util.html | 2 +- src/lib/template/dom-repeat.html | 21 +++++++++------------ src/lib/template/templatizer.html | 29 +++++------------------------ src/micro/attributes.html | 5 ++++- src/micro/behaviors.html | 7 +++++-- src/micro/properties.html | 8 +++++++- src/mini/ready.html | 6 +++--- src/mini/shady.html | 1 + src/standard/annotations.html | 12 ++++++------ src/standard/configure.html | 5 ----- src/standard/effectBuilder.html | 5 +---- src/standard/styling.html | 4 ++-- src/standard/x-styling.html | 5 +++-- 19 files changed, 72 insertions(+), 89 deletions(-) diff --git a/polymer-mini.html b/polymer-mini.html index cfd2b47c..cf03ceff 100644 --- a/polymer-mini.html +++ b/polymer-mini.html @@ -41,16 +41,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _initFeatures: function() { - this._calcHost(); + this._registerHost(); if (this._template) { // manage local dom this._poolContent(); // host stack - this._beginHost(); + this._beginHosting(); // instantiate template this._stampTemplate(); // host stack - this._popHost(); + this._endHosting(); } // install host attributes this._marshalHostAttributes(); diff --git a/polymer.html b/polymer.html index 46b62ff9..3510433a 100644 --- a/polymer.html +++ b/polymer.html @@ -63,16 +63,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this._setupStyleProperties(); // setup debouncers this._setupDebouncers(); - this._calcHost(); + this._registerHost(); if (this._template) { // manage local dom this._poolContent(); // host stack - this._beginHost(); + this._beginHosting(); // instantiate template this._stampTemplate(); // host stack - this._popHost(); + this._endHosting(); // concretize template references this._marshalAnnotationReferences(); } diff --git a/src/lib/bind/accessors.html b/src/lib/bind/accessors.html index 1b854b98..4704c2b4 100644 --- a/src/lib/bind/accessors.html +++ b/src/lib/bind/accessors.html @@ -248,13 +248,22 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // Property listeners: // .on.-changed: = e.detail.value //console.log('[_setupBindListener]: [%s][%s] listening for [%s][%s-changed]', this.localName, info.path, info.id || info.index, info.property); - this._addNotifyListener(inst._nodes[info.index], inst, info); + // + // TODO(sorvell): fix templatizer to support this before uncommenting + // Optimization: only add bind listeners if the bound property is notifying... + var node = inst._nodes[info.index]; + //var p = node._propertyInfo && node._propertyInfo[info.property]; + //if (node._prepParentProperties || !node._propertyInfo || (p && p.notify)) { + this._addNotifyListener(node, inst, info.event, info.changedFn); + //} }; }, - _addNotifyListener: function(element, context, info) { - element.addEventListener(info.event, function(e) { - return context._notifyListener(info.changedFn, e); + // TODO(sorvell): note, adding these synchronously may impact performance, + // measure and consider if we can defer until after first paint in some cases at least. + _addNotifyListener: function(element, context, event, changedFn) { + element.addEventListener(event, function(e) { + return context._notifyListener(changedFn, e); }); } }; diff --git a/src/lib/collection.html b/src/lib/collection.html index 3a8ebd6a..71cd6913 100644 --- a/src/lib/collection.html +++ b/src/lib/collection.html @@ -131,14 +131,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // corresponding to the added/removed items _applySplices: function(splices) { // Dedupe added and removed keys to a final added/removed map - var keyMap = {}, key, i; + var keyMap = {}, key; for (var i=0, s; (i> 1; var midKey = this._instances[mid].__key__; - var cmp = sortFn(c.getItem(midKey), item); + var cmp = this._sortFn(c.getItem(midKey), item); if (cmp < 0) { start = mid + 1; } else if (cmp > 0) { diff --git a/src/lib/template/templatizer.html b/src/lib/template/templatizer.html index b8bf0c7b..1adc6834 100644 --- a/src/lib/template/templatizer.html +++ b/src/lib/template/templatizer.html @@ -248,16 +248,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.Bind._createAccessors(proto, parentProp, effects); } } + // capture this reference for use below + var self = this; // Instance setup if (template != this) { Polymer.Bind.prepareInstance(template); - var self = this; template._forwardParentProp = function(source, value) { self._forwardParentProp(source, value); } } this._extendTemplate(template, proto); - var self = this; template._pathEffector = function(path, value, fromAbove) { return self._pathEffectorImpl(path, value, fromAbove); } @@ -332,12 +332,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _constructorImpl: function(model, host) { this._rootDataHost = host._getRootDataHost(); this._setupConfigure(model); - this._calcHost(host); - this._beginHost(); + this._registerHost(host); + this._beginHosting(); this.root = this.instanceTemplate(this._template); this.root.__noContent = !this._notes._hasContent; this.root.__styleScoped = true; - this._popHost(); + this._endHosting(); this._marshalAnnotatedNodes(); this._marshalInstanceEffects(); this._marshalAnnotatedListeners(); @@ -450,25 +450,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } } - // TODO(sorvell): note, using the template as host is ~5-10% faster if - // elements have no default values. - // _constructorImpl: function(model, host) { - // this._setupConfigure(model); - // host._beginHost(); - // this.root = this.instanceTemplate(this._template); - // host._popHost(); - // this._marshalTemplateContent(); - // this._marshalAnnotatedNodes(); - // this._marshalInstanceEffects(); - // this._marshalAnnotatedListeners(); - // this._ready(); - // }, - - // stamp: function(model) { - // return new this.ctor(model, this.dataHost); - // } - - }; diff --git a/src/micro/attributes.html b/src/micro/attributes.html index 73eadb16..2f68da48 100644 --- a/src/micro/attributes.html +++ b/src/micro/attributes.html @@ -60,6 +60,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.Base._addFeature({ + // prototype time _addHostAttributes: function(attributes) { if (!this._aggregatedAttributes) { this._aggregatedAttributes = {}; @@ -69,6 +70,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } }, + // instance time _marshalHostAttributes: function() { if (this._aggregatedAttributes) { this._applyAttributes(this, this._aggregatedAttributes); @@ -88,7 +90,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // if necessary, add this value to configuration... if (!this._clientsReadied && this._propertyInfo[n] && (this._config[n] === undefined)) { - this._config[n] = v; + this._configValue(n, v); } } } @@ -114,6 +116,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (!this._serializing) { var property = property || Polymer.CaseMap.dashToCamelCase(attribute); // fallback to property lookup + // TODO(sorvell): check for _propertyInfo existence because of dom-bind info = info || (this._propertyInfo && this._propertyInfo[property]); if (info && !info.readOnly) { var v = this.getAttribute(attribute); diff --git a/src/micro/behaviors.html b/src/micro/behaviors.html index 160df135..ad4945b0 100644 --- a/src/micro/behaviors.html +++ b/src/micro/behaviors.html @@ -97,7 +97,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _mixinBehavior: function(b) { var n$ = Object.getOwnPropertyNames(b); for (var i=0, n; (i Date: Wed, 4 Nov 2015 17:09:17 -0800 Subject: [PATCH 116/268] revert host attributes ordering change optimization as it was not worth the trouble (barely measurable and more cumbersome impl). --- polymer.html | 10 ++++++++-- src/lib/base.html | 2 ++ src/micro/attributes.html | 6 ------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/polymer.html b/polymer.html index 3510433a..547eaaec 100644 --- a/polymer.html +++ b/polymer.html @@ -80,10 +80,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this._marshalInstanceEffects(); // acquire instance behaviors this._marshalBehaviors(); - // acquire initial instance attribute values - this._marshalAttributes(); + /* + TODO(sorvell): It's *slightly() more efficient to marshal attributes prior + to installing hostAttributes, but then hostAttributes must be separately + funneled to configure, which is cumbersome. + Since this delta seems hard to measure we will not bother atm. + */ // install host attributes this._marshalHostAttributes(); + // acquire initial instance attribute values + this._marshalAttributes(); // top-down initial distribution, configuration, & ready callback this._tryReady(); }, diff --git a/src/lib/base.html b/src/lib/base.html index ae84efab..10f6b4d4 100644 --- a/src/lib/base.html +++ b/src/lib/base.html @@ -59,6 +59,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // reserved for canonical behavior attributeChangedCallback: function(name, oldValue, newValue) { + // TODO(sorvell): consider filtering out changes to host attributes + // note: this was barely measurable with 3 host attributes. this._attributeChangedImpl(name); // abstract this._doBehavior('attributeChanged', [name, oldValue, newValue]); // abstract }, diff --git a/src/micro/attributes.html b/src/micro/attributes.html index 2f68da48..8622f97e 100644 --- a/src/micro/attributes.html +++ b/src/micro/attributes.html @@ -86,12 +86,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (!this.hasAttribute(n) && (n !== 'class')) { var v = attr$[n]; this.serializeValueToAttribute(v, n, this); - // TODO(sorvell): this should not be in micro layer. - // if necessary, add this value to configuration... - if (!this._clientsReadied && this._propertyInfo[n] && - (this._config[n] === undefined)) { - this._configValue(n, v); - } } } }, From 0233d6deaffeaa0e617e0a48f006b609dd6aa1d9 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Wed, 4 Nov 2015 17:12:54 -0800 Subject: [PATCH 117/268] fix line endings. --- src/lib/dom-api.html | 1988 +++++++++++++++++++++--------------------- 1 file changed, 994 insertions(+), 994 deletions(-) diff --git a/src/lib/dom-api.html b/src/lib/dom-api.html index 36fdfc20..ac5a7a07 100644 --- a/src/lib/dom-api.html +++ b/src/lib/dom-api.html @@ -1,995 +1,995 @@ - - - - \ No newline at end of file From d53ab5736f72edf8b5cbc50de60fb12afd1eef89 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Wed, 4 Nov 2015 17:18:26 -0800 Subject: [PATCH 118/268] add back deepContains (got removed incorrectly in merge). --- src/lib/dom-api.html | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/lib/dom-api.html b/src/lib/dom-api.html index ac5a7a07..875054bc 100644 --- a/src/lib/dom-api.html +++ b/src/lib/dom-api.html @@ -52,6 +52,28 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom.flush(); }, + /** + * Check that the given node is a descendant of `this`, + * ignoring ShadowDOM boundaries + * @param {Node} node + * @return {Boolean} true if `node` is a descendant or equal to `this` + */ + deepContains: function(node) { + // fast path, use shallow `contains`. + if (this.node.contains(node)) { + return true; + } + var n = node; + // wrap document for SD polyfill + var wrappedDocument = wrap(document); + // walk from node to `this` or `document` + while (n && n !== wrappedDocument && n !== this.node) { + // use logical parentnode, or native ShadowRoot host + n = Polymer.dom(n).parentNode || n.host; + } + return n === this.node; + }, + _lazyDistribute: function(host) { // note: only try to distribute if the root is not clean; this ensures // we don't distribute before initial distribution From f447c0eb70b48574eb26aa5a33245e13df60347d Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Wed, 4 Nov 2015 17:39:42 -0800 Subject: [PATCH 119/268] Remove limit & chunkCount API. Refactor insert/remove. --- src/lib/template/dom-repeat.html | 224 ++++++++++------------ test/unit/dom-repeat-elements.html | 4 +- test/unit/dom-repeat.html | 290 ++++++++++++++--------------- 3 files changed, 243 insertions(+), 275 deletions(-) diff --git a/src/lib/template/dom-repeat.html b/src/lib/template/dom-repeat.html index 78af69c0..db74fa96 100644 --- a/src/lib/template/dom-repeat.html +++ b/src/lib/template/dom-repeat.html @@ -190,19 +190,6 @@ Then the `observe` property should be configured as follows: */ delay: Number, - /** - * When `limit` is defined, the number of actually rendered template - * instances will be limited to this count. - * - * Note that if `initialCount` is used, the `limit` property will be - * automatically controlled and should not be set by the user. - */ - limit: { - value: Infinity, - type: Number, - observer: '_limitChanged' - }, - /** * Defines an initial count of template instances to render after setting * the `items` array, before the next paint, and puts the `dom-repeat` @@ -213,28 +200,16 @@ Then the `observe` property should be configured as follows: */ initialCount: { type: Number, - value: 0 + observer: '_initializeChunking' }, /** - * When `initialCount` is used, defines the number of instances to be - * created at each animation frame after rendering the `initialCount`. - * When left to the default `'auto'` value, the chunk count will be - * throttled automatically using a best effort scheme to maintain the - * value of the `targetFramerate` property. - */ - chunkCount: { - type: Number, - value: 'auto' - }, - - /** - * When `initialCount` is used and `chunkCount` is set to `'auto'`, this - * property defines a frame rate to target by throttling the number of - * instances rendered each frame to not exceed the budget for the target - * frame rate. Setting this to a higher number will allow lower latency - * and higher throughput for things like event handlers, but will result - * in a longer time for the remaining items to complete rendering. + * When `initialCount` is used, this property defines a frame rate to + * target by throttling the number of instances rendered each frame to + * not exceed the budget for the target frame rate. Setting this to a + * higher number will allow lower latency and higher throughput for + * things like event handlers, but will result in a longer time for the + * remaining items to complete rendering. */ targetFramerate: { type: Number, @@ -252,32 +227,29 @@ Then the `observe` property should be configured as follows: ], observers: [ - '_itemsChanged(items.*)', - '_initializeChunkCount(initialCount, chunkCount)' + '_itemsChanged(items.*)' ], created: function() { this._instances = []; this._pool = []; - this._boundRenderChunk = this._renderChunk.bind(this); + this._limit = Infinity; + var self = this; + this._boundRenderChunk = function() { + self._renderChunk(); + }; }, detached: function() { for (var i=0; i=0; i--) { var inst = this._instances[i]; - if (inst.isPlaceholder && i=this.limit) { - inst = this._insertRow(i, inst.__key__, true, true); + if (inst.isPlaceholder && i=this._limit) { + inst = this._downgradeInstance(i, inst.__key__); } keyToIdx[inst.__key__] = i; if (!inst.isPlaceholder) { @@ -514,16 +482,16 @@ Then the `observe` property should be configured as follows: var inst = this._instances[i]; if (inst) { inst.__key__ = key; - if (!inst.isPlaceholder && i < this.limit) { + if (!inst.isPlaceholder && i < this._limit) { inst.__setProperty(this.as, c.getItem(key), true); } } else { - this._insertRow(i, key); + this._insertPlaceholder(i, key); } } // Remove any extra instances from previous state for (var j=this._instances.length-1; j>=i; j--) { - this._detachRow(j); + this._removeInstance(j); } }, @@ -576,7 +544,7 @@ Then the `observe` property should be configured as follows: var idx = removedIdxs[i]; // Removed idx may be undefined if item was previously filtered out if (idx !== undefined) { - this._detachRow(idx); + this._removeInstance(idx); } } } @@ -624,7 +592,7 @@ Then the `observe` property should be configured as follows: idx = end + 1; } // Insert instance at insertion point - this._insertRow(idx, key); + this._insertPlaceholder(idx, key); return idx; }, @@ -638,65 +606,48 @@ Then the `observe` property should be configured as follows: splices.forEach(function(s) { // Detach & pool removed instances for (var i=0; i= this.limit) { - inst = { - isPlaceholder: true, - __key__: key - }; - } else { - if (inst = this._pool.pop()) { - // TODO(kschaaf): If the pool is shared across turns, parentProps - // need to be re-set to reused instances in addition to item/key - inst.__setProperty(this.as, this.collection.getItem(key), true); - inst.__setProperty('__key__', key, true); - } else { - inst = this._generateRow(idx, key); - } - var beforeRow = this._instances[replace ? idx + 1 : idx]; - var beforeNode = beforeRow && !beforeRow.isPlaceholder ? beforeRow._children[0] : this; - var parentNode = Polymer.dom(this).parentNode; - Polymer.dom(parentNode).insertBefore(inst.root, beforeNode); + _attachInstance: function(idx, parent) { + var inst = this._instances[idx]; + if (!inst.isPlaceholder) { + parent.insertBefore(inst.root, this); } - if (replace) { - if (makePlaceholder) { - this._detachRow(idx, true); - } - this._instances[idx] = inst; - } else { - this._instances.splice(idx, 0, inst); - } - return inst; }, - _generateRow: function(idx, key) { + _removeInstance: function(idx) { + var inst = this._detachInstance(idx); + if (inst) { + this._pool.push(inst); + } + this._instances.splice(idx, 1); + }, + + _insertPlaceholder: function(idx, key) { + this._instances.splice(idx, 0, { + isPlaceholder: true, + __key__: key + }); + }, + + _generateInstance: function(idx, key) { var model = { __key__: key }; @@ -706,6 +657,37 @@ Then the `observe` property should be configured as follows: return inst; }, + _upgradePlaceholder: function(idx, key) { + var inst = this._pool.pop(); + if (inst) { + // TODO(kschaaf): If the pool is shared across turns, parentProps + // need to be re-set to reused instances in addition to item/key + inst.__setProperty(this.as, this.collection.getItem(key), true); + inst.__setProperty('__key__', key, true); + } else { + inst = this._generateInstance(idx, key); + } + var beforeRow = this._instances[idx + 1 ]; + var beforeNode = beforeRow && !beforeRow.isPlaceholder ? beforeRow._children[0] : this; + var parentNode = Polymer.dom(this).parentNode; + Polymer.dom(parentNode).insertBefore(inst.root, beforeNode); + this._instances[idx] = inst; + return inst; + }, + + _downgradeInstance: function(idx, key) { + var inst = this._detachInstance(idx); + if (inst) { + this._pool.push(inst); + } + inst = { + isPlaceholder: true, + __key__: key + }; + this._instances[idx] = inst; + return inst; + }, + // Implements extension point from Templatizer mixin _showHideChildren: function(hidden) { for (var i=0; i + + From fa96ff302057ccf56cce9da398573b585cd958a2 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Fri, 6 Nov 2015 15:28:23 -0800 Subject: [PATCH 139/268] Update test to avoid template polypill issues. --- test/unit/dom-if.html | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/unit/dom-if.html b/test/unit/dom-if.html index 12b0c05a..1050514d 100644 --- a/test/unit/dom-if.html +++ b/test/unit/dom-if.html @@ -56,10 +56,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN - + + +
+
+
+ + From a9704934a2fbdb2fccbbe3e705e7b4c198b0ffd9 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 13 Nov 2015 15:19:22 -0800 Subject: [PATCH 158/268] Simplify custom-style property deferment. --- src/lib/custom-style.html | 14 ++++++++++++-- src/lib/render-status.html | 11 +---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/lib/custom-style.html b/src/lib/custom-style.html index ff791d65..b3c86533 100644 --- a/src/lib/custom-style.html +++ b/src/lib/custom-style.html @@ -145,8 +145,18 @@ Note, all features of `custom-style` are available when defining styles as part // Allow all custom-styles defined in this turn to register // before applying any properties. This helps ensure that all properties // are defined before any are consumed. - Polymer.RenderStatus.beforeNextRender(this, - this._applyCustomProperties, [e]); + // Premature application of properties can occur in 2 cases: + // (1) A property is consumed in a style created before it is produced. + // In general, we require custom properties to be defined before usage + // for elements so this case is only to be slightly more like native + // custom properties where this construction is supported. + // (2) A set of in order styles (A, B) are re-ordered due to a parser + // yield A wait for textContent, making B go before A. This case + // can occur with native or polyflled webcomponents. + var self = this; + requestAnimationFrame(function() { + self._applyCustomProperties(e); + }); } }, diff --git a/src/lib/render-status.html b/src/lib/render-status.html index 493c76dd..c4735260 100644 --- a/src/lib/render-status.html +++ b/src/lib/render-status.html @@ -50,8 +50,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _afterNextRenderQueue: [], - _beforeNextRenderQueue: [], - _waitingNextRender: false, afterNextRender: function(element, fn, args) { @@ -59,11 +57,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this._afterNextRenderQueue.push([element, fn, args]); }, - beforeNextRender: function(element, fn, args) { - this._watchNextRender(); - this._beforeNextRenderQueue.push([element, fn, args]); - }, - _watchNextRender: function() { if (!this._waitingNextRender) { this._waitingNextRender = true; @@ -79,14 +72,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _flushNextRender: function() { - this._waitingNextRender = false; - this._flushRenderCallbacks(this._beforeNextRenderQueue); - this._beforeNextRenderQueue = []; var self = this; // we want to defer after render until just after the paint. setTimeout(function() { self._flushRenderCallbacks(self._afterNextRenderQueue); self._afterNextRenderQueue = []; + self._waitingNextRender = false; }); }, From 27e1dcdc640a871d018956e33cbd2c2cf4369a93 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 13 Nov 2015 15:27:13 -0800 Subject: [PATCH 159/268] Update comment. --- src/lib/custom-style.html | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/lib/custom-style.html b/src/lib/custom-style.html index b3c86533..123fff06 100644 --- a/src/lib/custom-style.html +++ b/src/lib/custom-style.html @@ -146,13 +146,16 @@ Note, all features of `custom-style` are available when defining styles as part // before applying any properties. This helps ensure that all properties // are defined before any are consumed. // Premature application of properties can occur in 2 cases: - // (1) A property is consumed in a style created before it is produced. - // In general, we require custom properties to be defined before usage - // for elements so this case is only to be slightly more like native - // custom properties where this construction is supported. + // (1) A property `--foo` is consumed in a custom-style + // before another custom-style produces `--foo`. + // In general, we require custom properties to be defined before being + // used in elements so supporting this for custom-style + // is dubious but is slightly more like native properties where this + // is supported. // (2) A set of in order styles (A, B) are re-ordered due to a parser - // yield A wait for textContent, making B go before A. This case - // can occur with native or polyflled webcomponents. + // yield that makes A wait for textContent. This reorders its + // `_apply` after B. + // This case should only occur with native webcomponents. var self = this; requestAnimationFrame(function() { self._applyCustomProperties(e); From 4bf0e13b916a847452725dbdf13ed49291fd96be Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 13 Nov 2015 16:05:53 -0800 Subject: [PATCH 160/268] Defer property application only when a custom-style is first created. --- src/lib/custom-style.html | 19 ++++++++++++++----- test/unit/custom-style.html | 20 ++++++++------------ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/lib/custom-style.html b/src/lib/custom-style.html index 123fff06..98476106 100644 --- a/src/lib/custom-style.html +++ b/src/lib/custom-style.html @@ -116,12 +116,12 @@ Note, all features of `custom-style` are available when defining styles as part // we may not have any textContent yet due to parser yielding // if so, wait until we do... if (e.textContent || this.include) { - this._apply(); + this._apply(true); } else { var self = this; var observer = new MutationObserver(function() { observer.disconnect(); - self._apply(); + self._apply(true); }); observer.observe(e, {childList: true}); } @@ -131,7 +131,7 @@ Note, all features of `custom-style` are available when defining styles as part // polyfill this style with root scoping and // apply custom properties! - _apply: function() { + _apply: function(deferProperties) { // used applied element from HTMLImports polyfill or this var e = this.__appliedElement || this; if (this.include) { @@ -157,9 +157,18 @@ Note, all features of `custom-style` are available when defining styles as part // `_apply` after B. // This case should only occur with native webcomponents. var self = this; - requestAnimationFrame(function() { + function fn() { self._applyCustomProperties(e); - }); + } + if (this._pendingApplyProperties) { + cancelAnimationFrame(this._pendingApplyProperties); + this._pendingApplyProperties = null; + } + if (deferProperties) { + this._pendingApplyProperties = requestAnimationFrame(fn); + } else { + fn(); + } } }, diff --git a/test/unit/custom-style.html b/test/unit/custom-style.html index 65630f2a..058bc8e0 100644 --- a/test/unit/custom-style.html +++ b/test/unit/custom-style.html @@ -359,17 +359,15 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN assertComputed(m, '4px'); }); - test('dynamic custom-styles apply', function(done) { + test('dynamic custom-styles apply', function() { var dynamic = document.querySelector('.dynamic'); assertComputed(dynamic, '0px'); var ds = document.createElement('style', 'custom-style'); ds.textContent = ':root { --dynamic: 11px solid orange; }'; document.head.appendChild(ds); + CustomElements.takeRecords(); Polymer.updateStyles(); - Polymer.RenderStatus.afterNextRender(null, function() { - assertComputed(dynamic, '11px'); - done(); - }); + assertComputed(dynamic, '11px'); }); test('custom-styles apply normal and property values to elements and cannot be late bound via inheritance', function() { @@ -409,7 +407,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN document.body.removeChild(style); }); - test('imperative custom style with include', function(done) { + test('imperative custom style with include', function() { var style = document.createElement('style', 'custom-style'); style.include = 'shared-style2'; var d = document.createElement('div'); @@ -417,12 +415,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN document.body.appendChild(d); document.body.appendChild(style); CustomElements.takeRecords(); - Polymer.RenderStatus.afterNextRender(null, function() { - assertComputed(d, '16px'); - document.body.removeChild(d); - document.body.removeChild(style); - done(); - }); + Polymer.updateStyles(); + assertComputed(d, '16px'); + document.body.removeChild(d); + document.body.removeChild(style); }); test('imperative custom style with non-existent include', function() { From 134766f7b3d8937d6b11d4a7af7e4d6096e3cd3d Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 13 Nov 2015 16:20:42 -0800 Subject: [PATCH 161/268] Fix global leak test. Necessary due to changes to test harness. --- test/unit/globals.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/unit/globals.html b/test/unit/globals.html index c1b3062c..cb15ad98 100644 --- a/test/unit/globals.html +++ b/test/unit/globals.html @@ -33,6 +33,9 @@ suite('globals', function() { assert: true, expect: true, run: true, + fixture: true, + replace: true, + stub: true, // Polymer Polymer: true, From e2a2cfde73ea334e88800c8bc6ba9976b7e30863 Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Mon, 16 Nov 2015 12:32:28 -0800 Subject: [PATCH 162/268] Call decorate instead of bootstrap for template prepping Depends on webcomponents/webcomponentsjs#447 --- bower.json | 2 +- src/mini/template.html | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bower.json b/bower.json index 6976f2f0..3081829b 100644 --- a/bower.json +++ b/bower.json @@ -18,7 +18,7 @@ "url": "https://github.com/Polymer/polymer.git" }, "dependencies": { - "webcomponentsjs": "^0.7.2" + "webcomponentsjs": "^0.7.18" }, "devDependencies": { "web-component-tester": "*" diff --git a/src/mini/template.html b/src/mini/template.html index d3668688..c6e1296c 100644 --- a/src/mini/template.html +++ b/src/mini/template.html @@ -26,7 +26,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _prepTemplate: function() { // locate template using dom-module if (this._template === undefined) { - this._template = Polymer.DomModule.import(this.is, 'template'); + this._template = Polymer.DomModule.import(this.is, 'template'); } // stick finger in footgun if (this._template && this._template.hasAttribute('is')) { @@ -35,10 +35,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN 'Move inside simple + + From 811f76680c09f6964a5088198c989b6b1ac0d6ac Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Wed, 25 Nov 2015 10:27:17 -0800 Subject: [PATCH 184/268] Remove closures holding element references after mouseup/touchend With tests Fixes #3083 --- src/standard/gestures.html | 10 ++++---- test/unit/gestures-elements.html | 2 +- test/unit/gestures.html | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/standard/gestures.html b/src/standard/gestures.html index 5e418a4a..e4528340 100644 --- a/src/standard/gestures.html +++ b/src/standard/gestures.html @@ -168,6 +168,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN function untrackDocument(stateObj) { document.removeEventListener('mousemove', stateObj.movefn); document.removeEventListener('mouseup', stateObj.upfn); + stateObj.movefn = null; + stateObj.upfn = null; } var Gestures = { @@ -416,8 +418,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN emits: ['down', 'up'], info: { - movefn: function(){}, - upfn: function(){} + movefn: null, + upfn: null }, reset: function() { @@ -486,8 +488,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } this.moves.push(move); }, - movefn: function(){}, - upfn: function(){}, + movefn: null, + upfn: null, prevent: false }, diff --git a/test/unit/gestures-elements.html b/test/unit/gestures-elements.html index 38709fcc..ee9a3c13 100644 --- a/test/unit/gestures-elements.html +++ b/test/unit/gestures-elements.html @@ -148,7 +148,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN stream: { type: Array, value: function() { - return []; + return []; } } }, diff --git a/test/unit/gestures.html b/test/unit/gestures.html index 5165ea95..24efc9e1 100644 --- a/test/unit/gestures.html +++ b/test/unit/gestures.html @@ -406,6 +406,45 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN assert.equal(el.stream.length, 1); }); }); + + suite('Reference Cleanup', function() { + var el; + + setup(function() { + el = document.createElement('x-buttons'); + document.body.appendChild(el); + }); + + teardown(function() { + document.body.removeChild(el); + }); + + test('down and up clear document tracking', function() { + var ev = new CustomEvent('mousedown', {bubbles: true}); + el.dispatchEvent(ev); + + // some recognizers do not track the document, like tap + var recognizers = Polymer.Gestures.recognizers.filter(function(r) { + return r.info.hasOwnProperty('movefn') && + r.info.hasOwnProperty('upfn'); + }); + + assert.isAbove(recognizers.length, 0, 'some recognizers track the document'); + + recognizers.forEach(function(r) { + assert.isFunction(r.info.movefn, r.name + ' movefn'); + assert.isFunction(r.info.upfn, r.name + ' upfn'); + }); + + ev = new CustomEvent('mouseup', {bubbles: true}); + el.dispatchEvent(ev); + + recognizers.forEach(function(r) { + assert.isNull(r.info.movefn, r.name + ' movefn'); + assert.isNull(r.info.upfn, r.name + ' upfn'); + }); + }); + }); From 938589112dd9d27c119d9973320b96fb0411928c Mon Sep 17 00:00:00 2001 From: Dan Beam Date: Wed, 25 Nov 2015 12:29:11 -0800 Subject: [PATCH 185/268] ?Node --- src/standard/utils.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/standard/utils.html b/src/standard/utils.html index 5356c547..84528710 100644 --- a/src/standard/utils.html +++ b/src/standard/utils.html @@ -402,7 +402,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * Checks whether an element is in this element's light DOM tree. * * @method isLightDescendant - * @param {Node} node The element to be checked. + * @param {?Node} node The element to be checked. * @return {Boolean} true if node is in this element's light DOM tree. */ isLightDescendant: function(node) { From 00ed7970c25e8f13c1455ad5c760b48ac7b82c15 Mon Sep 17 00:00:00 2001 From: ikeagold Date: Fri, 25 Sep 2015 23:49:56 +0300 Subject: [PATCH 186/268] added missing semicolons, removed some unused variables --- src/lib/css-parse.html | 6 +++--- src/lib/dom-api.html | 10 +++++----- src/lib/dom-innerHTML.html | 2 +- src/lib/dom-module.html | 2 +- src/lib/experimental/sinspect.html | 2 +- src/lib/style-cache.html | 2 +- src/lib/style-transformer.html | 2 +- src/micro/tag.html | 2 +- src/mini/shady.html | 2 +- src/standard/gestures.html | 1 - src/standard/x-styling.html | 2 +- 11 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/lib/css-parse.html b/src/lib/css-parse.html index 2199fdb7..937a60d0 100644 --- a/src/lib/css-parse.html +++ b/src/lib/css-parse.html @@ -31,7 +31,7 @@ Polymer.CssParse = (function() { _lex: function(text) { var root = {start: 0, end: text.length}; var n = root; - for (var i=0, s=0, l=text.length; i < l; i++) { + for (var i=0, l=text.length; i < l; i++) { switch (text[i]) { case this.OPEN_BRACE: //console.group(i); @@ -174,10 +174,10 @@ Polymer.CssParse = (function() { customProp: /(?:^|[\s;])--[^;{]*?:[^{};]*?(?:[;\n]|$)/gim, mixinProp: /(?:^|[\s;])?--[^;{]*?:[^{;]*?{[^}]*?}(?:[;\n]|$)?/gim, mixinApply: /@apply[\s]*\([^)]*?\)[\s]*(?:[;\n]|$)?/gim, - varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim, + varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim, keyframesRule: /^@[^\s]*keyframes/, multipleSpaces: /\s+/g - }, + }, VAR_START: '--', MEDIA_START: '@media', diff --git a/src/lib/dom-api.html b/src/lib/dom-api.html index d85d9ad2..98da3b9f 100644 --- a/src/lib/dom-api.html +++ b/src/lib/dom-api.html @@ -767,7 +767,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var forwardMethod = function(method) { DomApi.prototype[method] = function() { return this.node[method].apply(this.node, arguments); - } + }; }; forwardMethods(['cloneNode', 'appendChild', 'insertBefore', @@ -791,7 +791,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var doc = this.node instanceof Document ? this.node : this.node.ownerDocument; return doc.importNode(externalNode, deep); - } + }; DomApi.prototype.getDestinationInsertionPoints = function() { var n$ = this.node.getDestinationInsertionPoints && @@ -875,11 +875,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN node.__domApi = new DomApi(node, patch); } return node.__domApi; - }; + } function hasDomApi(node) { return Boolean(node.__domApi); - }; + } Polymer.dom = function(obj, patch) { if (obj instanceof Event) { @@ -1009,4 +1009,4 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN })(); - \ No newline at end of file + diff --git a/src/lib/dom-innerHTML.html b/src/lib/dom-innerHTML.html index 466bbba6..5586ec9d 100644 --- a/src/lib/dom-innerHTML.html +++ b/src/lib/dom-innerHTML.html @@ -29,7 +29,7 @@ Polymer.domInnerHTML = (function() { case '>': return '>'; case '"': - return '"' + return '"'; case '\u00A0': return ' '; } diff --git a/src/lib/dom-module.html b/src/lib/dom-module.html index 4420bca6..f1f9355a 100644 --- a/src/lib/dom-module.html +++ b/src/lib/dom-module.html @@ -6,7 +6,7 @@ var lcModules = {}; var findModule = function(id) { return modules[id] || lcModules[id.toLowerCase()]; - } + }; /** * The `dom-module` element registers the dom it contains to the name given diff --git a/src/lib/experimental/sinspect.html b/src/lib/experimental/sinspect.html index 009653a2..0e0b33c9 100644 --- a/src/lib/experimental/sinspect.html +++ b/src/lib/experimental/sinspect.html @@ -193,7 +193,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // remote api - shadowize = function() { + var shadowize = function() { var idx = Number(this.attributes.idx.value); //alert(idx); var node = drillable[idx]; diff --git a/src/lib/style-cache.html b/src/lib/style-cache.html index 02dabc83..8b2f1ff6 100644 --- a/src/lib/style-cache.html +++ b/src/lib/style-cache.html @@ -12,7 +12,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.StyleCache = function() { this.cache = {}; - } + }; Polymer.StyleCache.prototype = { diff --git a/src/lib/style-transformer.html b/src/lib/style-transformer.html index 27afb0fd..a3bed9fc 100644 --- a/src/lib/style-transformer.html +++ b/src/lib/style-transformer.html @@ -97,7 +97,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN elementStyles: function(element, callback) { var styles = element._styles; var cssText = ''; - for (var i=0, l=styles.length, s, text; (i Date: Mon, 30 Nov 2015 14:13:39 -0800 Subject: [PATCH 187/268] Patch rAF to setTimeout to reduce flakiness on CI. --- test/unit/dom-repeat.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/unit/dom-repeat.html b/test/unit/dom-repeat.html index bf9fd5a9..4743d455 100644 --- a/test/unit/dom-repeat.html +++ b/test/unit/dom-repeat.html @@ -3648,6 +3648,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN suite('chunked rendering', function() { + // Patch requestAnimationFrame to setTimeout to reduce flakiness on CI + var rAF; + suiteSetup(function() { + rAF = window.requestAnimationFrame; + window.requestAnimationFrame = setTimeout; + }); + suiteTeardown(function() { + window.requestAnimationFrame = rAF; + }); + test('basic chunked rendering', function(done) { var checkItemOrder = function(stamped) { From 63782fa57840d42107008dc6059f1b4a3e4a4d27 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Mon, 30 Nov 2015 14:24:56 -0800 Subject: [PATCH 188/268] Clarify this is for IE. --- test/unit/dom-repeat.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/dom-repeat.html b/test/unit/dom-repeat.html index 4743d455..0b9eca93 100644 --- a/test/unit/dom-repeat.html +++ b/test/unit/dom-repeat.html @@ -3648,7 +3648,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN suite('chunked rendering', function() { - // Patch requestAnimationFrame to setTimeout to reduce flakiness on CI + // Patch requestAnimationFrame to setTimeout to reduce IE test flakiness on CI var rAF; suiteSetup(function() { rAF = window.requestAnimationFrame; From 3df4ef20bdb5e050aa71ee2f75fccd445d708d09 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 30 Nov 2015 14:29:34 -0800 Subject: [PATCH 189/268] Fixes #3108. Moves `debounce` functionality from polymer-micro to polymer-mini. The functionality belongs at the mini tier and was never actually functional in micro. --- polymer-micro.html | 3 -- polymer-mini.html | 1 + src/{micro => mini}/debouncer.html | 3 ++ test/runner.html | 1 + test/unit/debounce.html | 83 ++++++++++++++++++++++++++++++ test/unit/utils.html | 41 --------------- 6 files changed, 88 insertions(+), 44 deletions(-) rename src/{micro => mini}/debouncer.html (94%) create mode 100644 test/unit/debounce.html diff --git a/polymer-micro.html b/polymer-micro.html index 3914a91e..209235a2 100644 --- a/polymer-micro.html +++ b/polymer-micro.html @@ -14,7 +14,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN - + + + + + + + + diff --git a/test/unit/utils.html b/test/unit/utils.html index 4415ce90..bc14a3fe 100644 --- a/test/unit/utils.html +++ b/test/unit/utils.html @@ -57,47 +57,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }); - suite('debounce', function() { - - test('debounce (no-wait)', function(done) { - - var called = 0; - var cb = function() { - called++; - }; - - window.el1.debounce('foo', cb); - window.el1.debounce('foo', cb); - window.el1.debounce('foo', cb); - - setTimeout(function() { - assert.equal(called, 1, 'debounce should be called exactly once'); - done(); - }, 50); - - }); - - test('debounce (wait)', function(done) { - - var called = 0; - var now = Date.now(); - var cb = function() { - called++; - }; - - window.el1.debounce('foo', cb); - window.el1.debounce('foo', cb, 100); - window.el1.debounce('foo', cb, 100); - - setTimeout(function() { - assert.equal(called, 1, 'debounce should be called exactly once'); - assert(Date.now() - now > 100, 'debounce should be called after at least 100ms'); - done(); - }, 200); - - }); - - }); From 644105a4691ffabafb13594aca0c825c92deb8ee Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Mon, 30 Nov 2015 15:01:15 -0800 Subject: [PATCH 190/268] Make Polymer.dom.flush reentrant-safe. Fixes #3115. --- src/lib/dom-api-flush.html | 22 +++++++++++----------- test/unit/polymer-dom.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/lib/dom-api-flush.html b/src/lib/dom-api-flush.html index a9e1c6ec..618bdd72 100644 --- a/src/lib/dom-api-flush.html +++ b/src/lib/dom-api-flush.html @@ -9,16 +9,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN --> From d4586908dc0994c99029af4a9be713b93a103de5 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Thu, 5 Nov 2015 15:43:23 +0100 Subject: [PATCH 193/268] Fix parsing of minimized css output --- src/lib/css-parse.html | 2 +- test/unit/custom-style.html | 14 +++++++++++++- test/unit/styling-cross-scope-var.html | 10 +++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/lib/css-parse.html b/src/lib/css-parse.html index 2199fdb7..bc6b4932 100644 --- a/src/lib/css-parse.html +++ b/src/lib/css-parse.html @@ -171,7 +171,7 @@ Polymer.CssParse = (function() { _rx: { comments: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim, port: /@import[^;]*;/gim, - customProp: /(?:^|[\s;])--[^;{]*?:[^{};]*?(?:[;\n]|$)/gim, + customProp: /(?:^[^;\-\s}]+)?--[^;{]*?:[^{};]*?(?:[;\n]|$)/gim, mixinProp: /(?:^|[\s;])?--[^;{]*?:[^{;]*?{[^}]*?}(?:[;\n]|$)?/gim, mixinApply: /@apply[\s]*\([^)]*?\)[\s]*(?:[;\n]|$)?/gim, varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim, diff --git a/test/unit/custom-style.html b/test/unit/custom-style.html index 058bc8e0..33a207b4 100644 --- a/test/unit/custom-style.html +++ b/test/unit/custom-style.html @@ -235,6 +235,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN --variable-property-after-property: 3px; --variable-property-after-assignment: 4px; --variable-property-before-assignment: 5px; + --variable-into-first-variable: 9px; + --variable-into-second-variable: 10px; + --variable-into-third-variable: 11px; } @@ -251,7 +254,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN --variable-between-properties: 6px; background-color: var(--variable-property-before-property); padding-top: var(--variable-property-after-property); --variable-assignment-before-property: 7px; padding-bottom: var(--variable-property-after-assignment); - padding-left: var(--variable-property-before-assignment);--variable-assignment-after-property: 8px + padding-left: var(--variable-property-before-assignment);--variable-assignment-after-property: 8px; + top: 12px;--variable-from-other-variable: var(--variable-into-first-variable);--variable-from-another-variable: var(--variable-into-second-variable); --variable-from-last-variable: var(--variable-into-third-variable); } @@ -266,6 +270,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN padding-right: var(--variable-between-properties); margin-left: var(--variable-assignment-before-property); margin-right: var(--variable-assignment-after-property); + bottom: var(--variable-from-other-variable); + left: var(--variable-from-another-variable); + right: var(--variable-from-last-variable); } Text @@ -468,11 +475,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN assertComputed(el, '7px', 'margin-left'); assertComputed(el, '8px', 'margin-right'); assertComputed(el, 'rgb(255, 255, 0)', 'background-color'); + assertComputed(el, '9px', 'bottom'); + assertComputed(el, '10px', 'left'); + assertComputed(el, '11px', 'right'); + assertComputed(el, '12px', 'top'); // Because FireFox and Chrome parse font-family differently... var computed = getComputedStyle(el); assert.equal(computed['font-family'].replace(/['"]+/g, ''), 'Varela font'); }); + test('BEM-like CSS selectors under media queries', function() { assertComputed(document.querySelector('.foo--bar'), '3px'); }); diff --git a/test/unit/styling-cross-scope-var.html b/test/unit/styling-cross-scope-var.html index cdd52dcd..ba288808 100644 --- a/test/unit/styling-cross-scope-var.html +++ b/test/unit/styling-cross-scope-var.html @@ -94,7 +94,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } #gc4 { - --grand-child-scope-var: + --grand-child-scope-var: var(--gc4-scope); } @@ -286,7 +286,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }); - + @@ -679,7 +679,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // test('var values can be overridden by subsequent concrete properties', function() { // assertComputed(styled.$.overridesConcrete, '4px'); // }); - + }); From 526fa3c545fffcb1379793b353b0ebd1eea408a9 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Thu, 3 Dec 2015 12:05:12 -0800 Subject: [PATCH 194/268] Ensure literals are excluded from parent props. Fixes #3128. Fixes #3121. --- src/standard/annotations.html | 11 ++++++++--- src/standard/effectBuilder.html | 4 ++-- test/unit/templatizer-elements.html | 4 +++- test/unit/templatizer.html | 5 +++++ 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/standard/annotations.html b/src/standard/annotations.html index 8f95261d..28ce0664 100644 --- a/src/standard/annotations.html +++ b/src/standard/annotations.html @@ -130,8 +130,8 @@ TODO(sjmiles): this module should produce either syntactic metadata this._notes = this._template._content._notes; } else { this._notes = Polymer.Annotations.parseAnnotations(this._template); + this._processAnnotations(this._notes); } - this._processAnnotations(this._notes); Polymer.Annotations.prepElement = null; } }, @@ -188,10 +188,15 @@ TODO(sjmiles): this module should produce either syntactic metadata if (p.signature) { var args = p.signature.args; for (var kk=0; kk 0; if (a.structured) { diff --git a/test/unit/templatizer-elements.html b/test/unit/templatizer-elements.html index 395787a6..e56e4668 100644 --- a/test/unit/templatizer-elements.html +++ b/test/unit/templatizer-elements.html @@ -11,6 +11,7 @@ obj="{{obj}}" obj-prop="{{obj.prop}}" conflict="{{outerInnerConflict.prop}}" + computed-from-literal="{{computeFromLiteral(33, prop)}}" > @@ -238,7 +239,8 @@ ], outerObjChanged: function() {}, objAChanged: function() {}, - objBChanged: function() {} + objBChanged: function() {}, + computeFromLiteral: function() {} }); diff --git a/test/unit/templatizer.html b/test/unit/templatizer.html index 0ba1481e..a2538b26 100644 --- a/test/unit/templatizer.html +++ b/test/unit/templatizer.html @@ -250,6 +250,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN assert.equal(childA.conflict, 'bar'); }); + test('ensure literals are not forwarded to templates', function() { + assert.notOk(host._propertyEffects[33]); + assert.notOk(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(host), 33)); + }); + }); From 94c2bc25531e158282d1927034a2a3c65b652cdb Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Sat, 26 Sep 2015 13:44:11 +0200 Subject: [PATCH 195/268] Add .gitattributes to solve line endings cross-OS --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..4cab1f4d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto From 43fc853750fa750e1465d7efd2ab9af6fbf2e28c Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 4 Dec 2015 14:32:20 -0800 Subject: [PATCH 196/268] Slightly faster `findAnnotatedNodes` --- src/lib/annotations/annotations.html | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/lib/annotations/annotations.html b/src/lib/annotations/annotations.html index 42f6425b..d3762755 100644 --- a/src/lib/annotations/annotations.html +++ b/src/lib/annotations/annotations.html @@ -366,18 +366,22 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // instance-time - _localSubTree: function(node, host) { - return (node === host) ? node.childNodes : - (node._lightChildren || node.childNodes); - }, - findAnnotatedNode: function(root, annote) { // recursively ascend tree until we hit root var parent = annote.parent && Polymer.Annotations.findAnnotatedNode(root, annote.parent); // unwind the stack, returning the indexed node at each level - return !parent ? root : - Polymer.Annotations._localSubTree(parent, root)[annote.index]; + if (parent) { + // note: marginally faster than indexing via childNodes + // (http://jsperf.com/childnodes-lookup) + for (var n=parent.firstChild, i=0; n; n=n.nextSibling) { + if (annote.index === i++) { + return n; + } + } + } else { + return root; + } } }; From dcbafbfc166b146e106677f58d01039fad169d69 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 4 Dec 2015 14:33:21 -0800 Subject: [PATCH 197/268] Avoid making a copy of childNodes when a dom fragment is inserted in the logical tree. --- src/lib/dom-tree-api.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/dom-tree-api.html b/src/lib/dom-tree-api.html index da49c816..339a56a1 100644 --- a/src/lib/dom-tree-api.html +++ b/src/lib/dom-tree-api.html @@ -99,10 +99,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN container.__childNodes = null; // handle document fragments if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { - // NOTE: the act of setting this info can affect patched nodes + // TODO(sorvell): remember this for patching: + // the act of setting this info can affect patched nodes // getters; therefore capture childNodes before patching. - var c$ = TreeApi.arrayCopyChildNodes(node); - for (var i=0, n; (i Date: Fri, 4 Dec 2015 15:38:20 -0800 Subject: [PATCH 198/268] Ensure dom-if in host does not restamp when host detaches. Fixes #3125. --- src/lib/template/dom-if.html | 27 +++++-- test/unit/dom-if-elements.html | 24 ++++++ test/unit/dom-if.html | 136 +++++++++++++++++++++++++++++++-- 3 files changed, 172 insertions(+), 15 deletions(-) diff --git a/src/lib/template/dom-if.html b/src/lib/template/dom-if.html index 236a0f50..31b68cfb 100644 --- a/src/lib/template/dom-if.html +++ b/src/lib/template/dom-if.html @@ -74,7 +74,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN detached: function() { // TODO(kschaaf): add logic to re-stamp in attached? - this._teardownInstance(); + if (!this.parentNode) { + this._teardownInstance(); + } }, attached: function() { @@ -116,16 +118,27 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _ensureInstance: function() { - if (!this._instance) { - var parentNode = Polymer.dom(this).parentNode; - // Guard against element being detached while render was queued - if (parentNode) { - var parent = Polymer.dom(parentNode); + var parentNode = Polymer.dom(this).parentNode; + // Guard against element being detached while render was queued + if (parentNode) { + var parent = Polymer.dom(parentNode); + if (!this._instance) { // TODO(sorvell): pickup stamping logic from x-repeat this._instance = this.stamp(); var root = this._instance.root; // TODO(sorvell): this incantation needs to be simpler. parent.insertBefore(root, this); + } else { + var c$ = this._instance._children; + if (c$ && c$.length) { + // Detect case where dom-if was re-attached in new position + var lastChild = Polymer.dom(this).previousSibling; + if (lastChild !== c$[c$.length-1]) { + for (var i=0, n; (i + + + + + diff --git a/test/unit/dom-if.html b/test/unit/dom-if.html index 1050514d..1f379e45 100644 --- a/test/unit/dom-if.html +++ b/test/unit/dom-if.html @@ -56,9 +56,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN - +
+ + +
+
+
diff --git a/test/unit/dom-if.html b/test/unit/dom-if.html index 1050514d..71ebe046 100644 --- a/test/unit/dom-if.html +++ b/test/unit/dom-if.html @@ -495,6 +495,27 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN document.body.removeChild(x); }); + test('binding to text nodes changed while if=false', function() { + var x = document.createElement('x-textcontent'); + document.body.appendChild(x); + x.$.domIf.render(); + var stamped = Polymer.dom(x.root).childNodes; + assert.equal(stamped.length, 12); + assert.equal(stamped[7].textContent.trim(), 'Stuff'); + x.$.domIf.if = false; + x.$.domIf.render(); + x.text = 'Hollaaaaa!'; + stamped = Polymer.dom(x.root).childNodes; + assert.equal(stamped.length, 12); + assert.equal(stamped[7].textContent.trim(), ''); + x.$.domIf.if = true; + x.$.domIf.render(); + stamped = Polymer.dom(x.root).childNodes; + assert.equal(stamped.length, 12); + assert.equal(stamped[7].textContent.trim(), 'Hollaaaaa!'); + document.body.removeChild(x); + }); + }); suite('queueing race conditions', function() { From d3145e8ef58b506ea565b9feb2daba810ca6296e Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Fri, 4 Dec 2015 16:40:44 -0800 Subject: [PATCH 200/268] Revert "Fix parsing of minimized css output" --- src/lib/css-parse.html | 2 +- test/unit/custom-style.html | 14 +------------- test/unit/styling-cross-scope-var.html | 10 +++++----- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/lib/css-parse.html b/src/lib/css-parse.html index 5f2c4281..c3454b4d 100644 --- a/src/lib/css-parse.html +++ b/src/lib/css-parse.html @@ -171,7 +171,7 @@ Polymer.CssParse = (function() { _rx: { comments: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim, port: /@import[^;]*;/gim, - customProp: /(?:^[^;\-\s}]+)?--[^;{]*?:[^{};]*?(?:[;\n]|$)/gim, + customProp: /(?:^|[\s;])--[^;{]*?:[^{};]*?(?:[;\n]|$)/gim, mixinProp: /(?:^|[\s;])?--[^;{]*?:[^{;]*?{[^}]*?}(?:[;\n]|$)?/gim, mixinApply: /@apply[\s]*\([^)]*?\)[\s]*(?:[;\n]|$)?/gim, varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim, diff --git a/test/unit/custom-style.html b/test/unit/custom-style.html index 33a207b4..058bc8e0 100644 --- a/test/unit/custom-style.html +++ b/test/unit/custom-style.html @@ -235,9 +235,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN --variable-property-after-property: 3px; --variable-property-after-assignment: 4px; --variable-property-before-assignment: 5px; - --variable-into-first-variable: 9px; - --variable-into-second-variable: 10px; - --variable-into-third-variable: 11px; } @@ -254,8 +251,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN --variable-between-properties: 6px; background-color: var(--variable-property-before-property); padding-top: var(--variable-property-after-property); --variable-assignment-before-property: 7px; padding-bottom: var(--variable-property-after-assignment); - padding-left: var(--variable-property-before-assignment);--variable-assignment-after-property: 8px; - top: 12px;--variable-from-other-variable: var(--variable-into-first-variable);--variable-from-another-variable: var(--variable-into-second-variable); --variable-from-last-variable: var(--variable-into-third-variable); + padding-left: var(--variable-property-before-assignment);--variable-assignment-after-property: 8px } @@ -270,9 +266,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN padding-right: var(--variable-between-properties); margin-left: var(--variable-assignment-before-property); margin-right: var(--variable-assignment-after-property); - bottom: var(--variable-from-other-variable); - left: var(--variable-from-another-variable); - right: var(--variable-from-last-variable); } Text @@ -475,16 +468,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN assertComputed(el, '7px', 'margin-left'); assertComputed(el, '8px', 'margin-right'); assertComputed(el, 'rgb(255, 255, 0)', 'background-color'); - assertComputed(el, '9px', 'bottom'); - assertComputed(el, '10px', 'left'); - assertComputed(el, '11px', 'right'); - assertComputed(el, '12px', 'top'); // Because FireFox and Chrome parse font-family differently... var computed = getComputedStyle(el); assert.equal(computed['font-family'].replace(/['"]+/g, ''), 'Varela font'); }); - test('BEM-like CSS selectors under media queries', function() { assertComputed(document.querySelector('.foo--bar'), '3px'); }); diff --git a/test/unit/styling-cross-scope-var.html b/test/unit/styling-cross-scope-var.html index ba288808..cdd52dcd 100644 --- a/test/unit/styling-cross-scope-var.html +++ b/test/unit/styling-cross-scope-var.html @@ -94,7 +94,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } #gc4 { - --grand-child-scope-var: + --grand-child-scope-var: var(--gc4-scope); } @@ -286,7 +286,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }); - + @@ -679,7 +679,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // test('var values can be overridden by subsequent concrete properties', function() { // assertComputed(styled.$.overridesConcrete, '4px'); // }); - + }); From e39d5ba1fd37e35f16bdfa13ce72aea8c81a7885 Mon Sep 17 00:00:00 2001 From: Arthur Evans Date: Fri, 4 Dec 2015 17:14:56 -0800 Subject: [PATCH 201/268] Make renderedItemCount readOnly & add tests. --- src/lib/template/dom-repeat.html | 5 +++-- test/unit/dom-repeat.html | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/lib/template/dom-repeat.html b/src/lib/template/dom-repeat.html index 95b10ab3..20bca426 100644 --- a/src/lib/template/dom-repeat.html +++ b/src/lib/template/dom-repeat.html @@ -199,7 +199,8 @@ Then the `observe` property should be configured as follows: */ renderedItemCount: { type: Number, - notify: true + notify: true, + readOnly: true }, /** @@ -450,7 +451,7 @@ Then the `observe` property should be configured as follows: // the same item. this._pool.length = 0; // Set rendered item count - this.renderedItemCount = this._instances.length; + this._setRenderedItemCount(this._instances.length); // Notify users this.fire('dom-change'); // Check to see if we need to render more items diff --git a/test/unit/dom-repeat.html b/test/unit/dom-repeat.html index 1164fd43..72091a66 100644 --- a/test/unit/dom-repeat.html +++ b/test/unit/dom-repeat.html @@ -3311,6 +3311,23 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN assert.equal(repeater3.keyForElement(stamped1[4]), coll3.getKey(items3[2])); }); + test('renderedItemCount', function() { + var repeater1 = primitive.$.repeater1; + primitive.items = [ 'a', 'b', 'c', 'd', 'e' ]; + repeater1.render(); + assert.equal(repeater1.renderedItemCount, 5, 'renderedItemCount is incorrect'); + repeater1.renderedItemCount = 0; + assert.equal(repeater1.renderedItemCount, 5, 'renderedItemCount is writable'); + repeater1.filter = function(item) { + return (item != 'a' && item != 'e'); + } + repeater1.render(); + assert.equal(repeater1.renderedItemCount, 3, 'renderedItemCount incorrect after filter'); + // reset repeater + repeater1.filter = undefined; + repeater1.render(); + }); + test('__hideTemplateChildren__', function() { // Initially all showing var stamped1 = Polymer.dom(primitive.$.container1).querySelectorAll('*:not(template)'); From b6b8293b5aa8c1f8ebb04b458f9465c5b5c6e1ae Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Fri, 4 Dec 2015 18:31:27 -0800 Subject: [PATCH 202/268] Revert "Add .gitattributes to solve line endings cross-OS (merge after other PRs)" --- .gitattributes | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 4cab1f4d..00000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Set the default behavior, in case people don't have core.autocrlf set. -* text=auto From 6467ae11c4d4d89ee60d6cba44499fca7e5702d2 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 7 Dec 2015 12:49:45 -0800 Subject: [PATCH 203/268] Remove all TODOs --- src/lib/template/dom-if.html | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib/template/dom-if.html b/src/lib/template/dom-if.html index 31b68cfb..89a39c0a 100644 --- a/src/lib/template/dom-if.html +++ b/src/lib/template/dom-if.html @@ -73,7 +73,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, detached: function() { - // TODO(kschaaf): add logic to re-stamp in attached? if (!this.parentNode) { this._teardownInstance(); } @@ -81,7 +80,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN attached: function() { if (this.if && this.ctor) { - // TODO(sorvell): should not be async, but node can be attached + // NOTE: ideally should not be async, but node can be attached // when shady dom is in the act of distributing/composing so push it out this.async(this._ensureInstance); } @@ -123,10 +122,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (parentNode) { var parent = Polymer.dom(parentNode); if (!this._instance) { - // TODO(sorvell): pickup stamping logic from x-repeat this._instance = this.stamp(); var root = this._instance.root; - // TODO(sorvell): this incantation needs to be simpler. parent.insertBefore(root, this); } else { var c$ = this._instance._children; From dfa6a44ac0b20f900ebd472d610d65970c59d931 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 7 Dec 2015 14:48:21 -0800 Subject: [PATCH 204/268] Correct test to avoid using `firstElementChild` on a documentFragment since it is not universally supported. --- test/unit/polymer-dom-content.html | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/unit/polymer-dom-content.html b/test/unit/polymer-dom-content.html index 0ab9a3ef..be6f99aa 100644 --- a/test/unit/polymer-dom-content.html +++ b/test/unit/polymer-dom-content.html @@ -1100,7 +1100,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); Polymer.dom(h1).appendChild(d); @@ -1112,7 +1112,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); document.body.removeChild(h1); @@ -1134,7 +1134,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); Polymer.dom(h1).appendChild(d); @@ -1146,7 +1146,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); document.body.removeChild(h1); @@ -1246,7 +1246,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); Polymer.dom(h1).appendChild(d); @@ -1258,7 +1258,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); document.body.removeChild(h1); @@ -1280,7 +1280,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); Polymer.dom(h1).appendChild(d); @@ -1292,7 +1292,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); document.body.removeChild(h1); @@ -1313,7 +1313,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); Polymer.dom(h1).appendChild(d); @@ -1325,7 +1325,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); document.body.removeChild(h1); @@ -1335,7 +1335,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var div = document.createElement('div'); div.innerHTML = '
'; var h1 = div.firstChild; - var h2 = document.createDocumentFragment();; + var h2 = document.createDocumentFragment(); document.body.appendChild(h1); Polymer.dom.flush(); var d = Polymer.dom(h1).firstElementChild; @@ -1347,7 +1347,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); Polymer.dom(h1).appendChild(d); @@ -1359,7 +1359,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.dom(h2).appendChild(d); Polymer.dom.flush(); assert.equal(Polymer.dom(h2).childNodes.length, 1); - assert.equal(Polymer.dom(h2).firstElementChild, d); + assert.equal(Polymer.dom(h2).firstChild, d); assert.equal(Polymer.dom(h1).childNodes.length, 0); assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0); document.body.removeChild(h1); From 02c5c79d2e852a86334d119f23761d25351c3264 Mon Sep 17 00:00:00 2001 From: Peter Burns Date: Mon, 7 Dec 2015 15:18:05 -0800 Subject: [PATCH 205/268] Minor typo in docs: call the debounce callback --- src/mini/debouncer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mini/debouncer.html b/src/mini/debouncer.html index c3fb0767..d8365fab 100644 --- a/src/mini/debouncer.html +++ b/src/mini/debouncer.html @@ -27,7 +27,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * debouncedClickAction: function(e) { * // will not call `processClick` more than once per 100ms * this.debounce('click', function() { - * this.processClick; + * this.processClick(); * }, 100); * } * From 8272d5e2bf81ab4580c334013686814d7cdc2c5a Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 7 Dec 2015 17:09:06 -0800 Subject: [PATCH 206/268] Factoring of distribution logic in both add and remove cases. --- src/lib/dom-api-shady.html | 161 ++++++++++++++++++------------------- src/lib/dom-tree-api.html | 8 ++ src/mini/shady.html | 5 ++ 3 files changed, 90 insertions(+), 84 deletions(-) diff --git a/src/lib/dom-api-shady.html b/src/lib/dom-api-shady.html index 584d5bc6..61888b38 100644 --- a/src/lib/dom-api-shady.html +++ b/src/lib/dom-api-shady.html @@ -44,11 +44,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, appendChild: function(node) { - return this._addNode(node); - }, - - insertBefore: function(node, ref_node) { - return this._addNode(node, ref_node); + return this.insertBefore(node); }, // cases in which we may not be able to just do standard native call @@ -57,25 +53,18 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // 2. container is a shadyRoot (don't distribute, instead set // container to container.host. // 3. node is (host of container needs distribution) - _addNode: function(node, ref_node) { - this._removeNodeFromParent(node); - var addedInsertionPoint; - var root = this.getOwnerRoot(); - // if a is added, make sure it's parent has logical info. - if (root) { - addedInsertionPoint = this._maybeAddInsertionPoint(node, this.node); + insertBefore: function(node, ref_node) { + if (ref_node && TreeApi.Logical.getParentNode(ref_node) !== this.node) { + throw Error('The ref_node to be inserted before is not a child ' + + 'of this node'); } - if (TreeApi.Logical.hasChildNodes(this.node)) { - if (ref_node && ref_node.__parentNode !== this.node) { - throw Error('The ref_node to be inserted before is not a child ' + - 'of this node'); - } - TreeApi.Logical.recordInsertBefore(node, this.node, ref_node); + // notify existing parent that this node is being removed. + var parent = TreeApi.Logical.getParentNode(node); + if (parent && DomApi.hasApi(parent)) { + dom(parent).notifyObserver(); } - this._addNodeToHost(node); - // if not distributing and not adding to host, do a fast path addition - if (!this._maybeDistribute(node, this.node) && - !this._tryRemoveUndistributedNode(node)) { + this._removeNode(node); + if (!this._addNode(node, ref_node)) { if (ref_node) { // if ref_node is replace with first distributed node ref_node = ref_node.localName === CONTENT ? @@ -90,13 +79,27 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } TreeApi.Composed.recordInsertBefore(container, node, ref_node); } - if (addedInsertionPoint) { - this._updateInsertionPoints(root.host); - } this.notifyObserver(); return node; }, + // Try to add node. Record logical info, track insertion points, perform + // distribution iff needed. Return true if the add is handled. + _addNode: function(node, ref_node) { + var root = this.getOwnerRoot(); + if (root) { + root._invalidInsertionPoints = + this._maybeAddInsertionPoint(node, this.node); + this._addNodeToHost(root.host, node); + } + if (TreeApi.Logical.hasChildNodes(this.node)) { + TreeApi.Logical.recordInsertBefore(node, this.node, ref_node); + } + // if not distributing and not adding to host, do a fast path addition + return (this._maybeDistribute(node) || + this._tryRemoveUndistributedNode(node)); + }, + /** Removes the given `node` from the element's `lightChildren`. This method also performs dom composition. @@ -106,8 +109,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN console.warn('The node to be removed is not a child of this node', node); } - this._removeNodeFromHost(node); - if (!this._maybeDistribute(node, this.node)) { + if (!this._removeNode(node)) { // if removing from a shadyRoot, remove form host instead var container = this.node._isShadyRoot ? this.node.host : this.node; // not guaranteed to physically be in container; e.g. @@ -121,6 +123,35 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return node; }, + // Try to remove node: update logical info and perform distribution iff + // needed. Return true if the removal has been handled. + // note that it's possible for both the node's host and its parent + // to require distribution... both cases are handled here. + _removeNode: function(node) { + TreeApi.Composed.recordRemoveChild( + TreeApi.Composed.getParentNode(node), node); + // important that we want to do this only if the node has a logical parent + var logicalParent = TreeApi.Logical.hasParentNode(node) && + TreeApi.Logical.getParentNode(node); + var distributed; + var root = this._ownerShadyRootForNode(node); + if (logicalParent) { + // distribute node's parent iff needed + distributed = dom(node)._distributeParent(); + TreeApi.Logical.recordRemoveChild(node, logicalParent); + // remove node from root and distribute it iff needed + if (root && this._removeDistributedChildren(root, node)) { + root._invalidInsertionPoints = true; + this._lazyDistribute(root.host); + } + } + this._removeOwnerShadyRoot(node); + if (root) { + this._removeNodeFromHost(root.host, node); + } + return distributed; + }, + replaceChild: function(node, ref_node) { this.insertBefore(node, ref_node); this.removeChild(ref_node); @@ -157,7 +188,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return node._ownerShadyRoot; }, - _maybeDistribute: function(node, parent) { + _maybeDistribute: function(node) { // TODO(sorvell): technically we should check non-fragment nodes for // children but since this case is assumed to be exceedingly // rare, we avoid the cost and will address with some specific api @@ -176,24 +207,23 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // 2. children being inserted into parent with a shady root (parent // needs distribution) if (hasContent) { - var root = this._ownerShadyRootForNode(parent); + var root = this.getOwnerRoot(); if (root) { - var host = root.host; // note, insertion point list update is handled after node // mutations are complete - this._lazyDistribute(host); + this._lazyDistribute(root.host); } } - var parentNeedsDist = this._parentNeedsDistribution(parent); - if (parentNeedsDist) { - this._lazyDistribute(parent); + var needsDist = this._nodeNeedsDistribution(this.node); + if (needsDist) { + this._lazyDistribute(this.node); } // Return true when distribution will fully handle the composition // Note that if a content was being inserted that was wrapped by a node, // and the parent does not need distribution, return false to allow // the nodes to be added directly, after which children may be // distributed and composed into the wrapping node(s) - return parentNeedsDist || (hasContent && !wrappedContent); + return needsDist || (hasContent && !wrappedContent); }, /* note: parent argument is required since node may have an out @@ -241,51 +271,21 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } }, - _parentNeedsDistribution: function(parent) { - return parent && parent.shadyRoot && - DomApi.hasInsertionPoint(parent.shadyRoot); + _nodeNeedsDistribution: function(node) { + return node && node.shadyRoot && + DomApi.hasInsertionPoint(node.shadyRoot); }, - _removeNodeFromParent: function(node) { - // note: we may need to notify and not have logical info so fallback - // to composed parentNode. - - var parent = node.__parentNode || node.parentNode; - //var parent = dom(node).parentNode; - // TODO(sorvell): hasDomApi doesn't make sense now - if (parent && DomApi.hasApi(parent)) { - dom(parent).notifyObserver(); + // a node being added is always in this same host as this.node. + _addNodeToHost: function(host, node) { + if (host._elementAdd) { + host._elementAdd(node); } - this._removeNodeFromHost(node, true); }, - // NOTE: if `ensureComposedRemoval` is true then the node should be - // removed from its composed parent. - _removeNodeFromHost: function(node, ensureComposedRemoval) { - // note that it's possible for both the node's host and its parent - // to require distribution... both cases are handled here. - var hostNeedsDist; - var root; - // important that we want to do this only if the node has a logical parent - var parent = node.__parentNode; - if (parent) { - // distribute node's parent iff needed - dom(node)._distributeParent(); - root = this._ownerShadyRootForNode(node); - // remove node from root and distribute it iff needed - if (root) { - root.host._elementRemove(node); - hostNeedsDist = this._removeDistributedChildren(root, node); - } - TreeApi.Logical.recordRemoveChild(node, parent); - } - this._removeOwnerShadyRoot(node); - if (root && hostNeedsDist) { - this._updateInsertionPoints(root.host); - this._lazyDistribute(root.host); - } else if (ensureComposedRemoval) { - TreeApi.Composed.recordRemoveChild( - TreeApi.Composed.getParentNode(node), node); + _removeNodeFromHost: function(host, node) { + if (host._elementRemove) { + host._elementRemove(node); } }, @@ -319,14 +319,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } }, - // a node being added is always in this same host as this.node. - _addNodeToHost: function(node) { - var root = this.getOwnerRoot(); - if (root) { - root.host._elementAdd(node); - } - }, - _removeOwnerShadyRoot: function(node) { // optimization: only reset the tree if node is actually in a root if (this._hasCachedOwnerRoot(node)) { @@ -410,8 +402,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _distributeParent: function() { - if (this._parentNeedsDistribution(this.parentNode)) { + if (this._nodeNeedsDistribution(this.parentNode)) { this._lazyDistribute(this.parentNode); + return true; } }, diff --git a/src/lib/dom-tree-api.html b/src/lib/dom-tree-api.html index 339a56a1..2d48a4b7 100644 --- a/src/lib/dom-tree-api.html +++ b/src/lib/dom-tree-api.html @@ -58,6 +58,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return Boolean(node.__childNodes !== undefined); }, + hasParentNode: function(node) { + return Boolean(node.__parentNode); + }, + getChildNodes: function(node) { if (this.hasChildNodes(node)) { if (!node.__childNodes) { @@ -75,6 +79,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } }, + getParentNode: function(node) { + return node.__parentNode || node.parentNode; + }, + // Capture the list of light children. It's important to do this before we // start transforming the DOM into "rendered" state. // Children may be added to this list dynamically. It will be treated as the diff --git a/src/mini/shady.html b/src/mini/shady.html index 4e7883ca..5d446a31 100644 --- a/src/mini/shady.html +++ b/src/mini/shady.html @@ -134,6 +134,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _distributeContent: function() { if (this._useContent && !this.shadyRoot._distributionClean) { + if (this.shadyRoot._invalidInsertionPoints) { + var dom = Polymer.dom(this); + dom._updateInsertionPoints(this); + this.shadyRoot._invalidInsertionPoints = false; + } // logically distribute self this._beginDistribute(); this._distributeDirtyRoots(); From 9b898c25cca663dec22e8368e5cfc87a08aff628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gro=CC=88nke?= Date: Thu, 30 Jul 2015 19:50:04 +0200 Subject: [PATCH 207/268] remove dead debounce test assertion --- test/unit/utils.html | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/unit/utils.html b/test/unit/utils.html index bc14a3fe..bebd5ca9 100644 --- a/test/unit/utils.html +++ b/test/unit/utils.html @@ -57,6 +57,44 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }); + suite('debounce', function() { + + test('debounce (no-wait)', function(done) { + + var called = 0; + var cb = function() { + called++; + }; + + window.el1.debounce('foo', cb); + window.el1.debounce('foo', cb); + window.el1.debounce('foo', cb); + + setTimeout(function() { + assert.equal(called, 1, 'debounce should be called exactly once'); + done(); + }, 50); + + }); + + test('debounce (wait)', function(done) { + + var called = 0; + var cb = function() { + called++; + }; + + window.el1.debounce('foo', cb); + window.el1.debounce('foo', cb, 100); + + setTimeout(function() { + assert.equal(called, 1, 'debounce should be called exactly once'); + done(); + }, 200); + + }); + + }); From 02068525759c6ee4cbc2178c04ceb30372f2ac40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gro=CC=88nke?= Date: Thu, 30 Jul 2015 20:17:35 +0200 Subject: [PATCH 208/268] add more debouncer tests --- test/unit/utils.html | 65 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/unit/utils.html b/test/unit/utils.html index bebd5ca9..9e142d89 100644 --- a/test/unit/utils.html +++ b/test/unit/utils.html @@ -94,6 +94,71 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }); + test('debounce flushing', function(done) { + + var called = 0; + var cb = function() { + called++; + }; + + window.el1.debounce('foo', cb); + window.el1.flushDebouncer('foo'); + window.el1.debounce('foo', cb); + + setTimeout(function() { + assert.equal(called, 2, 'debounce should be called twice'); + done(); + }, 100); + + }); + + test('debounce state', function(done) { + + window.el1.debounce('foo', function() { + assert.equal(window.el1.isDebouncerActive('foo'), false, 'debouncer is inactive after resolution'); + done(); + }); + + assert.equal(window.el1.isDebouncerActive('foo'), true, 'debouncer is active immediately after triggering'); + + }); + + test('debounce cancelling', function(done) { + + var triggered = false; + + window.el1.debounce('foo', function() { + triggered = true; + }); + window.el1.cancelDebouncer('foo'); + assert.equal(window.el1.isDebouncerActive('foo'), false, 'debouncer is inactive after cancelling'); + + setTimeout(function() { + assert.equal(triggered, false, 'debounce never fired'); + done(); + }, 100); + + }); + + test('duplicate debouncer assignment', function(done) { + + var a, b; + + window.el1.debounce('foo', function() { + a = 'foo'; + }); + window.el1.debounce('foo', function() { + b = 'bar'; + }); + + setTimeout(function() { + assert.equal(a, undefined, 'first debouncer was never fired'); + assert.equal(b, 'bar', 'only the second debouncer callback was executed'); + done(); + }, 100); + + }); + }); From 391649341b6449810191b4040f7e28ab23b5420b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gro=CC=88nke?= Date: Thu, 30 Jul 2015 20:17:58 +0200 Subject: [PATCH 209/268] ensure isDebouncerActive returns a Boolean --- src/mini/debouncer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mini/debouncer.html b/src/mini/debouncer.html index d8365fab..493953bc 100644 --- a/src/mini/debouncer.html +++ b/src/mini/debouncer.html @@ -52,7 +52,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN */ isDebouncerActive: function(jobName) { var debouncer = this._debouncers[jobName]; - return debouncer && debouncer.finish; + return !!(debouncer && debouncer.finish); }, /** From 9bef4c057c6da56f534bab0beac911ba80998c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gro=CC=88nke?= Date: Sat, 1 Aug 2015 13:22:55 +0200 Subject: [PATCH 210/268] speed up microtask testing --- test/unit/utils.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/utils.html b/test/unit/utils.html index 9e142d89..7de7c823 100644 --- a/test/unit/utils.html +++ b/test/unit/utils.html @@ -73,7 +73,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN setTimeout(function() { assert.equal(called, 1, 'debounce should be called exactly once'); done(); - }, 50); + }); }); From 8ef7bac6dc92c44fa702c3c9606b2a5d0d1d43eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gro=CC=88nke?= Date: Sat, 1 Aug 2015 13:33:40 +0200 Subject: [PATCH 211/268] more explicit tests for debouncer wait and no-wait behavior --- test/unit/utils.html | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/test/unit/utils.html b/test/unit/utils.html index 7de7c823..9ddb3c50 100644 --- a/test/unit/utils.html +++ b/test/unit/utils.html @@ -85,10 +85,15 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }; window.el1.debounce('foo', cb); + window.el1.debounce('foo', cb, 50); window.el1.debounce('foo', cb, 100); setTimeout(function() { - assert.equal(called, 1, 'debounce should be called exactly once'); + assert.equal(called, 0, 'callback is not called yet'); + }, 50); + + setTimeout(function() { + assert.equal(called, 1, 'callback was called exactly once'); done(); }, 200); @@ -140,7 +145,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }); - test('duplicate debouncer assignment', function(done) { + test('duplicate debouncer assignment (no-wait)', function(done) { var a, b; @@ -155,7 +160,26 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN assert.equal(a, undefined, 'first debouncer was never fired'); assert.equal(b, 'bar', 'only the second debouncer callback was executed'); done(); - }, 100); + }); + + }); + + test('duplicate debouncer assignment (wait)', function(done) { + + var a, b, delay = 50; + + window.el1.debounce('foo', function() { + a = 'foo'; + }, delay); + window.el1.debounce('foo', function() { + b = 'bar'; + }, delay); + + setTimeout(function() { + assert.equal(a, undefined, 'first debouncer was never fired'); + assert.equal(b, 'bar', 'only the second debouncer callback was executed'); + done(); + }, (delay+50)); }); From 68707ad76009f8f8bc12843fd89780a929659e18 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Fri, 30 Oct 2015 22:53:02 +0100 Subject: [PATCH 212/268] Deduplicate setup and verifying in notify-path test suite --- test/unit/notify-path-elements.html | 2 +- test/unit/notify-path.html | 481 ++++++---------------------- 2 files changed, 96 insertions(+), 387 deletions(-) diff --git a/test/unit/notify-path-elements.html b/test/unit/notify-path-elements.html index c10d2f05..48bf32cb 100644 --- a/test/unit/notify-path-elements.html +++ b/test/unit/notify-path-elements.html @@ -230,4 +230,4 @@ cChanged: function() {} }); - \ No newline at end of file + diff --git a/test/unit/notify-path.html b/test/unit/notify-path.html index 7cc82c41..b0997f34 100644 --- a/test/unit/notify-path.html +++ b/test/unit/notify-path.html @@ -47,6 +47,80 @@ suite('basic path bindings', function() { document.body.removeChild(el); }); + function setupNested() { + var nested = { + obj: { + value: 41 + } + }; + el.nested = nested; + el.expectedNestedSubpath = 'nested.obj.value'; + el.expectedNestedValue = 42; + el.expectedNestedObjSubpath = 'nested.obj.value'; + el.expectedNestedObjValue = 42; + el.$.compose.expectedObjSubpath = 'obj.value'; + el.$.compose.expectedObjValue = 42; + el.$.forward.expectedObjSubpath = 'obj.value'; + el.$.forward.expectedObjValue = 42; + el.$.forward.$.compose.expectedObjSubpath = 'obj.value'; + el.$.forward.$.compose.expectedObjValue = 42; + el.clearObserverCounts(); + } + + function setupComposedAndGetObject() { + el.nested = { + obj: { + value: 41 + } + }; + var obj = { + value: 42 + }; + el.expectedNestedSubpath = 'nested.obj'; + el.expectedNestedValue = obj; + el.expectedNestedObjSubpath = 'nested.obj'; + el.expectedNestedObjValue = obj; + el.$.compose.expectedObjSubpath = 'obj'; + el.$.compose.expectedObjValue = obj; + el.$.forward.expectedObjSubpath = 'obj'; + el.$.forward.expectedObjValue = obj; + el.$.forward.$.compose.expectedObjSubpath = 'obj'; + el.$.forward.$.compose.expectedObjValue = obj; + el.clearObserverCounts(); + + return obj; + } + + function verifyObserverOutput(expectedNestedObjChanged) { + assert.equal(el.observerCounts.nestedSubpathChanged, 1); + assert.equal(el.observerCounts.nestedObjChanged, expectedNestedObjChanged); + assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); + assert.equal(el.observerCounts.nestedObjValueChanged, 1); + assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); + assert.equal(el.$.compose.observerCounts.objValueChanged, 1); + assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); + assert.equal(el.$.forward.observerCounts.objValueChanged, 1); + assert.equal(el.$.basic.notifyingValue, 42); + assert.equal(el.$.basic.notifyingValue, 42); + assert.equal(el.$.compose.$.basic1.notifyingValue, 42); + assert.equal(el.$.compose.$.basic2.notifyingValue, 42); + assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); + assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); + assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); + assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); + assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); + assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + } + + function verifyNestedObserversOutput() { + verifyObserverOutput(0); + } + + function verifyNonNestedObserversOutput() { + verifyObserverOutput(1); + } + test('downward data flow', function() { // Setup var nested = { @@ -67,462 +141,97 @@ suite('basic path bindings', function() { // Do the thing el.nested = nested; // Verify - assert.equal(el.observerCounts.nestedSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjChanged, 1); - assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjValueChanged, 1); - assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.compose.observerCounts.objValueChanged, 1); - assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.forward.observerCounts.objValueChanged, 1); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.compose.obj, nested.obj); - assert.equal(el.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.forward.obj, nested.obj); - assert.equal(el.$.forward.$.compose.obj, nested.obj); - assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + verifyNonNestedObserversOutput(); }); test('notification from basic element property change', function() { // Setup - var nested = { - obj: { - value: 41 - } - }; - el.nested = nested; - el.expectedNestedSubpath = 'nested.obj.value'; - el.expectedNestedValue = 42; - el.expectedNestedObjSubpath = 'nested.obj.value'; - el.expectedNestedObjValue = 42; - el.$.compose.expectedObjSubpath = 'obj.value'; - el.$.compose.expectedObjValue = 42; - el.$.forward.expectedObjSubpath = 'obj.value'; - el.$.forward.expectedObjValue = 42; - el.$.forward.$.compose.expectedObjSubpath = 'obj.value'; - el.$.forward.$.compose.expectedObjValue = 42; - el.clearObserverCounts(); + setupNested(); // Do the thing el.$.basic.notifyingValue = 42; // Verify - assert.equal(el.observerCounts.nestedSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjChanged, 0); - assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjValueChanged, 1); - assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.compose.observerCounts.objValueChanged, 1); - assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.forward.observerCounts.objValueChanged, 1); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + verifyNestedObserversOutput(); }); test('notification from composed element property change', function() { // Setup - var nested = { - obj: { - value: 41 - } - }; - el.nested = nested; - el.expectedNestedSubpath = 'nested.obj.value'; - el.expectedNestedValue = 42; - el.expectedNestedObjSubpath = 'nested.obj.value'; - el.expectedNestedObjValue = 42; - el.$.compose.expectedObjSubpath = 'obj.value'; - el.$.compose.expectedObjValue = 42; - el.$.forward.expectedObjSubpath = 'obj.value'; - el.$.forward.expectedObjValue = 42; - el.$.forward.$.compose.expectedObjSubpath = 'obj.value'; - el.$.forward.$.compose.expectedObjValue = 42; - el.clearObserverCounts(); + setupNested(); // Do the thing el.$.compose.$.basic1.notifyingValue = 42; // Verify - assert.equal(el.observerCounts.nestedSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjChanged, 0); - assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjValueChanged, 1); - assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.compose.observerCounts.objValueChanged, 1); - assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.forward.observerCounts.objValueChanged, 1); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + verifyNestedObserversOutput(); }); test('notification from forward\'s composed element property change', function() { // Setup - var nested = { - obj: { - value: 41 - } - }; - el.nested = nested; - el.expectedNestedSubpath = 'nested.obj.value'; - el.expectedNestedValue = 42; - el.expectedNestedObjSubpath = 'nested.obj.value'; - el.expectedNestedObjValue = 42; - el.$.compose.expectedObjSubpath = 'obj.value'; - el.$.compose.expectedObjValue = 42; - el.$.forward.expectedObjSubpath = 'obj.value'; - el.$.forward.expectedObjValue = 42; - el.$.forward.$.compose.expectedObjSubpath = 'obj.value'; - el.$.forward.$.compose.expectedObjValue = 42; - el.clearObserverCounts(); + setupNested(); // Do the thing el.$.forward.$.compose.$.basic1.notifyingValue = 42; // Verify - assert.equal(el.observerCounts.nestedSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjChanged, 0); - assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjValueChanged, 1); - assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.compose.observerCounts.objValueChanged, 1); - assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.forward.observerCounts.objValueChanged, 1); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + verifyNestedObserversOutput(); }); test('notification from set in top element', function() { // Setup - var nested = { - obj: { - value: 41 - } - }; - el.nested = nested; - el.expectedNestedSubpath = 'nested.obj.value'; - el.expectedNestedValue = 42; - el.expectedNestedObjSubpath = 'nested.obj.value'; - el.expectedNestedObjValue = 42; - el.$.compose.expectedObjSubpath = 'obj.value'; - el.$.compose.expectedObjValue = 42; - el.$.forward.expectedObjSubpath = 'obj.value'; - el.$.forward.expectedObjValue = 42; - el.$.forward.$.compose.expectedObjSubpath = 'obj.value'; - el.$.forward.$.compose.expectedObjValue = 42; - el.clearObserverCounts(); + setupNested(); // Do the thing el.set('nested.obj.value', 42); // Verify - assert.equal(el.observerCounts.nestedSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjChanged, 0); - assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjValueChanged, 1); - assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.compose.observerCounts.objValueChanged, 1); - assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.forward.observerCounts.objValueChanged, 1); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + verifyNestedObserversOutput(); }); test('notification from set in composed element', function() { // Setup - var nested = { - obj: { - value: 41 - } - }; - el.nested = nested; - el.expectedNestedSubpath = 'nested.obj.value'; - el.expectedNestedValue = 42; - el.expectedNestedObjSubpath = 'nested.obj.value'; - el.expectedNestedObjValue = 42; - el.$.compose.expectedObjSubpath = 'obj.value'; - el.$.compose.expectedObjValue = 42; - el.$.forward.expectedObjSubpath = 'obj.value'; - el.$.forward.expectedObjValue = 42; - el.$.forward.$.compose.expectedObjSubpath = 'obj.value'; - el.$.forward.$.compose.expectedObjValue = 42; - el.clearObserverCounts(); + setupNested(); // Do the thing el.$.compose.set('obj.value', 42); // Verify - assert.equal(el.observerCounts.nestedSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjChanged, 0); - assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjValueChanged, 1); - assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.compose.observerCounts.objValueChanged, 1); - assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.forward.observerCounts.objValueChanged, 1); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + verifyNestedObserversOutput(); }); test('notification from set in forward element', function() { // Setup - var nested = { - obj: { - value: 41 - } - }; - el.nested = nested; - el.expectedNestedSubpath = 'nested.obj.value'; - el.expectedNestedValue = 42; - el.expectedNestedObjSubpath = 'nested.obj.value'; - el.expectedNestedObjValue = 42; - el.$.compose.expectedObjSubpath = 'obj.value'; - el.$.compose.expectedObjValue = 42; - el.$.forward.expectedObjSubpath = 'obj.value'; - el.$.forward.expectedObjValue = 42; - el.$.forward.$.compose.expectedObjSubpath = 'obj.value'; - el.$.forward.$.compose.expectedObjValue = 42; - el.clearObserverCounts(); + setupNested(); // Do the thing el.$.forward.set('obj.value', 42); // Verify - assert.equal(el.observerCounts.nestedSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjChanged, 0); - assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjValueChanged, 1); - assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.compose.observerCounts.objValueChanged, 1); - assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.forward.observerCounts.objValueChanged, 1); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + verifyNestedObserversOutput(); }); test('notification from set in forward\'s composed element', function() { // Setup - var nested = { - obj: { - value: 41 - } - }; - el.nested = nested; - el.expectedNestedSubpath = 'nested.obj.value'; - el.expectedNestedValue = 42; - el.expectedNestedObjSubpath = 'nested.obj.value'; - el.expectedNestedObjValue = 42; - el.$.compose.expectedObjSubpath = 'obj.value'; - el.$.compose.expectedObjValue = 42; - el.$.forward.expectedObjSubpath = 'obj.value'; - el.$.forward.expectedObjValue = 42; - el.$.forward.$.compose.expectedObjSubpath = 'obj.value'; - el.$.forward.$.compose.expectedObjValue = 42; - el.clearObserverCounts(); + setupNested(); // Do the thing el.$.forward.$.compose.set('obj.value', 42); // Verify - assert.equal(el.observerCounts.nestedSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjChanged, 0); - assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjValueChanged, 1); - assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.compose.observerCounts.objValueChanged, 1); - assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.forward.observerCounts.objValueChanged, 1); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + verifyNestedObserversOutput(); }); test('notification from object change in compose element', function() { // Setup - el.nested = { - obj: { - value: 41 - } - }; - var obj = { - value: 42 - }; - el.expectedNestedSubpath = 'nested.obj'; - el.expectedNestedValue = obj; - el.expectedNestedObjSubpath = 'nested.obj'; - el.expectedNestedObjValue = obj; - el.$.compose.expectedObjSubpath = 'obj'; - el.$.compose.expectedObjValue = obj; - el.$.forward.expectedObjSubpath = 'obj'; - el.$.forward.expectedObjValue = obj; - el.$.forward.$.compose.expectedObjSubpath = 'obj'; - el.$.forward.$.compose.expectedObjValue = obj; - el.clearObserverCounts(); + var obj = setupComposedAndGetObject(); // Do the thing el.$.compose.obj = obj; // Verify - assert.equal(el.observerCounts.nestedSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjChanged, 1); - assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjValueChanged, 1); - assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.compose.observerCounts.objValueChanged, 1); - assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.forward.observerCounts.objValueChanged, 1); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + verifyNonNestedObserversOutput(); }); test('notification from object change in forward element', function() { // Setup - el.nested = { - obj: { - value: 41 - } - }; - var obj = { - value: 42 - }; - el.expectedNestedSubpath = 'nested.obj'; - el.expectedNestedValue = obj; - el.expectedNestedObjSubpath = 'nested.obj'; - el.expectedNestedObjValue = obj; - el.$.compose.expectedObjSubpath = 'obj'; - el.$.compose.expectedObjValue = obj; - el.$.forward.expectedObjSubpath = 'obj'; - el.$.forward.expectedObjValue = obj; - el.$.forward.$.compose.expectedObjSubpath = 'obj'; - el.$.forward.$.compose.expectedObjValue = obj; - el.clearObserverCounts(); + var obj = setupComposedAndGetObject(); // Do the thing el.$.forward.obj = obj; // Verify - assert.equal(el.observerCounts.nestedSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjChanged, 1); - assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjValueChanged, 1); - assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.compose.observerCounts.objValueChanged, 1); - assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.forward.observerCounts.objValueChanged, 1); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + verifyNonNestedObserversOutput(); }); test('notification from object change in forward\'s compose element', function() { // Setup - el.nested = { - obj: { - value: 41 - } - }; - var obj = { - value: 42 - }; - el.expectedNestedSubpath = 'nested.obj'; - el.expectedNestedValue = obj; - el.expectedNestedObjSubpath = 'nested.obj'; - el.expectedNestedObjValue = obj; - el.$.compose.expectedObjSubpath = 'obj'; - el.$.compose.expectedObjValue = obj; - el.$.forward.expectedObjSubpath = 'obj'; - el.$.forward.expectedObjValue = obj; - el.$.forward.$.compose.expectedObjSubpath = 'obj'; - el.$.forward.$.compose.expectedObjValue = obj; - el.clearObserverCounts(); + var obj = setupComposedAndGetObject(); // Do the thing el.$.forward.$.compose.obj = obj; // Verify - assert.equal(el.observerCounts.nestedSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjChanged, 1); - assert.equal(el.observerCounts.nestedObjSubpathChanged, 1); - assert.equal(el.observerCounts.nestedObjValueChanged, 1); - assert.equal(el.$.compose.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.compose.observerCounts.objValueChanged, 1); - assert.equal(el.$.forward.observerCounts.objSubpathChanged, 1); - assert.equal(el.$.forward.observerCounts.objValueChanged, 1); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.basic.notifyingValue, 42); - assert.equal(el.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic1.notifyingValue, 42); - assert.equal(el.$.forward.$.compose.$.basic2.notifyingValue, 42); - assert.equal(el.$.basic.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42'); - assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42'); + verifyNonNestedObserversOutput(); }); test('negation', function() { From 0e248f5a3f8b86d2d55540cc70d9460b5b45ca00 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Fri, 30 Oct 2015 22:53:25 +0100 Subject: [PATCH 213/268] Produce nicer error on malformed observer --- src/standard/effectBuilder.html | 5 +++++ test/unit/notify-path.html | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/standard/effectBuilder.html b/src/standard/effectBuilder.html index b86d6e80..27730ec4 100644 --- a/src/standard/effectBuilder.html +++ b/src/standard/effectBuilder.html @@ -106,6 +106,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _addComplexObserverEffect: function(observer) { var sig = this._parseMethod(observer); + + if (!sig) { + throw new Error("Malformed observer expression '" + observer + "'"); + } + for (var i=0, arg; (i From 5033fdb29cd009ffc91b2c2fe59ff2c40cc7f4a4 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Wed, 9 Dec 2015 17:11:44 -0800 Subject: [PATCH 214/268] Consistently use TreeApi.Composed api for composed dom manipulation; use TreeApi.Logical methods to get node leaves. Avoid making a Polymer.dom when TreeApi.Logical can provide the needed info. --- src/lib/dom-api-classlist.html | 2 +- src/lib/dom-api-shady.html | 71 ++++++++++++++++----------------- src/lib/dom-api.html | 4 +- src/lib/dom-tree-api.html | 72 ++++++++++++++++++++++------------ src/mini/shady.html | 19 ++++----- 5 files changed, 91 insertions(+), 77 deletions(-) diff --git a/src/lib/dom-api-classlist.html b/src/lib/dom-api-classlist.html index 80d47208..a5ef7940 100644 --- a/src/lib/dom-api-classlist.html +++ b/src/lib/dom-api-classlist.html @@ -56,7 +56,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _distributeParent: function() { if (!useShadow) { - this.domApi._distributeParent(); + this.domApi._maybeDistributeParent(); } }, diff --git a/src/lib/dom-api-shady.html b/src/lib/dom-api-shady.html index 61888b38..8f034cd0 100644 --- a/src/lib/dom-api-shady.html +++ b/src/lib/dom-api-shady.html @@ -25,9 +25,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return; } - var nativeInsertBefore = Element.prototype.insertBefore; - var nativeRemoveChild = Element.prototype.removeChild; - var nativeAppendChild = Element.prototype.appendChild; var nativeCloneNode = Element.prototype.cloneNode; var nativeImportNode = Document.prototype.importNode; @@ -73,11 +70,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // if adding to a shadyRoot, add to host instead var container = this.node._isShadyRoot ? this.node.host : this.node; if (ref_node) { - nativeInsertBefore.call(container, node, ref_node); + TreeApi.Composed.insertBefore(container, node, ref_node); } else { - nativeAppendChild.call(container, node); + TreeApi.Composed.appendChild(container, node); } - TreeApi.Composed.recordInsertBefore(container, node, ref_node); } this.notifyObserver(); return node; @@ -105,8 +101,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN This method also performs dom composition. */ removeChild: function(node) { - if (dom(node).parentNode !== this.node) { - console.warn('The node to be removed is not a child of this node', + if (TreeApi.Logical.getParentNode(node) !== this.node) { + throw Error('The node to be removed is not a child of this node: ' + node); } if (!this._removeNode(node)) { @@ -115,8 +111,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // not guaranteed to physically be in container; e.g. // undistributed nodes. if (container === node.parentNode) { - nativeRemoveChild.call(container, node); - TreeApi.Composed.recordRemoveChild(container, node); + TreeApi.Composed.removeChild(container, node); } } this.notifyObserver(); @@ -128,8 +123,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // note that it's possible for both the node's host and its parent // to require distribution... both cases are handled here. _removeNode: function(node) { - TreeApi.Composed.recordRemoveChild( - TreeApi.Composed.getParentNode(node), node); // important that we want to do this only if the node has a logical parent var logicalParent = TreeApi.Logical.hasParentNode(node) && TreeApi.Logical.getParentNode(node); @@ -137,7 +130,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var root = this._ownerShadyRootForNode(node); if (logicalParent) { // distribute node's parent iff needed - distributed = dom(node)._distributeParent(); + distributed = dom(node)._maybeDistributeParent(); TreeApi.Logical.recordRemoveChild(node, logicalParent); // remove node from root and distribute it iff needed if (root && this._removeDistributedChildren(root, node)) { @@ -175,7 +168,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (node._isShadyRoot) { root = node; } else { - var parent = Polymer.dom(node).parentNode; + var parent = TreeApi.Logical.getParentNode(node); if (parent) { root = parent._isShadyRoot ? parent : this._ownerShadyRootForNode(parent); @@ -196,9 +189,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // distributeContent(true), which updates insertion points manually // and forces distribution. var fragContent = (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) && - !node.__noContent && Polymer.dom(node).querySelector(CONTENT); + !node.__noContent && dom(node).querySelector(CONTENT); var wrappedContent = fragContent && - (Polymer.dom(fragContent).parentNode.nodeType !== + (TreeApi.Logical.getParentNode(fragContent).nodeType !== Node.DOCUMENT_FRAGMENT_NODE); var hasContent = fragContent || (node.localName === CONTENT); // There are 2 possible cases where a distribution may need to occur: @@ -234,7 +227,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN !node.__noContent) { var c$ = dom(node).querySelectorAll(CONTENT); for (var i=0, n, np, na; (i ref_node + // update ref_node.previousSibling <-> node node.__previousSibling = ref_node ? ref_node.__previousSibling : container.__lastChild; if (node.__previousSibling) { node.__previousSibling.__nextSibling = node; } + // update node <-> ref_node node.__nextSibling = ref_node; - if (ref_node) { - ref_node.__previousSibling = node; + if (node.__nextSibling) { + node.__nextSibling.__previousSibling = node; } // update node <-> container node.__parentNode = container; - if (ref_node && ref_node === container.__firstChild) { - container.__firstChild = node; + if (ref_node) { + if (ref_node === container.__firstChild) { + container.__firstChild = node; + } } else { container.__lastChild = node; if (!container.__firstChild) { @@ -182,13 +206,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return node.parentNode; }, - recordInsertBefore: function(parent, node, ref_node) { + getFirstChild: function(node) { + return node.firstChild; }, - recordRemoveChild: function(parent, node) { + getLastChild: function(node) { + return node.lastChild; }, - recordParentNode: function(node, parent) { + getNextSibling: function(node) { + return node.nextSibling; + }, + + getPreviousSibling: function(node) { + return node.previousSibling; }, // composed tracking needs to reset composed children here in case @@ -200,24 +231,15 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, insertBefore: function(parentNode, newChild, refChild) { - var newChildParent = this.getParentNode(newChild); - if (newChildParent !== parentNode) { - this.recordRemoveChild(newChildParent, newChild); - } - // remove child from its old parent first - this.removeChild(newChild); - // insert it into the real DOM - nativeInsertBefore.call(parentNode, newChild, refChild || null); - this.recordParentNode(newChild, parentNode); + return nativeInsertBefore.call(parentNode, newChild, refChild || null); }, - removeChild: function(node) { - var parentNode = this.getParentNode(node); - if (parentNode) { - this.recordParentNode(node, null); - // remove it from the real DOM - nativeRemoveChild.call(parentNode, node); - } + appendChild: function(parentNode, newChild) { + return nativeAppendChild.call(parentNode, newChild); + }, + + removeChild: function(parentNode, node) { + return nativeRemoveChild.call(parentNode, node); } }; diff --git a/src/mini/shady.html b/src/mini/shady.html index 5d446a31..90ae45dd 100644 --- a/src/mini/shady.html +++ b/src/mini/shady.html @@ -121,22 +121,19 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN */ distributeContent: function(updateInsertionPoints) { if (this.shadyRoot) { - var dom = Polymer.dom(this); - if (updateInsertionPoints) { - dom._updateInsertionPoints(this); - } + this.shadyRoot._invalidInsertionPoints = + this.shadyRoot._invalidInsertionPoints || updateInsertionPoints; // Distribute the host that's the top of this element's distribution // tree. Distributing that host will *always* distibute this element. var host = getTopDistributingHost(this); - dom._lazyDistribute(host); + Polymer.dom(this)._lazyDistribute(host); } }, _distributeContent: function() { if (this._useContent && !this.shadyRoot._distributionClean) { if (this.shadyRoot._invalidInsertionPoints) { - var dom = Polymer.dom(this); - dom._updateInsertionPoints(this); + Polymer.dom(this)._updateInsertionPoints(this); this.shadyRoot._invalidInsertionPoints = false; } // logically distribute self @@ -298,7 +295,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this._updateChildNodes(this, this._composeNode(this)); var p$ = this.shadyRoot._insertionPoints; for (var i=0, l=p$.length, p, parent; (i Date: Wed, 9 Dec 2015 17:55:14 -0800 Subject: [PATCH 215/268] Polymer.dom: when adding a node, only remove the node from its existing location if it's not a fragment and has a parent. --- src/lib/dom-api-shady.html | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/lib/dom-api-shady.html b/src/lib/dom-api-shady.html index 8f034cd0..a729c161 100644 --- a/src/lib/dom-api-shady.html +++ b/src/lib/dom-api-shady.html @@ -55,12 +55,19 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN throw Error('The ref_node to be inserted before is not a child ' + 'of this node'); } - // notify existing parent that this node is being removed. - var parent = TreeApi.Logical.getParentNode(node); - if (parent && DomApi.hasApi(parent)) { - dom(parent).notifyObserver(); + // remove node from its current position iff it's in a tree. + if (node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) { + var parent = TreeApi.Logical.getParentNode(node); + // notify existing parent that this node is being removed. + if (parent) { + if (DomApi.hasApi(parent)) { + dom(parent).notifyObserver(); + } + this._removeNode(node); + } else { + this._removeOwnerShadyRoot(node); + } } - this._removeNode(node); if (!this._addNode(node, ref_node)) { if (ref_node) { // if ref_node is replace with first distributed node From fadd455e0d464e83dfc53b2645322948721965fc Mon Sep 17 00:00:00 2001 From: Eric Bidelman Date: Mon, 30 Nov 2015 14:55:47 -0800 Subject: [PATCH 216/268] Fixes #3113 --- src/standard/utils.html | 22 ++++++++++++------ test/unit/dynamic-import.html | 23 ++++++++++++++++++- .../unit/dynamic-imports/dynamic-element.html | 6 ++--- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/standard/utils.html b/src/standard/utils.html index 84528710..8f8f5fe9 100644 --- a/src/standard/utils.html +++ b/src/standard/utils.html @@ -164,7 +164,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN /** * Returns a list of nodes distributed to this element's ``. * - * If this element contans more than one `` in its local DOM, + * If this element contains more than one `` in its local DOM, * an optional selector may be passed to choose the desired content. * * @method getContentChildNodes @@ -181,7 +181,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * Returns a list of element children distributed to this element's * ``. * - * If this element contans more than one `` in its + * If this element contains more than one `` in its * local DOM, an optional selector may be passed to choose the desired * content. This method differs from `getContentChildNodes` in that only * elements are returned. @@ -198,7 +198,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }); }, - + /** * Dispatches a custom event with an optional detail value. * @@ -234,13 +234,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN __eventCache: {}, // NOTE: We optionally cache event objects for efficiency during high - // freq. opts. This option cannot be used for events which may have + // freq. opts. This option cannot be used for events which may have // `stopPropagation` called on them. On Chrome and Safari (but not FF) - // if `stopPropagation` is called, the event cannot be reused. It does not + // if `stopPropagation` is called, the event cannot be reused. It does not // dispatch again. _getEvent: function(type, bubbles, cancelable, useCache) { var event = useCache && this.__eventCache[type]; - if (!event || ((event.bubbles != bubbles) || + if (!event || ((event.bubbles != bubbles) || (event.cancelable != cancelable))) { event = new Event(type, { bubbles: Boolean(bubbles), @@ -358,12 +358,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN * loaded. * @param {Function} onerror Callback to notify when an import * unsuccessfully loaded. + * @param {boolean} optAsync True if the import should be loaded `async`. + * Defaults to `false`. * @return {HTMLLinkElement} The link element for the URL to be loaded. */ - importHref: function(href, onload, onerror) { + importHref: function(href, onload, onerror, optAsync) { var l = document.createElement('link'); l.rel = 'import'; l.href = href; + + optAsync = Boolean(optAsync); + if (optAsync) { + l.setAttribute('async', ''); + } + var self = this; if (onload) { l.onload = function(e) { diff --git a/test/unit/dynamic-import.html b/test/unit/dynamic-import.html index 983f05a4..c4c94588 100644 --- a/test/unit/dynamic-import.html +++ b/test/unit/dynamic-import.html @@ -20,7 +20,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN diff --git a/test/unit/dynamic-imports/dynamic-element.html b/test/unit/dynamic-imports/dynamic-element.html index 7b5b1467..3233e3fb 100644 --- a/test/unit/dynamic-imports/dynamic-element.html +++ b/test/unit/dynamic-imports/dynamic-element.html @@ -12,12 +12,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN \ No newline at end of file + From b9e6859cde2b50d0a685ab13afc5aa081b9f44e1 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 11 Dec 2015 11:27:52 -0800 Subject: [PATCH 217/268] Updates the patch-don experiment to work with recent changes. --- src/lib/dom-api.html | 4 +- src/lib/experimental/patch-dom.html | 322 ++++++++++++++++++++++++---- test/smoke/patch/patch-dom.html | 18 +- test/smoke/patch/smoke.html | 79 +++++++ 4 files changed, 366 insertions(+), 57 deletions(-) create mode 100644 test/smoke/patch/smoke.html diff --git a/src/lib/dom-api.html b/src/lib/dom-api.html index 237994bb..0a45d9e0 100644 --- a/src/lib/dom-api.html +++ b/src/lib/dom-api.html @@ -140,10 +140,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var CONTENT = DomApi.CONTENT = 'content'; - var dom = DomApi.factory = function(node, patch) { + var dom = DomApi.factory = function(node) { node = node || document; if (!node.__domApi) { - node.__domApi = new DomApi(node, patch); + node.__domApi = new DomApi.ctor(node); } return node.__domApi; }; diff --git a/src/lib/experimental/patch-dom.html b/src/lib/experimental/patch-dom.html index eb78eedc..397c40b2 100644 --- a/src/lib/experimental/patch-dom.html +++ b/src/lib/experimental/patch-dom.html @@ -22,7 +22,19 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN (function() { + // ******* Only patch if we're using Shady DOM ******* + if (Polymer.Settings.useShadow) { + return; + } + var baseFinishDistribute = Polymer.Base._finishDistribute; + var TreeApi = Polymer.TreeApi; + var DomApi = Polymer.DomApi; + var dom = Polymer.dom; + + var nativeInsertBefore = Element.prototype.insertBefore; + var nativeAppendChild = Element.prototype.appendChild; + var nativeRemoveChild = Element.prototype.removeChild; // NOTE: any manipulation of a node must occur in a patched parent // so that the parent can cleanup the node's composed and logical @@ -30,13 +42,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // likely to be satisfied. // Also note that any use of qS/qSA must be done in a patched node. Polymer.Base._finishDistribute = function() { + var hasDistributed = this.root._hasDistributed; baseFinishDistribute.call(this); - if (!this.__patched) { + if (!hasDistributed) { + for (var n=this.firstChild; n; n=n.nextSibling) { + Polymer.dom(n); + }; Polymer.dom(this); Polymer.dom(this.root); - Array.prototype.forEach.call(this.childNodes, function(c) { - Polymer.dom(c); - }); // TODO(sorvell): ensure top element's parents are wrapped (helped A2 // since it uses qSA on the fragment containing stamped custom elements) // note that getOwnerRoot will patch all parents but there should be an @@ -48,34 +61,31 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }; - var saveLightChildrenIfNeeded = Polymer.DomApi.saveLightChildrenIfNeeded; - var getComposedChildren = Polymer.DomApi.getComposedChildren; - - var nativeShadow = Polymer.Settings.useShadow; - var excluded = ['head']; Polymer.telemetry.patched = 0; - // experimental: support patching selected native api. - Polymer.DomApi.ctor.prototype.patch = function(force) { - if (nativeShadow || this.node.__patched || - (this.node.localName && excluded.indexOf(this.node.localName) >= 0)) { - return; - } + var ctor = Polymer.DomApi.ctor; + Polymer.DomApi.ctor = function(node) { + Polymer.DomApi.patch(node); + return new ctor(node); + } - getComposedChildren(this.node); - saveLightChildrenIfNeeded(this.node); - if (!this.node._lightParent) { - this.node._lightParent = this.node.parentNode; - } - if (!this.node._composedParent) { - this.node._composedParent = this.node.parentNode; - } - // TODO(sorvell): correctly patch non-element nodes. - if (this.node.nodeType !== Node.TEXT_NODE) { - this.node.__patched = true; - patchImpl.patch(this.node); + Polymer.DomApi.ctor.prototype = ctor.prototype; + + Polymer.DomApi.patch = function(node) { + if (!node.__patched && + (!node.localName || !excluded.indexOf(node.localName) >= 0)) { + TreeApi.Logical.saveChildNodes(node); + if (!TreeApi.Composed.hasParentNode(node)) { + TreeApi.Composed.saveParentNode(node); + } + TreeApi.Composed.saveChildNodes(node); + // TODO(sorvell): correctly patch non-element nodes. + if (node.nodeType !== Node.TEXT_NODE) { + node.__patched = true; + patchImpl.patch(node); + } } }; @@ -90,9 +100,21 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this.unpatch(); }; - var log = false; + // allows attribute setting to be patched + var nativeSetAttribute = Element.prototype.setAttribute; + Polymer.DomApi.ctor.prototype.setAttribute = function(name, value) { + nativeSetAttribute.call(this.node, name, value); + this._maybeDistributeParent(); + }; - var factory = Polymer.DomApi.factory; + var nativeRemoveAttribute = Element.prototype.removeAttribute; + Polymer.DomApi.ctor.prototype.removeAttribute = function(name, value) { + nativeRemoveAttribute.call(this.node, name); + this._maybeDistributeParent(); + }; + + + var log = false; var patchImpl = { @@ -101,7 +123,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN methods: ['appendChild', 'insertBefore', 'removeChild', 'replaceChild', 'querySelector', 'querySelectorAll', 'getDestinationInsertionPoints', - 'cloneNode', 'importNode'], + 'cloneNode', /*'importNode',*/ 'setAttribute', 'removeAttribute'], // : getDistributedNodes accessors: ['parentNode', 'childNodes', @@ -160,7 +182,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN obj['_$' + name + '$_'] = orig; obj[name] = function() { log && console.log(this, name, arguments); - return factory(this)[name].apply(this.__domApi, arguments); + return dom(this)[name].apply(this.__domApi, arguments); }; }, @@ -170,14 +192,17 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } var info = { get: function() { - log && console.log(this, name); - return factory(this)[name]; + //log && console.log(this, name); + if (window.nug) { + debugger; + } + return dom(this)[name]; }, configurable: true }; if (writable) { info.set = function(value) { - factory(this)[name] = value; + dom(this)[name] = value; }; } Object.defineProperty(obj, name, info); @@ -216,20 +241,225 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }; - Polymer.DomApi.getLightChildren = function(node) { - var children = node._lightChildren; - return children ? children : Polymer.DomApi.getComposedChildren(node); - } - - Polymer.Base.instanceTemplate = function(template) { - var m = document._$importNode$_ || document.importNode; - var dom = - m.call(document, template._content || template.content, true); - return dom; - } - Polymer.DomApi.patchImpl = patchImpl; + Polymer.TreeApi.Logical.saveChildNodes = function(node) { + if (!this.hasChildNodes(node)) { + node.__firstChild = node.firstChild; + node.__lastChild = node.lastChild; + node.__childNodes = []; + for (var n=TreeApi.Composed.getFirstChild(node); n; + n=TreeApi.Composed.getNextSibling(n)) { + n.__parentNode = node; + node.__childNodes.push(n); + n.__nextSibling = TreeApi.Composed.getNextSibling(n); + n.__previousSibling = TreeApi.Composed.getPreviousSibling(n); + } + } + } + + Polymer.TreeApi.Logical.recordInsertBefore = + function(node, container, ref_node) { + container.__childNodes = null; + // handle document fragments + if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { + // TODO(sorvell): remember this for patching: + // the act of setting this info can affect patched nodes + // getters; therefore capture childNodes before patching. + for (var n=TreeApi.Composed.getFirstChild(node); n; + n=TreeApi.Composed.getNextSibling(n)) { + this._linkNode(n, container, ref_node); + } + } else { + this._linkNode(node, container, ref_node); + } + } + + Polymer.TreeApi.Composed = { + + + ensureParentNodes: function(parent, children) { + }, + + hasParentNode: function(node) { + return Boolean(node.__composedParent !== undefined); + }, + + hasChildNodes: function(node) { + return Boolean(node.__composedChildNodes !== undefined); + }, + + getChildNodes: function(node) { + // return node.__composedChildNodes || + // (!node.__patched && TreeApi.arrayCopy(node.childNodes)); + return (node.__composedChildNodes && + TreeApi.arrayCopy(node.__composedChildNodes)) || + (!node.__patched && TreeApi.arrayCopy(node.childNodes)); + }, + + getComposedChildNodes: function(node) { + return node.__composedChildNodes; + }, + + getParentNode: function(node) { + return this.hasParentNode(node) ? node.__composedParent : + (!node.__patched && node.parentNode); + }, + + getFirstChild: function(node) { + if (node.__patched) { + return this.getChildNodes(node)[0]; + } else { + return node.firstChild; + } + }, + + getLastChild: function(node) { + if (node.__patched) { + var c$ = this.getChildNodes(node); + return c$[c$.length-1]; + } else { + return node.lastChild; + } + }, + + getNextSibling: function(node) { + // TODO(sorvell): linked list + var parent = this.getParentNode(node); + //if (parent.__patched) { + var c$ = this.getChildNodes(parent); + var i = c$.indexOf(node); + return c$[i+1]; + //} else if (!node.__patched) { + // return node.nextSibling; + //} + }, + + getPreviousSibling: function(node) { + // TODO(sorvell): linked list + var parent = this.getParentNode(node); + //if (parent.__patched) { + var c$ = this.getChildNodes(parent); + var i = c$.indexOf(node); + return c$[i-1]; + //} else if (!node.__patched) { + // return node.previousSibling; + //} + }, + + // composed tracking needs to reset composed children here in case + // they may have already been set (this shouldn't happen but can + // if dependency ordering is incorrect and as a result upgrade order + // is unexpected) + clearChildNodes: function(node) { + if (node.__composedParent) { + node.__composedParent.__composedChildNodes = []; + } + node.textContent = ''; + }, + + saveChildNodes: function(node) { + var c$ = node.__composedChildNodes = []; + for (var n=node.firstChild; n; n=n.nextSibling) { + n.__composedParent = node; + c$.push(n); + } + }, + + saveParentNode: function(node) { + node.__composedParent = node.parentNode; + }, + + insertBefore: function(parentNode, newChild, refChild) { + if (!this.hasChildNodes(parentNode)) { + this.saveChildNodes(parentNode); + } + // remove from current location. + if (this.hasParentNode(newChild)) { + var oldParent = this.getParentNode(newChild); + if (oldParent) { + this._removeChild(oldParent, newChild); + } + } + this._addChild(parentNode, newChild, refChild); + return nativeInsertBefore.call(parentNode, newChild, refChild || null); + }, + + appendChild: function(parentNode, newChild) { + if (!this.hasChildNodes(parentNode)) { + this.saveChildNodes(parentNode); + } + // remove from current location. + if (this.hasParentNode(newChild)) { + var oldParent = this.getParentNode(newChild); + if (oldParent) { + this._removeChild(oldParent, newChild); + } + } + this._addChild(parentNode, newChild); + return nativeAppendChild.call(parentNode, newChild); + }, + + removeChild: function(parentNode, node) { + var currentParent = this.getParentNode(node); + if (!this.hasChildNodes(parentNode)) { + this.saveChildNodes(parentNode); + } + this._removeChild(parentNode, node); + if (currentParent === parentNode) { + if (!node.__patched && node.parentNode !== node.__composedParent) { + //console.warn('composedParent wrong for', node); + return; + } + return nativeRemoveChild.call(parentNode, node); + } + }, + + _addChild: function(parentNode, newChild, refChild) { + if (newChild.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { + var c$ = this.getChildNodes(newChild); + for (var j=0; j < c$.length; j++) { + this._addChild(parentNode, c$[j], refChild); + } + } else { + newChild.__composedParent = parentNode; + var c$ = this.getComposedChildNodes(parentNode); + if (c$) { + var i = c$.indexOf(refChild); + i = i === -1 ? c$.length : i; + c$.splice(i, 0, newChild); + } + } + }, + + _removeChild: function(parentNode, node) { + node.__composedParent = null; + var c$ = this.getComposedChildNodes(parentNode); + if (c$) { + var i = c$.indexOf(node); + if (i >= 0) { + c$.splice(i, 1); + } + } + } + + }; + + // TODO(sorvell): only necessary if we allow document.importNode to be patched. + // var nativeImportNode = document.importNode; + // Polymer.Base.instanceTemplate = function(template) { + // return nativeImportNode.call(document, + // template._content || template.content, true); + // } + + // patch important nodes + if (window.document) { + Polymer.dom(document); + if (document.body) { + Polymer.dom(document.body); + } + } + })(); diff --git a/test/smoke/patch/patch-dom.html b/test/smoke/patch/patch-dom.html index 1e223e6a..9cdc74df 100644 --- a/test/smoke/patch/patch-dom.html +++ b/test/smoke/patch/patch-dom.html @@ -253,19 +253,19 @@ suite('Polymer.dom (patch)', function() { assert.equal(s.parentNode, rere); Polymer.dom.flush(); if (rere.shadyRoot) { - assert.notEqual(s._composedParent, rere); + assert.notEqual(s.__composedParent, rere); } Polymer.dom.flush(); if (rere.shadyRoot) { - assert.equal(s._composedParent, p); + assert.equal(s.__composedParent, p); } rere.removeChild(s); if (rere.shadyRoot) { - assert.equal(s._composedParent, p); + assert.equal(s.__composedParent, p); } Polymer.dom.flush(); if (rere.shadyRoot) { - assert.equal(s._composedParent, null); + assert.equal(s.__composedParent, null); } }); @@ -374,13 +374,13 @@ suite('Polymer.dom non-distributed elements', function() { function testNoAttr() { assert.equal(Polymer.dom(child).getDestinationInsertionPoints()[0], d.$.notTestContent, 'child not distributed logically'); if (shady) { - assert.equal(child._composedParent, d.$.notTestContainer, 'child not rendered in composed dom'); + assert.equal(child.__composedParent, d.$.notTestContainer, 'child not rendered in composed dom'); } } function testWithAttr() { assert.equal(Polymer.dom(child).getDestinationInsertionPoints()[0], d.$.testContent, 'child not distributed logically'); if (shady) { - assert.equal(child._composedParent, d.$.testContainer, 'child not rendered in composed dom'); + assert.equal(child.__composedParent, d.$.testContainer, 'child not rendered in composed dom'); } } // test with x-distribute @@ -395,17 +395,17 @@ suite('Polymer.dom non-distributed elements', function() { testNoAttr(); // set / unset `test` attr and see if it distributes properly child.setAttribute('test', ''); - d.distributeContent(); + //d.distributeContent(); Polymer.dom.flush(); testWithAttr(); // child.removeAttribute('test'); - d.distributeContent(); + //d.distributeContent(); Polymer.dom.flush(); testNoAttr(); // child.setAttribute('test', ''); - d.distributeContent(); + //d.distributeContent(); Polymer.dom.flush(); testWithAttr(); }); diff --git a/test/smoke/patch/smoke.html b/test/smoke/patch/smoke.html new file mode 100644 index 00000000..e8d59c17 --- /dev/null +++ b/test/smoke/patch/smoke.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + + +
header 1
+
footer 1
+
+ + + + + + + + + + From da5d781b3dd8db732b668e284be13af84c5e4c12 Mon Sep 17 00:00:00 2001 From: Hayko Koryun Date: Mon, 14 Dec 2015 00:32:34 +0400 Subject: [PATCH 218/268] added polymer-mini and polymer-micro to main Fixes #2617 by adding both files to main so they get copied over. When using `bower-installer` (when I don't want to send dev files to production servers, and vulcanisation isn't set up yet) currently only `polymer.html` gets copied over. This fixes that. --- bower.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 8f88ea2d..b6655cda 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,9 @@ "name": "polymer", "version": "1.2.3", "main": [ - "polymer.html" + "polymer.html", + "polymer-mini.html", + "polymer-micro.html" ], "license": "http://polymer.github.io/LICENSE.txt", "ignore": [ From c3fbd10da8a1da33a5b560d442c1061db200b2cf Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 14 Dec 2015 11:41:25 -0800 Subject: [PATCH 219/268] remove unused code; minor changes based on review. --- src/lib/experimental/patch-dom.html | 42 +++++++++-------------------- src/mini/shady.html | 2 -- test/smoke/patch/patch-dom.html | 36 ------------------------- 3 files changed, 13 insertions(+), 67 deletions(-) diff --git a/src/lib/experimental/patch-dom.html b/src/lib/experimental/patch-dom.html index 397c40b2..e1005d54 100644 --- a/src/lib/experimental/patch-dom.html +++ b/src/lib/experimental/patch-dom.html @@ -123,7 +123,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN methods: ['appendChild', 'insertBefore', 'removeChild', 'replaceChild', 'querySelector', 'querySelectorAll', 'getDestinationInsertionPoints', - 'cloneNode', /*'importNode',*/ 'setAttribute', 'removeAttribute'], + 'cloneNode', 'setAttribute', 'removeAttribute'], // : getDistributedNodes accessors: ['parentNode', 'childNodes', @@ -192,10 +192,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } var info = { get: function() { - //log && console.log(this, name); - if (window.nug) { - debugger; - } return dom(this)[name]; }, configurable: true @@ -243,6 +239,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.DomApi.patchImpl = patchImpl; + // NOTE: patch logical implementations here so we can use + // composed getters Polymer.TreeApi.Logical.saveChildNodes = function(node) { if (!this.hasChildNodes(node)) { node.__firstChild = node.firstChild; @@ -277,10 +275,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.TreeApi.Composed = { - - ensureParentNodes: function(parent, children) { - }, - hasParentNode: function(node) { return Boolean(node.__composedParent !== undefined); }, @@ -290,10 +284,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, getChildNodes: function(node) { - // return node.__composedChildNodes || - // (!node.__patched && TreeApi.arrayCopy(node.childNodes)); - return (node.__composedChildNodes && - TreeApi.arrayCopy(node.__composedChildNodes)) || + return node.__composedChildNodes || (!node.__patched && TreeApi.arrayCopy(node.childNodes)); }, @@ -326,25 +317,25 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN getNextSibling: function(node) { // TODO(sorvell): linked list var parent = this.getParentNode(node); - //if (parent.__patched) { + if (parent.__patched) { var c$ = this.getChildNodes(parent); var i = c$.indexOf(node); return c$[i+1]; - //} else if (!node.__patched) { - // return node.nextSibling; - //} + } else if (!node.__patched) { + return node.nextSibling; + } }, getPreviousSibling: function(node) { // TODO(sorvell): linked list var parent = this.getParentNode(node); - //if (parent.__patched) { + if (parent.__patched) { var c$ = this.getChildNodes(parent); var i = c$.indexOf(node); return c$[i-1]; - //} else if (!node.__patched) { - // return node.previousSibling; - //} + } else if (!node.__patched) { + return node.previousSibling; + } }, // composed tracking needs to reset composed children here in case @@ -407,8 +398,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } this._removeChild(parentNode, node); if (currentParent === parentNode) { + // TODO(sorvell); abort if the composedParent is not expected... if (!node.__patched && node.parentNode !== node.__composedParent) { - //console.warn('composedParent wrong for', node); return; } return nativeRemoveChild.call(parentNode, node); @@ -445,13 +436,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }; - // TODO(sorvell): only necessary if we allow document.importNode to be patched. - // var nativeImportNode = document.importNode; - // Polymer.Base.instanceTemplate = function(template) { - // return nativeImportNode.call(document, - // template._content || template.content, true); - // } - // patch important nodes if (window.document) { Polymer.dom(document); diff --git a/src/mini/shady.html b/src/mini/shady.html index 90ae45dd..314a6fb8 100644 --- a/src/mini/shady.html +++ b/src/mini/shady.html @@ -353,8 +353,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN composed.splice(j, 0, n); } } - // ensure composed parent is set - TreeApi.Composed.ensureParentNodes(container, children); }, _matchesContentSelect: function(node, contentElement) { diff --git a/test/smoke/patch/patch-dom.html b/test/smoke/patch/patch-dom.html index 9cdc74df..1db4259f 100644 --- a/test/smoke/patch/patch-dom.html +++ b/test/smoke/patch/patch-dom.html @@ -247,8 +247,6 @@ suite('Polymer.dom (patch)', function() { s.id = 'light'; s.textContent = 'Light'; rere.appendChild(s); - // TODO(sorvell); patch - Polymer.dom(s); assert.equal(rere.querySelector('#light'), s); assert.equal(s.parentNode, rere); Polymer.dom.flush(); @@ -298,35 +296,6 @@ suite('Polymer.dom (patch)', function() { assert.notOk(projected); }); - test('Polymer.dom event', function() { - var test = document.querySelector('x-test'); - var rere = test.root.querySelector('x-rereproject'); - var re = rere.root.querySelector('x-reproject'); - var p = re.root.querySelector('x-project'); - var eventHandled = 0; - test.addEventListener('test-event', function(e) { - eventHandled++; - assert.equal(Polymer.dom(e).rootTarget, p); - assert.equal(Polymer.dom(e).localTarget, test); - var path = Polymer.dom(e).path; - // 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], test); - }); - - rere.addEventListener('test-event', function(e) { - eventHandled++; - assert.equal(Polymer.dom(e).localTarget, rere); - }); - - p.fire('test-event'); - assert.equal(eventHandled, 2); - }); - test('Polymer.dom.childNodes is an array', function() { assert.isTrue(Array.isArray(Polymer.dom(document.body).childNodes)); }); @@ -395,17 +364,12 @@ suite('Polymer.dom non-distributed elements', function() { testNoAttr(); // 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(); }); From d135fef14a2131c085a4665577cd9df41670316a Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 14 Dec 2015 12:30:56 -0800 Subject: [PATCH 220/268] Shady patching: patch element accessors in composed tree; fixes HTMLImports polyfill support. --- src/lib/dom-api-shady.html | 41 ++---------------- src/lib/dom-tree-api.html | 64 ++++++++++++++++++++++++++++ src/lib/experimental/patch-dom.html | 66 +++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 37 deletions(-) diff --git a/src/lib/dom-api-shady.html b/src/lib/dom-api-shady.html index a729c161..461566cd 100644 --- a/src/lib/dom-api-shady.html +++ b/src/lib/dom-api-shady.html @@ -502,61 +502,28 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN firstElementChild: { get: function() { - if (this.node.__firstChild) { - var n = this.node.__firstChild; - while (n && n.nodeType !== Node.ELEMENT_NODE) { - n = n.__nextSibling; - } - return n; - } else { - return this.node.firstElementChild; - } - + return TreeApi.Logical.getFirstElementChild(this.node); }, configurable: true }, lastElementChild: { get: function() { - if (this.node.__lastChild) { - var n = this.node.__lastChild; - while (n && n.nodeType !== Node.ELEMENT_NODE) { - n = n.__previousSibling; - } - return n; - } else { - return this.node.lastElementChild; - } + return TreeApi.Logical.getLastElementChild(this.node); }, configurable: true }, nextElementSibling: { get: function() { - if (this.node.__nextSibling) { - var n = this.node.__nextSibling; - while (n && n.nodeType !== Node.ELEMENT_NODE) { - n = n.__nextSibling; - } - return n; - } else { - return this.node.nextElementSibling; - } + return TreeApi.Logical.getNextElementSibling(this.node); }, configurable: true }, previousElementSibling: { get: function() { - if (this.node.__previousSibling) { - var n = this.node.__previousSibling; - while (n && n.nodeType !== Node.ELEMENT_NODE) { - n = n.__previousSibling; - } - return n; - } else { - return this.node.previousElementSibling; - } + return TreeApi.Logical.getPreviousElementSibling(this.node); }, configurable: true }, diff --git a/src/lib/dom-tree-api.html b/src/lib/dom-tree-api.html index eaf81474..a1889cab 100644 --- a/src/lib/dom-tree-api.html +++ b/src/lib/dom-tree-api.html @@ -104,6 +104,54 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return node.__previousSibling || TreeApi.Composed.getPreviousSibling(node); }, + getFirstElementChild: function(node) { + if (node.__firstChild) { + var n = node.__firstChild; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__nextSibling; + } + return n; + } else { + return TreeApi.Composed.getFirstElementChild(node); + } + }, + + getLastElementChild: function(node) { + if (node.__lastChild) { + var n = node.__lastChild; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__previousSibling; + } + return n; + } else { + return TreeApi.Composed.getLastElementChild(node); + } + }, + + getNextElementSibling: function(node) { + if (node.__nextSibling) { + var n = node.__nextSibling; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__nextSibling; + } + return n; + } else { + return TreeApi.Composed.getNextElementSibling(node); + } + }, + + getPreviousElementSibling: function(node) { + if (node.__previousSibling) { + var n = node.__previousSibling; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__previousSibling; + } + return n; + } else { + return TreeApi.Composed.getPreviousElementSibling(node); + } + }, + // Capture the list of light children. It's important to do this before we // start transforming the DOM into "rendered" state. // Children may be added to this list dynamically. It will be treated as the @@ -222,6 +270,22 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return node.previousSibling; }, + getFirstElementChild: function(node) { + return node.firstElementChild; + }, + + getLastElementChild: function(node) { + return node.lastElementChild; + }, + + getNextElementSibling: function(node) { + return node.nextElementSibling; + }, + + getPreviousElementSibling: function(node) { + return node.previousElementSibling; + }, + // composed tracking needs to reset composed children here in case // they may have already been set (this shouldn't happen but can // if dependency ordering is incorrect and as a result upgrade order diff --git a/src/lib/experimental/patch-dom.html b/src/lib/experimental/patch-dom.html index e1005d54..571983e6 100644 --- a/src/lib/experimental/patch-dom.html +++ b/src/lib/experimental/patch-dom.html @@ -27,6 +27,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return; } + count = 0; + var baseFinishDistribute = Polymer.Base._finishDistribute; var TreeApi = Polymer.TreeApi; var DomApi = Polymer.DomApi; @@ -116,6 +118,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var log = false; + var count = 0; + var patchImpl = { hasPrototypeDescriptors: Boolean(Object.getOwnPropertyDescriptor( @@ -338,6 +342,68 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } }, + getFirstElementChild: function(node) { + if (node.__patched) { + var c$ = this.getChildNodes(node); + for (var i=0, n; i < c$.length; i++) { + n = c$[i]; + if (n.nodeType === Node.ELEMENT_NODE) { + return n; + } + } + } else { + return node.firstElementChild; + } + }, + + getLastElementChild: function(node) { + if (node.__patched) { + var c$ = this.getChildNodes(node); + for (var i=c$.length, n; i >=0 ; i--) { + n = c$[i]; + if (n.nodeType === Node.ELEMENT_NODE) { + return n; + } + } + } else { + return node.lastElementChild; + } + }, + + getNextElementSibling: function(node) { + if (node.__patched) { + var c$ = this.getChildNodes(node); + var i = c$.indexOf(node); + if (i >= 0) { + for (var n; i < c$.length; i++) { + n = c$[i]; + if (n.nodeType === Node.ELEMENT_NODE) { + return n; + } + } + } + } else { + return node.nextElementSibling; + } + }, + + getPreviousElementSibling: function(node) { + if (node.__patched) { + var c$ = this.getChildNodes(node); + var i = c$.indexOf(node); + if (i >= 0) { + for (var n; i >=0 ; i--) { + n = c$[i]; + if (n.nodeType === Node.ELEMENT_NODE) { + return n; + } + } + } + } else { + return node.previousElementSibling; + } + }, + // composed tracking needs to reset composed children here in case // they may have already been set (this shouldn't happen but can // if dependency ordering is incorrect and as a result upgrade order From 82b2443a1deb80267f84c470c121baf67c440968 Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Mon, 14 Dec 2015 15:57:17 -0800 Subject: [PATCH 221/268] Add more globals to whitelist for safari Fixes #3199 --- package.json | 2 +- test/unit/globals.html | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 02d16f0f..f886a96a 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "lazypipe": "^0.2.3", "polyclean": "^1.2.0", "run-sequence": "^1.1.0", - "web-component-tester": "^3.3.21" + "web-component-tester": "^4" }, "scripts": { "build": "gulp", diff --git a/test/unit/globals.html b/test/unit/globals.html index cb15ad98..3978314b 100644 --- a/test/unit/globals.html +++ b/test/unit/globals.html @@ -40,6 +40,11 @@ suite('globals', function() { // Polymer Polymer: true, currentImport: true + + // weird safari + selenium globals + alert: true, + confirm: true, + prompt: true }; test('check global leakage', function() { From 2b69bb14968e9f6f642006118e60cccb42a6af02 Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Mon, 14 Dec 2015 16:04:13 -0800 Subject: [PATCH 222/268] Modernize the build --- .travis.yml | 9 ++++++--- test/unit/globals.html | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ee77195f..9d3a1a94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,18 @@ language: node_js sudo: false -node_js: 4 +node_js: stable addons: firefox: latest + sauce_connect: true apt: sources: - google-chrome + - ubuntu-toolchain-r-test packages: - google-chrome-stable + - g++-4.8 before_script: -- npm install bower -- export PATH=$PWD/node_modules/.bin:$PATH +- npm install -g bower - bower install script: - xvfb-run wct @@ -19,3 +21,4 @@ env: global: - secure: eFrp9xwSYG579rAR9/XyXYKh+UtIQJ1xS5q5PABu4ndYFckdJb8o3m7oXqRSikbiPWbCSd3Fkd6+ZKXlcQFdjJ+nx9gFitGthtH93qkvZCO3XhWEEBPj65igIo3hrRSOB6dIWyiZcnoH9IXLLQtKXY9uL1NCqCcyVHg1omPKr9w= - secure: EAjjkzqZ8z+PEvdo2N2MiIjkqUYAjVkQABKyMw6N4hUa6YSNEW9PYyn4I0d9Rdvc25GwJ+oLQFdeQepioAkNfp6wYUj2IdMIfmmKa1aJWo5DWvOMDYp3ufRhIoiVi4ZVpLg9sTjw+078UhUQFWE44rwfUtHiIb2UbWe2/ueLOiM= + - CXX=g++-4.8 diff --git a/test/unit/globals.html b/test/unit/globals.html index 3978314b..34ae5552 100644 --- a/test/unit/globals.html +++ b/test/unit/globals.html @@ -39,7 +39,7 @@ suite('globals', function() { // Polymer Polymer: true, - currentImport: true + currentImport: true, // weird safari + selenium globals alert: true, From 9a3bead5688610c8f290249b351df59fe6d6f3ca Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 14 Dec 2015 18:40:01 -0800 Subject: [PATCH 223/268] Store all dom tree data in `__dom` private storage; implement composed patching via a linked list. --- src/lib/dom-tree-api.html | 224 +++++++++---------- src/lib/experimental/patch-dom.html | 332 ++++++++++++++++++---------- src/mini/shady.html | 7 +- test/smoke/patch/patch-dom.html | 12 +- test/unit/shady.html | 63 +++--- 5 files changed, 360 insertions(+), 278 deletions(-) diff --git a/src/lib/dom-tree-api.html b/src/lib/dom-tree-api.html index a1889cab..be6df6db 100644 --- a/src/lib/dom-tree-api.html +++ b/src/lib/dom-tree-api.html @@ -55,101 +55,103 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Polymer.TreeApi.Logical = { - hasChildNodes: function(node) { - return Boolean(node.__childNodes !== undefined); - }, - hasParentNode: function(node) { - return Boolean(node.__parentNode); + return Boolean(node.__dom && node.__dom.parentNode); }, + hasChildNodes: function(node) { + return Boolean(node.__dom && node.__dom.childNodes !== undefined); + }, + getChildNodes: function(node) { // note: we're distinguishing here between undefined and false-y: // hasChildNodes uses undefined check to see if this element has logical // children; the false-y check indicates whether or not we should rebuild // the cached childNodes array. - if (this.hasChildNodes(node)) { - if (!node.__childNodes) { - node.__childNodes = []; - for (var n=node.__firstChild; n; n=n.__nextSibling) { - node.__childNodes.push(n); - } - } - return node.__childNodes; - } else { - // TODO(sorvell): it's more correct to `Composed.getChildNodes` - // instead of `childNodes` here but any trivial failure - //to use Polymer.dom will result in an error. - return node.childNodes; + return this.hasChildNodes(node) ? this._getChildNodes(node) : + node.childNodes; + }, + + _getChildNodes: function(node) { + if (!node.__dom.childNodes) { + node.__dom.childNodes = []; + for (var n=node.__dom.firstChild; n; n=n.__dom.nextSibling) { + node.__dom.childNodes.push(n); + } } + return node.__dom.childNodes; }, getParentNode: function(node) { - return node.__parentNode || TreeApi.Composed.getParentNode(node); + return node.__dom && node.__dom.parentNode || node.parentNode; }, getFirstChild: function(node) { - return node.__firstChild || TreeApi.Composed.getFirstChild(node); + return node.__dom && node.__dom.firstChild || node.firstChild; }, getLastChild: function(node) { - return node.__lastChild || TreeApi.Composed.getLastChild(node); + return node.__dom && node.__dom.lastChild || node.lastChild; }, getNextSibling: function(node) { - return node.__nextSibling || TreeApi.Composed.getNextSibling(node); + return node.__dom && node.__dom.nextSibling || node.nextSibling; }, getPreviousSibling: function(node) { - return node.__previousSibling || TreeApi.Composed.getPreviousSibling(node); + return node.__dom && node.__dom.previousSibling || node.previousSibling; }, getFirstElementChild: function(node) { - if (node.__firstChild) { - var n = node.__firstChild; - while (n && n.nodeType !== Node.ELEMENT_NODE) { - n = n.__nextSibling; - } - return n; - } else { - return TreeApi.Composed.getFirstElementChild(node); + return node.__dom && node.__dom.firstChild ? + this._getFirstElementChild(node) : node.firstElementChild; + }, + + _getFirstElementChild: function(node) { + var n = node.__dom.firstChild; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__dom.nextSibling; } + return n; }, getLastElementChild: function(node) { - if (node.__lastChild) { - var n = node.__lastChild; - while (n && n.nodeType !== Node.ELEMENT_NODE) { - n = n.__previousSibling; - } - return n; - } else { - return TreeApi.Composed.getLastElementChild(node); + return node.__dom && node.__dom.lastChild ? + this._getLastElementChild(node) : node.firstElementChild; + }, + + _getLastElementChild: function(node) { + var n = node.__dom.lastChild; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__dom.previousSibling; } + return n; }, getNextElementSibling: function(node) { - if (node.__nextSibling) { - var n = node.__nextSibling; - while (n && n.nodeType !== Node.ELEMENT_NODE) { - n = n.__nextSibling; - } - return n; - } else { - return TreeApi.Composed.getNextElementSibling(node); + return node.__dom && node.__dom.nextSibling ? + this._getNextElementSibling(node) : node.nextElementSibling; + }, + + _getNextElementSibling: function(node) { + var n = node.__dom.nextSibling; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__dom.nextSibling; } + return n; }, getPreviousElementSibling: function(node) { - if (node.__previousSibling) { - var n = node.__previousSibling; - while (n && n.nodeType !== Node.ELEMENT_NODE) { - n = n.__previousSibling; - } - return n; - } else { - return TreeApi.Composed.getPreviousElementSibling(node); + return node.__dom && node.__dom.previousSibling ? + this._getPreviousElementSibling(node) : node.previousElementSibling; + }, + + _getPreviousElementSibling: function(node) { + var n = node.__dom.previousSibling; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__dom.previousSibling; } + return n; }, // Capture the list of light children. It's important to do this before we @@ -160,20 +162,22 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // has been called. saveChildNodes: function(node) { if (!this.hasChildNodes(node)) { - node.__firstChild = node.firstChild; - node.__lastChild = node.lastChild; - node.__childNodes = []; + node.__dom = node.__dom || {}; + node.__dom.firstChild = node.firstChild; + node.__dom.lastChild = node.lastChild; + node.__dom.childNodes = []; for (var n=node.firstChild; n; n=n.nextSibling) { - n.__parentNode = node; - node.__childNodes.push(n); - n.__nextSibling = n.nextSibling; - n.__previousSibling = n.previousSibling; + n.__dom = n.__dom || {}; + n.__dom.parentNode = node; + node.__dom.childNodes.push(n); + n.__dom.nextSibling = n.nextSibling; + n.__dom.previousSibling = n.previousSibling; } } }, recordInsertBefore: function(node, container, ref_node) { - container.__childNodes = null; + container.__dom.childNodes = null; // handle document fragments if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { // TODO(sorvell): remember this for patching: @@ -188,52 +192,60 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _linkNode: function(node, container, ref_node) { + node.__dom = node.__dom || {}; + container.__dom = container.__dom || {}; + if (ref_node) { + ref_node.__dom = ref_node.__dom || {}; + } // update ref_node.previousSibling <-> node - node.__previousSibling = ref_node ? ref_node.__previousSibling : - container.__lastChild; - if (node.__previousSibling) { - node.__previousSibling.__nextSibling = node; + node.__dom.previousSibling = ref_node ? ref_node.__dom.previousSibling : + container.__dom.lastChild; + if (node.__dom.previousSibling) { + node.__dom.previousSibling.__dom.nextSibling = node; } // update node <-> ref_node - node.__nextSibling = ref_node; - if (node.__nextSibling) { - node.__nextSibling.__previousSibling = node; + node.__dom.nextSibling = ref_node; + if (node.__dom.nextSibling) { + node.__dom.nextSibling.__dom.previousSibling = node; } // update node <-> container - node.__parentNode = container; + node.__dom.parentNode = container; if (ref_node) { - if (ref_node === container.__firstChild) { - container.__firstChild = node; + if (ref_node === container.__dom.firstChild) { + container.__dom.firstChild = node; } } else { - container.__lastChild = node; - if (!container.__firstChild) { - container.__firstChild = node; + container.__dom.lastChild = node; + if (!container.__dom.firstChild) { + container.__dom.firstChild = node; } } // remove caching of childNodes - container.__childNodes = null; + container.__dom.childNodes = null; }, recordRemoveChild: function(node, container) { - if (node === container.__firstChild) { - container.__firstChild = node.__nextSibling; + node.__dom = node.__dom || {}; + container.__dom = container.__dom || {}; + if (node === container.__dom.firstChild) { + container.__dom.firstChild = node.__dom.nextSibling; } - if (node === container.__lastChild) { - container.__lastChild = node.__previousSibling; + if (node === container.__dom.lastChild) { + container.__dom.lastChild = node.__dom.previousSibling; } - var p = node.__previousSibling; - var n = node.__nextSibling; + var p = node.__dom.previousSibling; + var n = node.__dom.nextSibling; if (p) { - p.__nextSibling = n; + p.__dom.nextSibling = n; } if (n) { - n.__previousSibling = p; + n.__dom.previousSibling = p; } - node.__parentNode = node.__previousSibling = node.__nextSibling = null; + node.__dom.parentNode = node.__dom.previousSibling = + node.__dom.nextSibling = null; // remove caching of childNodes - container.__childNodes = null; - }, + container.__dom.childNodes = null; + } } @@ -242,10 +254,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // to the tree for optional patching pluggability. Polymer.TreeApi.Composed = { - - ensureParentNodes: function(parent, children) { - }, - getChildNodes: function(node) { return Polymer.TreeApi.arrayCopyChildNodes(node); }, @@ -254,38 +262,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return node.parentNode; }, - getFirstChild: function(node) { - return node.firstChild; - }, - - getLastChild: function(node) { - return node.lastChild; - }, - - getNextSibling: function(node) { - return node.nextSibling; - }, - - getPreviousSibling: function(node) { - return node.previousSibling; - }, - - getFirstElementChild: function(node) { - return node.firstElementChild; - }, - - getLastElementChild: function(node) { - return node.lastElementChild; - }, - - getNextElementSibling: function(node) { - return node.nextElementSibling; - }, - - getPreviousElementSibling: function(node) { - return node.previousElementSibling; - }, - // composed tracking needs to reset composed children here in case // they may have already been set (this shouldn't happen but can // if dependency ordering is incorrect and as a result upgrade order diff --git a/src/lib/experimental/patch-dom.html b/src/lib/experimental/patch-dom.html index 571983e6..b8d424ef 100644 --- a/src/lib/experimental/patch-dom.html +++ b/src/lib/experimental/patch-dom.html @@ -245,24 +245,27 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // NOTE: patch logical implementations here so we can use // composed getters - Polymer.TreeApi.Logical.saveChildNodes = function(node) { + TreeApi.Logical.saveChildNodes = function(node) { if (!this.hasChildNodes(node)) { - node.__firstChild = node.firstChild; - node.__lastChild = node.lastChild; - node.__childNodes = []; + if (!node.__dom) { + node.__dom = {}; + } + node.__dom.firstChild = node.firstChild; + node.__dom.lastChild = node.lastChild; + node.__dom.childNodes = []; for (var n=TreeApi.Composed.getFirstChild(node); n; n=TreeApi.Composed.getNextSibling(n)) { - n.__parentNode = node; - node.__childNodes.push(n); - n.__nextSibling = TreeApi.Composed.getNextSibling(n); - n.__previousSibling = TreeApi.Composed.getPreviousSibling(n); + n.__dom = n.__dom || {}; + n.__dom.parentNode = node; + node.__dom.childNodes.push(n); + n.__dom.nextSibling = TreeApi.Composed.getNextSibling(n); + n.__dom.previousSibling = TreeApi.Composed.getPreviousSibling(n); } } } - Polymer.TreeApi.Logical.recordInsertBefore = - function(node, container, ref_node) { - container.__childNodes = null; + TreeApi.Logical.recordInsertBefore = function(node, container, ref_node) { + container.__dom.childNodes = null; // handle document fragments if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { // TODO(sorvell): remember this for patching: @@ -277,160 +280,265 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } } - Polymer.TreeApi.Composed = { + TreeApi.Logical.getChildNodes = function(node) { + if (this.hasChildNodes(node)) { + return this._getChildNodes(node); + } else { + // TODO(sorvell): it's more correct to `Composed.getChildNodes` + // instead of `childNodes` here but any trivial failure + //to use Polymer.dom will result in an error. + return node.childNodes; + } + }; + + + TreeApi.Logical.getParentNode = function(node) { + return node.__dom && node.__dom.parentNode || + TreeApi.Composed.getParentNode(node); + }; + + TreeApi.Logical.getFirstChild = function(node) { + return node.__dom && node.__dom.firstChild || + TreeApi.Composed.getFirstChild(node); + }; + + TreeApi.Logical.getLastChild = function(node) { + return node.__dom && node.__dom.lastChild || + TreeApi.Composed.getLastChild(node); + }; + + TreeApi.Logical.getNextSibling = function(node) { + return node.__dom && node.__dom.nextSibling || + TreeApi.Composed.getNextSibling(node); + }; + + TreeApi.Logical.getPreviousSibling = function(node) { + return node.__dom && node.__dom.previousSibling || + TreeApi.Composed.getPreviousSibling(node); + }; + + TreeApi.Logical.getFirstElementChild = function(node) { + return node.__dom && node.__dom.firstChild ? + this._getFirstElementChild(node) : + TreeApi.Composed.getFirstElementChild(node); + }; + + TreeApi.Logical.getLastElementChild = function(node) { + return node.__dom && node.__dom.lastChild ? + this._getLastElementChild(node) : + TreeApi.Composed.getLastElementChild(node); + }; + + TreeApi.Logical.getNextElementSibling = function(node) { + return node.__dom && node.__dom.nextSibling ? + this._getNextElementSibling(node) : + TreeApi.Composed.getNextElementSibling(node); + }; + + TreeApi.Logical.getPreviousElementSibling = function(node) { + return node.__dom && node.__dom.previousSibling ? + this._getPreviousElementSibling(node) : + TreeApi.Composed.getPreviousElementSibling(node); + }; + + + TreeApi.Composed = { hasParentNode: function(node) { - return Boolean(node.__composedParent !== undefined); + return Boolean(node.__dom && node.__dom.$parentNode !== undefined); }, hasChildNodes: function(node) { - return Boolean(node.__composedChildNodes !== undefined); + return Boolean(node.__dom && node.__dom.$childNodes !== undefined); }, getChildNodes: function(node) { - return node.__composedChildNodes || + return node.__dom.$childNodes || (!node.__patched && TreeApi.arrayCopy(node.childNodes)); }, getComposedChildNodes: function(node) { - return node.__composedChildNodes; + return node.__dom.$childNodes; }, getParentNode: function(node) { - return this.hasParentNode(node) ? node.__composedParent : + return this.hasParentNode(node) ? node.__dom.$parentNode : (!node.__patched && node.parentNode); }, getFirstChild: function(node) { - if (node.__patched) { - return this.getChildNodes(node)[0]; - } else { - return node.firstChild; - } + return node.__patched ? node.__dom.$firstChild : node.firstChild; }, getLastChild: function(node) { - if (node.__patched) { - var c$ = this.getChildNodes(node); - return c$[c$.length-1]; - } else { - return node.lastChild; - } + return node.__patched ? node.__dom.$lastChild : node.lastChild; }, getNextSibling: function(node) { - // TODO(sorvell): linked list - var parent = this.getParentNode(node); - if (parent.__patched) { - var c$ = this.getChildNodes(parent); - var i = c$.indexOf(node); - return c$[i+1]; - } else if (!node.__patched) { - return node.nextSibling; - } + return node.__patched ? node.__dom.$nextSibling : node.nextSibling; }, getPreviousSibling: function(node) { - // TODO(sorvell): linked list - var parent = this.getParentNode(node); - if (parent.__patched) { - var c$ = this.getChildNodes(parent); - var i = c$.indexOf(node); - return c$[i-1]; - } else if (!node.__patched) { - return node.previousSibling; - } + return node.__patched ? node.__dom.$previousSibling : node.previousSibling; }, getFirstElementChild: function(node) { - if (node.__patched) { - var c$ = this.getChildNodes(node); - for (var i=0, n; i < c$.length; i++) { - n = c$[i]; - if (n.nodeType === Node.ELEMENT_NODE) { - return n; - } - } - } else { - return node.firstElementChild; + return node.__patched ? this._getFirstElementChild(node) : + node.firstElementChild; + }, + + _getFirstElementChild: function(node) { + var n = node.__dom.$firstChild; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__dom.$nextSibling; } + return n; }, getLastElementChild: function(node) { - if (node.__patched) { - var c$ = this.getChildNodes(node); - for (var i=c$.length, n; i >=0 ; i--) { - n = c$[i]; - if (n.nodeType === Node.ELEMENT_NODE) { - return n; - } - } - } else { - return node.lastElementChild; + return node.__patched ? this._getLastElementChild(node) : + node.firstElementChild; + }, + + _getLastElementChild: function(node) { + var n = node.__dom.$lastChild; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__dom.$previousSibling; } + return n; }, getNextElementSibling: function(node) { - if (node.__patched) { - var c$ = this.getChildNodes(node); - var i = c$.indexOf(node); - if (i >= 0) { - for (var n; i < c$.length; i++) { - n = c$[i]; - if (n.nodeType === Node.ELEMENT_NODE) { - return n; - } - } - } - } else { - return node.nextElementSibling; + return node.__patched ? this._getNextElementSibling(node) : + node.nextElementSibling; + }, + + _getNextElementSibling: function(node) { + var n = node.__dom.$nextSibling; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__dom.$nextSibling; } + return n; }, getPreviousElementSibling: function(node) { - if (node.__patched) { - var c$ = this.getChildNodes(node); - var i = c$.indexOf(node); - if (i >= 0) { - for (var n; i >=0 ; i--) { - n = c$[i]; - if (n.nodeType === Node.ELEMENT_NODE) { - return n; - } - } + return node.__patched ? this._getPreviousElementSibling(node) : + node.previousElementSibling; + }, + + _getPreviousElementSibling: function(node) { + var n = node.__dom.$previousSibling; + while (n && n.nodeType !== Node.ELEMENT_NODE) { + n = n.__dom.$previousSibling; + } + return n; + }, + + saveChildNodes: function(node) { + if (!this.hasChildNodes(node)) { + node.__dom = node.__dom || {}; + node.__dom.$firstChild = node.firstChild; + node.__dom.$lastChild = node.lastChild; + node.__dom.$childNodes = []; + for (var n=node.firstChild; n; n=n.nextSibling) { + n.__dom = n.__dom || {}; + n.__dom.$parentNode = node; + node.__dom.$childNodes.push(n); + n.__dom.$nextSibling = n.nextSibling; + n.__dom.$previousSibling = n.previousSibling; + } + } + }, + + recordInsertBefore: function(node, container, ref_node) { + container.__dom.$childNodes = null; + // handle document fragments + if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { + // TODO(sorvell): remember this for patching: + // the act of setting this info can affect patched nodes + // getters; therefore capture childNodes before patching. + for (var n=this.getFirstChild(node); n; n=this.getNextSibling(n)) { + this._linkNode(n, container, ref_node); } } else { - return node.previousElementSibling; + this._linkNode(node, container, ref_node); } }, + _linkNode: function(node, container, ref_node) { + node.__dom = node.__dom || {}; + container.__dom = container.__dom || {}; + if (ref_node) { + ref_node.__dom = ref_node.__dom || {}; + } + // update ref_node.previousSibling <-> node + node.__dom.$previousSibling = ref_node ? ref_node.__dom.$previousSibling : + container.__dom.$lastChild; + if (node.__dom.$previousSibling) { + node.__dom.$previousSibling.__dom.$nextSibling = node; + } + // update node <-> ref_node + node.__dom.$nextSibling = ref_node; + if (node.__dom.$nextSibling) { + node.__dom.$nextSibling.__dom.$previousSibling = node; + } + // update node <-> container + node.__dom.$parentNode = container; + if (ref_node) { + if (ref_node === container.__dom.$firstChild) { + container.__dom.$firstChild = node; + } + } else { + container.__dom.$lastChild = node; + if (!container.__dom.$firstChild) { + container.__dom.$firstChild = node; + } + } + // remove caching of childNodes + container.__dom.$childNodes = null; + }, + + recordRemoveChild: function(node, container) { + node.__dom = node.__dom || {}; + container.__dom = container.__dom || {}; + if (node === container.__dom.$firstChild) { + container.__dom.$firstChild = node.__dom.$nextSibling; + } + if (node === container.__dom.$lastChild) { + container.__dom.$lastChild = node.__dom.$previousSibling; + } + var p = node.__dom.$previousSibling; + var n = node.__dom.$nextSibling; + if (p) { + p.__dom.$nextSibling = n; + } + if (n) { + n.__dom.$previousSibling = p; + } + node.__dom.$parentNode = node.__dom.$previousSibling = + node.__dom.$nextSibling = null; + // remove caching of childNodes + container.__dom.$childNodes = null; + }, + // composed tracking needs to reset composed children here in case // they may have already been set (this shouldn't happen but can // if dependency ordering is incorrect and as a result upgrade order // is unexpected) clearChildNodes: function(node) { - if (node.__composedParent) { - node.__composedParent.__composedChildNodes = []; + if (node.__dom && node.__dom.$parentNode) { + node.__dom.$parentNode.__dom.$childNodes = []; } node.textContent = ''; }, - saveChildNodes: function(node) { - var c$ = node.__composedChildNodes = []; - for (var n=node.firstChild; n; n=n.nextSibling) { - n.__composedParent = node; - c$.push(n); - } - }, - saveParentNode: function(node) { - node.__composedParent = node.parentNode; + node.__dom = node.__dom || {}; + node.__dom.$parentNode = node.parentNode; }, insertBefore: function(parentNode, newChild, refChild) { - if (!this.hasChildNodes(parentNode)) { - this.saveChildNodes(parentNode); - } + this.saveChildNodes(parentNode); // remove from current location. if (this.hasParentNode(newChild)) { var oldParent = this.getParentNode(newChild); @@ -443,9 +551,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, appendChild: function(parentNode, newChild) { - if (!this.hasChildNodes(parentNode)) { - this.saveChildNodes(parentNode); - } + this.saveChildNodes(parentNode); // remove from current location. if (this.hasParentNode(newChild)) { var oldParent = this.getParentNode(newChild); @@ -459,13 +565,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN removeChild: function(parentNode, node) { var currentParent = this.getParentNode(node); - if (!this.hasChildNodes(parentNode)) { - this.saveChildNodes(parentNode); - } + this.saveChildNodes(parentNode); this._removeChild(parentNode, node); if (currentParent === parentNode) { // TODO(sorvell); abort if the composedParent is not expected... - if (!node.__patched && node.parentNode !== node.__composedParent) { + if (!node.__patched && node.parentNode !== node.__dom.$parentNode) { return; } return nativeRemoveChild.call(parentNode, node); @@ -479,7 +583,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this._addChild(parentNode, c$[j], refChild); } } else { - newChild.__composedParent = parentNode; + newChild.__dom = newChild.__dom || {}; + newChild.__dom.$parentNode = parentNode; var c$ = this.getComposedChildNodes(parentNode); if (c$) { var i = c$.indexOf(refChild); @@ -490,7 +595,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _removeChild: function(parentNode, node) { - node.__composedParent = null; + node.__dom = node.__dom || {}; + node.__dom.$parentNode = null; var c$ = this.getComposedChildNodes(parentNode); if (c$) { var i = c$.indexOf(node); diff --git a/src/mini/shady.html b/src/mini/shady.html index 314a6fb8..641566da 100644 --- a/src/mini/shady.html +++ b/src/mini/shady.html @@ -40,6 +40,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (!this.__domApi) { this.__domApi = null; } + if (!this.__dom) { + this.__dom = null; + } if (!this._ownerShadyRoot) { this._ownerShadyRoot = undefined; } @@ -417,7 +420,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // dirty a shadyRoot if a change may trigger reprojection! function maybeRedistributeParent(content, host) { - var parent = content.__parentNode; + // only get logical parent. + var parent = TreeApi.Logical.hasParentNode(content) && + TreeApi.Logical.getParentNode(content); if (parent && parent.shadyRoot && DomApi.hasInsertionPoint(parent.shadyRoot) && parent.shadyRoot._distributionClean) { diff --git a/test/smoke/patch/patch-dom.html b/test/smoke/patch/patch-dom.html index 1db4259f..92e3a2fe 100644 --- a/test/smoke/patch/patch-dom.html +++ b/test/smoke/patch/patch-dom.html @@ -251,19 +251,19 @@ suite('Polymer.dom (patch)', function() { assert.equal(s.parentNode, rere); Polymer.dom.flush(); if (rere.shadyRoot) { - assert.notEqual(s.__composedParent, rere); + assert.notEqual(s.__dom.$parentNode, rere); } Polymer.dom.flush(); if (rere.shadyRoot) { - assert.equal(s.__composedParent, p); + assert.equal(s.__dom.$parentNode, p); } rere.removeChild(s); if (rere.shadyRoot) { - assert.equal(s.__composedParent, p); + assert.equal(s.__dom.$parentNode, p); } Polymer.dom.flush(); if (rere.shadyRoot) { - assert.equal(s.__composedParent, null); + assert.equal(s.__dom.$parentNode, null); } }); @@ -343,13 +343,13 @@ suite('Polymer.dom non-distributed elements', function() { function testNoAttr() { assert.equal(Polymer.dom(child).getDestinationInsertionPoints()[0], d.$.notTestContent, 'child not distributed logically'); if (shady) { - assert.equal(child.__composedParent, d.$.notTestContainer, 'child not rendered in composed dom'); + assert.equal(child.__dom.$parentNode, d.$.notTestContainer, 'child not rendered in composed dom'); } } function testWithAttr() { assert.equal(Polymer.dom(child).getDestinationInsertionPoints()[0], d.$.testContent, 'child not distributed logically'); if (shady) { - assert.equal(child.__composedParent, d.$.testContainer, 'child not rendered in composed dom'); + assert.equal(child.__dom.$parentNode, d.$.testContainer, 'child not rendered in composed dom'); } } // test with x-distribute diff --git a/test/unit/shady.html b/test/unit/shady.html index a7ed04a7..b1abbfcd 100644 --- a/test/unit/shady.html +++ b/test/unit/shady.html @@ -135,14 +135,14 @@ test('Reproject', function() { assert.strictEqual(getComposedHTML(host), 'a: b: '); - assertArrayEqual(host.__childNodes, [a]); - assert.strictEqual(a.__parentNode, host); - assertArrayEqual(host.shadyRoot.__childNodes, [p]); - assert.strictEqual(p.__parentNode, host.shadyRoot); - assertArrayEqual(p.__childNodes, [b, content]); - assert.strictEqual(b.__parentNode, p); - assert.strictEqual(content.__parentNode, p); - assertArrayEqual(p.shadyRoot.__childNodes, + assertArrayEqual(host.__dom.childNodes, [a]); + assert.strictEqual(a.__dom.parentNode, host); + assertArrayEqual(host.shadyRoot.__dom.childNodes, [p]); + assert.strictEqual(p.__dom.parentNode, host.shadyRoot); + assertArrayEqual(p.__dom.childNodes, [b, content]); + assert.strictEqual(b.__dom.parentNode, p); + assert.strictEqual(content.__dom.parentNode, p); + assertArrayEqual(p.shadyRoot.__dom.childNodes, [textNodeA, contentA, textNodeB, contentB]); } @@ -165,7 +165,7 @@ suite('Mutate light DOM', function() { distributeContentNow(host); assert.strictEqual(getComposedHTML(host), ''); - host.__childNodes = []; + host.__dom.childNodes = []; distributeContentNow(host); assert.strictEqual(getComposedHTML(host), 'fallback'); }); @@ -180,11 +180,11 @@ suite('Mutate light DOM', function() { distributeContentNow(host); assert.strictEqual(getComposedHTML(host), 'Helloafter'); - host.shadyRoot.__childNodes[1].textContent = ''; + host.shadyRoot.__dom.childNodes[1].textContent = ''; distributeContentNow(host); assert.strictEqual(getComposedHTML(host), 'Hello'); - host.shadyRoot.__childNodes = []; + host.shadyRoot.__dom.childNodes = []; distributeContentNow(host); assert.strictEqual(getComposedHTML(host), ''); }); @@ -203,11 +203,11 @@ suite('Mutate light DOM', function() { distributeContentNow(host); assert.strictEqual(getComposedHTML(host), ''); - host.shadyRoot.firstChild.__childNodes = []; + host.shadyRoot.firstChild.__dom.childNodes = []; distributeContentNow(host); assert.strictEqual(getComposedHTML(host), ''); - host.shadyRoot.__childNodes = []; + host.shadyRoot.__dom.childNodes = []; distributeContentNow(host); assert.strictEqual(getComposedHTML(host), ''); }); @@ -225,7 +225,7 @@ suite('Mutate light DOM', function() { distributeContentNow(host); assert.strictEqual(getComposedHTML(host), ''); - host.__childNodes = []; + host.__dom.childNodes = []; distributeContentNow(host); assert.strictEqual(getComposedHTML(host), 'fallback'); }); @@ -265,11 +265,11 @@ suite('Mutate light DOM', function() { distributeContentNow(host); assert.strictEqual(getComposedHTML(host), 'Hello'); - host.shadyRoot.__childNodes.splice(1, 1); // remove b + host.shadyRoot.__dom.childNodes.splice(1, 1); // remove b distributeContentNow(host); assert.strictEqual(getComposedHTML(host), 'Hello'); - host.shadyRoot.__childNodes = []; // remove a + host.shadyRoot.__dom.childNodes = []; // remove a distributeContentNow(host); assert.strictEqual(getComposedHTML(host), ''); }); @@ -368,7 +368,7 @@ suite('Mutate light DOM', function() { assert.strictEqual(getComposedHTML(host), 'Hello'); var b = document.createElement('b'); - host.__childNodes[0] = b; + host.__dom.childNodes[0] = b; distributeContentNow(host); assert.strictEqual(getComposedHTML(host), ''); }); @@ -437,16 +437,17 @@ suite('Mutate light DOM', function() { }); function syncLightDOM(n) { - if (n.__childNodes) { - var c$ = n.__patched ? n._composedChildren || [] : Array.prototype.slice.call(n.childNodes); - n.__firstChild = c$[0]; - n.__lastChild = c$[c$.length-1]; + if (n.__dom.childNodes !== undefined) { + var c$ = Array.prototype.slice.call(n.childNodes); + n.__dom.firstChild = c$[0]; + n.__dom.lastChild = c$[c$.length-1]; c$.forEach(function(c, i) { - if (n.__childNodes.indexOf(c) < 0) { - c.__parentNode = n; - c.__previousSibling = c$[i-1]; - c.__nextSibling = c$[i+1]; - n.__childNodes.push(c); + if (n.__dom.childNodes.indexOf(c) < 0) { + c.__dom = c.__dom || {}; + c.__dom.parentNode = n; + c.__dom.previousSibling = c$[i-1]; + c.__dom.nextSibling = c$[i+1]; + n.__dom.childNodes.push(c); } }); } @@ -456,17 +457,11 @@ var nativeAppendChild = Element.prototype.appendChild; function setInnerHTML(node, value) { node.textContent = ''; - if (node._composedChildren) { - node._composedChildren = []; - } var temp = node.ownerDocument.createElement('div'); temp.innerHTML = value; var firstChild; while (firstChild = temp.firstChild) { nativeAppendChild.call(node, firstChild); - if (node._composedChildren) { - node._composedChildren.push(firstChild); - } } } @@ -481,11 +476,11 @@ function updateRootInsertionPoints(root) { } function getComposedHTML(node) { - return node.__patched ? Polymer.domInnerHTML.getInnerHTML(node, true) : node.innerHTML; + return node.innerHTML; } function getComposedChildAtIndex(node, index) { - var c$ = node._composedChildren || node.childNodes; + var c$ = node.childNodes; if (c$) { index = index || 0; index = Math.max(0, Math.min(index, c$.length-1)); From 3f8b6ee2566208a98bc8750c82423e0388477abd Mon Sep 17 00:00:00 2001 From: valdrinkoshi Date: Mon, 14 Dec 2015 17:23:49 -0800 Subject: [PATCH 224/268] use destination insertion points when calculating the path --- src/lib/dom-api-event.html | 32 ++++++++++++++++++++------------ test/unit/polymer-dom.js | 19 +++++++++++++++++++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/lib/dom-api-event.html b/src/lib/dom-api-event.html index d1348080..a85aeced 100644 --- a/src/lib/dom-api-event.html +++ b/src/lib/dom-api-event.html @@ -15,13 +15,13 @@ Polymer.EventApi = (function() { var DomApi = Polymer.DomApi.ctor; var Settings = Polymer.Settings; - + /** - * DomApi.Event allows maniuplation of events compatible with - * the scoping concepts in Shadow DOM and compatible with both Shady DOM - * and Shadow DOM. The general usage is - * `Polymer.dom(event).property`. The `path` property returns `event.path` - * matching Shadow DOM. The `rootTarget` property returns the first node + * DomApi.Event allows maniuplation of events compatible with + * the scoping concepts in Shadow DOM and compatible with both Shady DOM + * and Shadow DOM. The general usage is + * `Polymer.dom(event).property`. The `path` property returns `event.path` + * matching Shadow DOM. The `rootTarget` property returns the first node * in the `path` and is the original event target. The `localTarget` property * matches event.target under Shadow DOM and is the scoped event target. */ @@ -32,7 +32,7 @@ Polymer.EventApi = (function() { if (Settings.useShadow) { DomApi.Event.prototype = { - + get rootTarget() { return this.event.path[0]; }, @@ -50,7 +50,7 @@ Polymer.EventApi = (function() { } else { DomApi.Event.prototype = { - + get rootTarget() { return this.event.target; }, @@ -71,10 +71,18 @@ Polymer.EventApi = (function() { get path() { if (!this.event._path) { var path = []; - var o = this.rootTarget; - while (o) { - path.push(o); - o = Polymer.dom(o).parentNode || o.host; + var current = this.rootTarget; + while (current) { + path.push(current); + var insertionPoints = Polymer.dom(current).getDestinationInsertionPoints(); + if (insertionPoints.length) { + for (var i = 0; i < insertionPoints.length - 1; i++) { + path.push(insertionPoints[i]); + } + current = insertionPoints[insertionPoints.length - 1]; + } else { + current = Polymer.dom(current).parentNode || current.host; + } } // event path includes window in most recent native implementations path.push(window); diff --git a/test/unit/polymer-dom.js b/test/unit/polymer-dom.js index bf5bd441..1e021cbb 100644 --- a/test/unit/polymer-dom.js +++ b/test/unit/polymer-dom.js @@ -663,6 +663,25 @@ suite('Polymer.dom', function() { assert.sameMembers(order, [cb1, cbReentrant, cb2, cb3, cb4]); }); + test('path correctly calculated for elements with destination insertion points', function(done) { + var re = document.createElement('x-reproject'); + var p = Polymer.dom(re.root).querySelector('x-project'); + var child = document.createElement('p'); + child.innerHTML = "hello"; + // child will be inserted into p after distributeContent is performed. + Polymer.dom(re).appendChild(child); + Polymer.dom(document.body).appendChild(re); + Polymer.dom.flush(); + child.addEventListener('child-event', function(e){ + var path = Polymer.dom(e).path; + 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); + }); + }); suite('Polymer.dom accessors', function() { From 8c950143dc5a07c6843827aee84211eb2899b658 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Tue, 15 Dec 2015 15:37:32 -0800 Subject: [PATCH 225/268] Minor factoring of dom patching. --- src/lib/experimental/patch-dom.html | 52 +++++++++-------------------- src/mini/shady.html | 8 +---- 2 files changed, 17 insertions(+), 43 deletions(-) diff --git a/src/lib/experimental/patch-dom.html b/src/lib/experimental/patch-dom.html index b8d424ef..d326d393 100644 --- a/src/lib/experimental/patch-dom.html +++ b/src/lib/experimental/patch-dom.html @@ -27,8 +27,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return; } - count = 0; - var baseFinishDistribute = Polymer.Base._finishDistribute; var TreeApi = Polymer.TreeApi; var DomApi = Polymer.DomApi; @@ -118,8 +116,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN var log = false; - var count = 0; - var patchImpl = { hasPrototypeDescriptors: Boolean(Object.getOwnPropertyDescriptor( @@ -245,25 +241,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // NOTE: patch logical implementations here so we can use // composed getters - TreeApi.Logical.saveChildNodes = function(node) { - if (!this.hasChildNodes(node)) { - if (!node.__dom) { - node.__dom = {}; - } - node.__dom.firstChild = node.firstChild; - node.__dom.lastChild = node.lastChild; - node.__dom.childNodes = []; - for (var n=TreeApi.Composed.getFirstChild(node); n; - n=TreeApi.Composed.getNextSibling(n)) { - n.__dom = n.__dom || {}; - n.__dom.parentNode = node; - node.__dom.childNodes.push(n); - n.__dom.nextSibling = TreeApi.Composed.getNextSibling(n); - n.__dom.previousSibling = TreeApi.Composed.getPreviousSibling(n); - } - } - } - + // TODO(sorvell): may need to patch saveChildNodes iff the tree has + // already been distributed. TreeApi.Logical.recordInsertBefore = function(node, container, ref_node) { container.__dom.childNodes = null; // handle document fragments @@ -280,18 +259,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } } - TreeApi.Logical.getChildNodes = function(node) { - if (this.hasChildNodes(node)) { - return this._getChildNodes(node); - } else { - // TODO(sorvell): it's more correct to `Composed.getChildNodes` - // instead of `childNodes` here but any trivial failure - //to use Polymer.dom will result in an error. - return node.childNodes; - } - }; - - TreeApi.Logical.getParentNode = function(node) { return node.__dom && node.__dom.parentNode || TreeApi.Composed.getParentNode(node); @@ -342,6 +309,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }; + // TODO(sorvell): This is largely copy/pasted from the Logical tree + // implementation. The code could be factored such that it could be shared + // but there are perf trade offs to consider. TreeApi.Composed = { hasParentNode: function(node) { @@ -353,10 +323,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, getChildNodes: function(node) { - return node.__dom.$childNodes || + return this.hasChildNodes(node) ? this._getChildNodes(node) : (!node.__patched && TreeApi.arrayCopy(node.childNodes)); }, + _getChildNodes: function(node) { + if (!node.__dom.$childNodes) { + node.__dom.$childNodes = []; + for (var n=node.__dom.$firstChild; n; n=n.__dom.$nextSibling) { + node.__dom.$childNodes.push(n); + } + } + return node.__dom.$childNodes; + }, + getComposedChildNodes: function(node) { return node.__dom.$childNodes; }, diff --git a/src/mini/shady.html b/src/mini/shady.html index 641566da..c06bc2fd 100644 --- a/src/mini/shady.html +++ b/src/mini/shady.html @@ -46,11 +46,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (!this._ownerShadyRoot) { this._ownerShadyRoot = undefined; } - // TODO(sorvell): these could be on the domApi object? - // there are a bunch of `__` properties that get put on the node - // from logicalizing. These could be on `__domApi`. Initializing - // them here is problematic because they may have been set prior - // to upgrading. }, // called as part of content initialization, prior to template stamping @@ -421,8 +416,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // dirty a shadyRoot if a change may trigger reprojection! function maybeRedistributeParent(content, host) { // only get logical parent. - var parent = TreeApi.Logical.hasParentNode(content) && - TreeApi.Logical.getParentNode(content); + var parent = TreeApi.Logical.getParentNode(content); if (parent && parent.shadyRoot && DomApi.hasInsertionPoint(parent.shadyRoot) && parent.shadyRoot._distributionClean) { From bb4d558ac5d4cfd063caaf8065cdf61805d2165b Mon Sep 17 00:00:00 2001 From: Sanndro Date: Thu, 17 Dec 2015 15:32:32 +0100 Subject: [PATCH 226/268] Update PRIMER.md Without testing my changes, I am pretty sure there is a mistake in the documentation. --- PRIMER.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PRIMER.md b/PRIMER.md index 2508799a..11b77286 100644 --- a/PRIMER.md +++ b/PRIMER.md @@ -167,8 +167,8 @@ MyElement = Polymer({ is: 'my-element', factoryImpl: function(foo, bar) { - el.foo = foo; - el.configureWithBar(bar); + this.foo = foo; + this.configureWithBar(bar); }, configureWithBar: function(bar) { From 0eea7a6038b0862309e78b7b6952b4ccaf6f5e36 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 18 Dec 2015 02:40:34 +0100 Subject: [PATCH 227/268] Fix for `Polymer.dom(...)._query()` method doesn't exist which causes `Polymer.updateStyles()` to fail --- src/lib/dom-api-shadow.html | 28 +++++++++++++++++++++++++--- test/runner.html | 1 + 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/lib/dom-api-shadow.html b/src/lib/dom-api-shadow.html index bcd76df4..6a3cc300 100644 --- a/src/lib/dom-api-shadow.html +++ b/src/lib/dom-api-shadow.html @@ -26,6 +26,28 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN return TreeApi.arrayCopy(this.node.querySelectorAll(selector)); }, + _query: function(matcher, node) { + node = node || this.node; + var list = []; + this._queryElements(node.childNodes, matcher, list); + return list; + }, + + _queryElements: function(elements, matcher, list) { + for (var i=0, l=elements.length, c; (i \ No newline at end of file + diff --git a/test/runner.html b/test/runner.html index 852e54f1..7ae43c2a 100644 --- a/test/runner.html +++ b/test/runner.html @@ -62,6 +62,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // 'unit/styling-cross-scope-apply.html?dom=shadow', 'unit/styling-cross-scope-unknown-host.html', 'unit/custom-style.html', + 'unit/custom-style.html?dom=shadow', 'unit/custom-style-late.html', 'unit/dynamic-import.html', 'unit/templatizer.html', From f92f9ff38e0435143bb13488b7acbc22f5d37b14 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Thu, 5 Nov 2015 15:43:23 +0100 Subject: [PATCH 228/268] Fix parsing of minimized css output --- src/lib/css-parse.html | 2 +- test/unit/custom-style.html | 14 +++++++++++++- test/unit/styling-cross-scope-var.html | 10 +++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/lib/css-parse.html b/src/lib/css-parse.html index 6414468e..78435c36 100644 --- a/src/lib/css-parse.html +++ b/src/lib/css-parse.html @@ -171,7 +171,7 @@ Polymer.CssParse = (function() { _rx: { comments: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim, port: /@import[^;]*;/gim, - customProp: /(?:^|[\s;])--[^;{]*?:[^{};]*?(?:[;\n]|$)/gim, + customProp: /(?:^[^;\-\s}]+)?--[^;{]*?:[^{};]*?(?:[;\n]|$)/gim, mixinProp: /(?:^|[\s;])?--[^;{]*?:[^{;]*?{[^}]*?}(?:[;\n]|$)?/gim, mixinApply: /@apply[\s]*\([^)]*?\)[\s]*(?:[;\n]|$)?/gim, varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim, diff --git a/test/unit/custom-style.html b/test/unit/custom-style.html index 058bc8e0..33a207b4 100644 --- a/test/unit/custom-style.html +++ b/test/unit/custom-style.html @@ -235,6 +235,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN --variable-property-after-property: 3px; --variable-property-after-assignment: 4px; --variable-property-before-assignment: 5px; + --variable-into-first-variable: 9px; + --variable-into-second-variable: 10px; + --variable-into-third-variable: 11px; } @@ -251,7 +254,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN --variable-between-properties: 6px; background-color: var(--variable-property-before-property); padding-top: var(--variable-property-after-property); --variable-assignment-before-property: 7px; padding-bottom: var(--variable-property-after-assignment); - padding-left: var(--variable-property-before-assignment);--variable-assignment-after-property: 8px + padding-left: var(--variable-property-before-assignment);--variable-assignment-after-property: 8px; + top: 12px;--variable-from-other-variable: var(--variable-into-first-variable);--variable-from-another-variable: var(--variable-into-second-variable); --variable-from-last-variable: var(--variable-into-third-variable); } @@ -266,6 +270,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN padding-right: var(--variable-between-properties); margin-left: var(--variable-assignment-before-property); margin-right: var(--variable-assignment-after-property); + bottom: var(--variable-from-other-variable); + left: var(--variable-from-another-variable); + right: var(--variable-from-last-variable); } Text @@ -468,11 +475,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN assertComputed(el, '7px', 'margin-left'); assertComputed(el, '8px', 'margin-right'); assertComputed(el, 'rgb(255, 255, 0)', 'background-color'); + assertComputed(el, '9px', 'bottom'); + assertComputed(el, '10px', 'left'); + assertComputed(el, '11px', 'right'); + assertComputed(el, '12px', 'top'); // Because FireFox and Chrome parse font-family differently... var computed = getComputedStyle(el); assert.equal(computed['font-family'].replace(/['"]+/g, ''), 'Varela font'); }); + test('BEM-like CSS selectors under media queries', function() { assertComputed(document.querySelector('.foo--bar'), '3px'); }); diff --git a/test/unit/styling-cross-scope-var.html b/test/unit/styling-cross-scope-var.html index cdd52dcd..ba288808 100644 --- a/test/unit/styling-cross-scope-var.html +++ b/test/unit/styling-cross-scope-var.html @@ -94,7 +94,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } #gc4 { - --grand-child-scope-var: + --grand-child-scope-var: var(--gc4-scope); } @@ -286,7 +286,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }); - + @@ -679,7 +679,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // test('var values can be overridden by subsequent concrete properties', function() { // assertComputed(styled.$.overridesConcrete, '4px'); // }); - + }); From 94f505a721c733e859c5fdc8eb026950d263782d Mon Sep 17 00:00:00 2001 From: Ruben Stolk Date: Mon, 28 Dec 2015 19:28:30 +0100 Subject: [PATCH 229/268] Set position to relative to make Safari to succeed top/bottom tests --- test/unit/custom-style.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/unit/custom-style.html b/test/unit/custom-style.html index 33a207b4..fef176d1 100644 --- a/test/unit/custom-style.html +++ b/test/unit/custom-style.html @@ -248,6 +248,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN