From e752636cb78512c4c0c0bc4af480dce095a1ac2a Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 26 Oct 2018 15:13:56 -0700 Subject: [PATCH 01/33] Adds basic legacy support for ShadyDOM.unPatch (WIP) * Polymer.dom uses ShadyDOM.wrap * LegacyElementMixin _attachDOM uses ShadyDOM.wrap --- lib/legacy/legacy-element-mixin.js | 30 ++- lib/legacy/polymer.dom.js | 116 +++++++-- lib/utils/flattened-nodes-observer.js | 41 ++- test/unit/polymer-dom-unpatch.html | 352 ++++++++++++++++++++++++++ 4 files changed, 506 insertions(+), 33 deletions(-) create mode 100644 test/unit/polymer-dom-unpatch.html diff --git a/lib/legacy/legacy-element-mixin.js b/lib/legacy/legacy-element-mixin.js index 151a13fa56..3fe3280256 100644 --- a/lib/legacy/legacy-element-mixin.js +++ b/lib/legacy/legacy-element-mixin.js @@ -23,6 +23,8 @@ import { get } from '../utils/path.js'; let styleInterface = window.ShadyCSS; +let wrap = (n) => n; + /** * Element class mixin that provides Polymer's "legacy" API intended to be * backward-compatible to the greatest extent possible with the API @@ -490,7 +492,7 @@ export const LegacyElementMixin = dedupingMixin((base) => { * @this {Element} */ get domHost() { - let root = this.getRootNode(); + let root = wrap(this).getRootNode(); return (root instanceof DocumentFragment) ? /** @type {ShadowRoot} */ (root).host : root; } @@ -636,8 +638,8 @@ export const LegacyElementMixin = dedupingMixin((base) => { */ isLightDescendant(node) { const thisNode = /** @type {Node} */ (this); - return thisNode !== node && thisNode.contains(node) && - thisNode.getRootNode() === node.getRootNode(); + return thisNode !== node && wrap(thisNode).contains(node) && + wrap(thisNode).getRootNode() === wrap(node).getRootNode(); } /** @@ -647,7 +649,7 @@ export const LegacyElementMixin = dedupingMixin((base) => { * @return {boolean} true if node is in this element's local DOM tree. */ isLocalDescendant(node) { - return this.root === node.getRootNode(); + return this.root === wrap(node).getRootNode(); } /** @@ -825,10 +827,10 @@ export const LegacyElementMixin = dedupingMixin((base) => { bool = !node.hasAttribute(name); } if (bool) { - node.setAttribute(name, ''); + wrap(node).setAttribute(name, ''); return true; } else { - node.removeAttribute(name); + wrap(node).removeAttribute(name); return false; } } @@ -983,6 +985,22 @@ export const LegacyElementMixin = dedupingMixin((base) => { } + if (window.ShadyDOM && window.ShadyDOM.inUse && window.ShadyDOM.noPatch) { + wrap = ShadyDOM.wrap; + + LegacyElement.prototype._attachDom = function(dom) { + const w = this.__wrapper = ShadyDOM.wrap(this); + if (dom) { + if (!w.shadowRoot) { + w.attachShadow({mode: 'open'}); + } + w.shadowRoot.appendChild(dom); + return w.shadowRoot; + } + return null; + }; + } + LegacyElement.prototype.is = ''; return LegacyElement; diff --git a/lib/legacy/polymer.dom.js b/lib/legacy/polymer.dom.js index 392e910d36..dd5d961ee1 100644 --- a/lib/legacy/polymer.dom.js +++ b/lib/legacy/polymer.dom.js @@ -41,7 +41,7 @@ export const matchesSelector = function(node, selector) { * `target` is a `Node`. * */ -export class DomApi { +export let DomApi = class { /** * @param {Node} node Node for which to create a Polymer.dom helper object. @@ -194,7 +194,7 @@ export class DomApi { let node = this.node; return node._activeElement !== undefined ? node._activeElement : node.activeElement; } -} +}; function forwardMethods(proto, methods) { for (let i=0; i < methods.length; i++) { @@ -368,22 +368,103 @@ DomApi.prototype.textContent; /** @type {string} */ DomApi.prototype.innerHTML; -forwardMethods(DomApi.prototype, [ - 'cloneNode', 'appendChild', 'insertBefore', 'removeChild', - 'replaceChild', 'setAttribute', 'removeAttribute', - 'querySelector', 'querySelectorAll' -]); -forwardReadOnlyProperties(DomApi.prototype, [ - 'parentNode', 'firstChild', 'lastChild', - 'nextSibling', 'previousSibling', 'firstElementChild', - 'lastElementChild', 'nextElementSibling', 'previousElementSibling', - 'childNodes', 'children', 'classList' -]); +if (window.ShadyDOM && window.ShadyDOM.inUse && window.ShadyDOM.noPatch) { + class Wrapper extends ShadyDOM.Wrapper { + observeNodes(callback) { + return new FlattenedNodesObserver( + /** @type {!HTMLElement} */(this.node), callback, dom); + } + + unobserveNodes(observerHandle) { + observerHandle.disconnect(); + } + + notifyObserver() {} + + deepContains(node) { + if (this.contains(node)) { + return true; + } + let n = node; + let doc = node.ownerDocument; + // walk from node to `this` or `document` + while (n && n !== doc && n !== this.node) { + // use logical parentnode, or native ShadowRoot host + n = this.parentNode || n.host; + } + return n === this.node; + } + + getOwnerRoot() { + return this.getRootNode(); + } + + getDistributedNodes() { + return (this.node.localName === 'slot') ? + this.assignedNodes({flatten: true}) : + []; + } + + getDestinationInsertionPoints() { + let ip$ = []; + let n = this.assignedSlot; + while (n) { + ip$.push(n); + n = ShadyDOM.wrap(n).assignedSlot; + } + return ip$; + } + + importNode(node, deep) { + let doc = this.node instanceof Document ? this.node : + this.node.ownerDocument; + return ShadyDOM.wrap(doc).importNode(node, deep); + } + + getEffectiveChildNodes() { + return FlattenedNodesObserver.getFlattenedNodes( + /** @type {!HTMLElement} */ (this), dom); + } + + queryDistributedElements(selector) { + let c$ = this.getEffectiveChildNodes(); + let list = []; + for (let i=0, l=c$.length, c; (i} The list of flattened nodes for the given `node`. * @nocollapse See https://github.com/google/closure-compiler/issues/2763 */ - static getFlattenedNodes(node) { + // eslint-disable-next-line + static getFlattenedNodes(node, wrapper = (n) => n) { + const wrapped = wrapper(node); if (isSlot(node)) { node = /** @type {!HTMLSlotElement} */(node); // eslint-disable-line no-self-assign - return node.assignedNodes({flatten: true}); + return wrapped.assignedNodes({flatten: true}); } else { - return Array.from(node.childNodes).map((node) => { + return Array.from(wrapped.childNodes).map((node) => { if (isSlot(node)) { node = /** @type {!HTMLSlotElement} */(node); // eslint-disable-line no-self-assign - return node.assignedNodes({flatten: true}); + return wrapper(node).assignedNodes({flatten: true}); } else { return [node]; } @@ -100,11 +102,13 @@ export class FlattenedNodesObserver { * @param {?function(this: Element, { target: !HTMLElement, addedNodes: !Array, removedNodes: !Array }):void} callback Function called when there are additions * or removals from the target's list of flattened nodes. */ - constructor(target, callback) { + // eslint-disable-next-line + constructor(target, callback, wrapper = n=> n) { /** * @type {MutationObserver} * @private */ + this._wrap = wrapper; this._shadyChildrenObserver = null; /** * @type {MutationObserver} @@ -132,6 +136,10 @@ export class FlattenedNodesObserver { this._schedule(); } + _wrap(node) { + return node; + } + /** * Activates an observer. This method is automatically called when * a `FlattenedNodesObserver` is created. It should only be called to @@ -142,9 +150,9 @@ export class FlattenedNodesObserver { connect() { if (isSlot(this._target)) { this._listenSlots([this._target]); - } else if (this._target.children) { + } else if (this._wrap(this._target).children) { this._listenSlots( - /** @type {!NodeList} */ (this._target.children)); + /** @type {!NodeList} */ (this._wrap(this._target).children)); if (window.ShadyDOM) { this._shadyChildrenObserver = ShadyDOM.observeChildren(this._target, (mutations) => { @@ -172,9 +180,9 @@ export class FlattenedNodesObserver { disconnect() { if (isSlot(this._target)) { this._unlistenSlots([this._target]); - } else if (this._target.children) { + } else if (this._wrap(this._target).children) { this._unlistenSlots( - /** @type {!NodeList} */ (this._target.children)); + /** @type {!NodeList} */ (this._wrap(this._target).children)); if (window.ShadyDOM && this._shadyChildrenObserver) { ShadyDOM.unobserveChildren(this._shadyChildrenObserver); this._shadyChildrenObserver = null; @@ -305,4 +313,15 @@ export class FlattenedNodesObserver { } } -} +}; + +if (window.ShadyDOM && window.ShadyDOM.inUse && window.ShadyDOM.noPatch) { + FlattenedNodesObserver = class extends FlattenedNodesObserver { + + static _wrap(node) { + return Polymer.dom(node); + } + + }; + +} \ No newline at end of file diff --git a/test/unit/polymer-dom-unpatch.html b/test/unit/polymer-dom-unpatch.html new file mode 100644 index 0000000000..d08c1eb527 --- /dev/null +++ b/test/unit/polymer-dom-unpatch.html @@ -0,0 +1,352 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 079ac3bc30e801ab593695faa6ecafab725071fa Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 26 Oct 2018 15:39:06 -0700 Subject: [PATCH 02/33] remove cruft --- lib/utils/flattened-nodes-observer.js | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/utils/flattened-nodes-observer.js b/lib/utils/flattened-nodes-observer.js index 7a48f4f7b6..9ba036414d 100644 --- a/lib/utils/flattened-nodes-observer.js +++ b/lib/utils/flattened-nodes-observer.js @@ -136,10 +136,6 @@ export let FlattenedNodesObserver = class { this._schedule(); } - _wrap(node) { - return node; - } - /** * Activates an observer. This method is automatically called when * a `FlattenedNodesObserver` is created. It should only be called to @@ -313,15 +309,4 @@ export let FlattenedNodesObserver = class { } } -}; - -if (window.ShadyDOM && window.ShadyDOM.inUse && window.ShadyDOM.noPatch) { - FlattenedNodesObserver = class extends FlattenedNodesObserver { - - static _wrap(node) { - return Polymer.dom(node); - } - - }; - -} \ No newline at end of file +}; \ No newline at end of file From b211436f4852645255004fdc74e959ee5e422216 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Wed, 31 Oct 2018 18:16:42 -0700 Subject: [PATCH 03/33] rename test file. --- lib/utils/flattened-nodes-observer.js | 2 +- .../unit/{polymer-dom-unpatch.html => polymer-dom-nopatch.html} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename test/unit/{polymer-dom-unpatch.html => polymer-dom-nopatch.html} (100%) diff --git a/lib/utils/flattened-nodes-observer.js b/lib/utils/flattened-nodes-observer.js index 9ba036414d..a4e1576f05 100644 --- a/lib/utils/flattened-nodes-observer.js +++ b/lib/utils/flattened-nodes-observer.js @@ -80,7 +80,7 @@ export let FlattenedNodesObserver = class { * @nocollapse See https://github.com/google/closure-compiler/issues/2763 */ // eslint-disable-next-line - static getFlattenedNodes(node, wrapper = (n) => n) { + static getFlattenedNodes(node, wrapper = n => n) { const wrapped = wrapper(node); if (isSlot(node)) { node = /** @type {!HTMLSlotElement} */(node); // eslint-disable-line no-self-assign diff --git a/test/unit/polymer-dom-unpatch.html b/test/unit/polymer-dom-nopatch.html similarity index 100% rename from test/unit/polymer-dom-unpatch.html rename to test/unit/polymer-dom-nopatch.html From 1bce4f08772ef02dae737774bc9c1220fdd9d553 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Sun, 18 Nov 2018 20:09:59 -0800 Subject: [PATCH 04/33] Add back event tests. --- lib/legacy/polymer.dom.js | 20 +++++++++- test/unit/polymer-dom-nopatch.html | 60 +++++++++++++++--------------- 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/lib/legacy/polymer.dom.js b/lib/legacy/polymer.dom.js index dd5d961ee1..8462873421 100644 --- a/lib/legacy/polymer.dom.js +++ b/lib/legacy/polymer.dom.js @@ -259,7 +259,7 @@ export class EventApi { * @return {!EventTarget} The node this event was dispatched to */ get rootTarget() { - return this.event.composedPath()[0]; + return this.path[0]; } /** @@ -446,6 +446,24 @@ if (window.ShadyDOM && window.ShadyDOM.inUse && window.ShadyDOM.noPatch) { } DomApi = Wrapper; + + Object.defineProperties(EventApi.prototype, { + + localTarget: { + get() { + return window.ShadyDOM && window.ShadyDOM.noPatch ? this.event.currentTarget : this.event.target; + }, + configurable: true + }, + + path: { + get() { + return ShadyDOM.composedPath(this.event); + }, + configurable: true + } + }); + } else { forwardMethods(DomApi.prototype, [ diff --git a/test/unit/polymer-dom-nopatch.html b/test/unit/polymer-dom-nopatch.html index d08c1eb527..d5c87afb6b 100644 --- a/test/unit/polymer-dom-nopatch.html +++ b/test/unit/polymer-dom-nopatch.html @@ -14,7 +14,7 @@ - + @@ -156,37 +156,39 @@ }); }); -// suite('events', function() { +suite('events', function() { -// test('localTarget, rootTarget, path', function(done) { -// var el = fixture('scoped'); -// el.addEventListener('composed', function(e) { -// assert.equal(dom(e).rootTarget, el.$.scoped); -// assert.equal(dom(e).localTarget, el); -// let nodes = []; -// let p = el.$.scoped; -// while (p) { -// nodes.push(p); -// p = p.parentNode || p.host; -// } -// nodes.push(window); -// assert.deepEqual(Array.from(dom(e).path), nodes); -// done(); -// }); -// el.fireComposed(); -// }); + test('localTarget, rootTarget, path', function(done) { + var el = fixture('scoped'); + el.addEventListener('composed', function(e) { + assert.equal(dom(e).rootTarget, el.$.scoped); + assert.equal(dom(e).localTarget, el); + let nodes = []; + let p = el.$.scoped; + while (p) { + nodes.push(p); + p = dom(p).parentNode || dom(p).host; + } + nodes.push(window); + const path = dom(e).path; + assert.deepEqual(path, nodes); + done(); + }); + ShadyDOM.flush(); + el.fireComposed(); + }); -// }); +}); -// suite('activeElement getter', function() { -// test('Retrieves `_activeElement` (ShadyDOM) or `activeElement`.', function() { -// var focusableInShadow = fixture('focusableInShadow'); -// focusableInShadow.$.focusable.focus(); -// var rootNode = focusableInShadow.getRootNode(); -// assert.equal(dom(rootNode).activeElement, focusableInShadow); -// assert.equal(dom(focusableInShadow.shadowRoot).activeElement, focusableInShadow.$.focusable); -// }); -// }); +suite('activeElement getter', function() { + test('Retrieves `activeElement`', function() { + var focusableInShadow = fixture('focusableInShadow'); + focusableInShadow.$.focusable.focus(); + var rootNode = dom(focusableInShadow).getRootNode(); + assert.equal(dom(rootNode).activeElement, focusableInShadow); + assert.equal(dom(dom(focusableInShadow).shadowRoot).activeElement, focusableInShadow.$.focusable); + }); +}); suite('legacy api', function() { test('getEffectiveChildNodes', function() { From 0f022dfe4e2ca4714be4c59016efdfab2533d694 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Mon, 19 Nov 2018 17:07:54 -0800 Subject: [PATCH 05/33] Manual merge from `perf-opt-disable-upgrade` branch. --- lib/legacy/class.js | 8 +++- lib/mixins/disable-upgrade-mixin.js | 68 ++++++++++++++--------------- lib/mixins/property-effects.js | 5 +++ test/unit/disable-upgrade.html | 3 -- 4 files changed, 45 insertions(+), 39 deletions(-) diff --git a/lib/legacy/class.js b/lib/legacy/class.js index 9206907764..aef7eb1f62 100644 --- a/lib/legacy/class.js +++ b/lib/legacy/class.js @@ -10,6 +10,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN import { LegacyElementMixin } from './legacy-element-mixin.js'; import { legacyOptimizations } from '../utils/settings.js'; +import {DisableUpgradeMixin} from '../mixins/disable-upgrade-mixin.js'; const lifecycleProps = { attached: true, @@ -80,6 +81,8 @@ export function mixinBehaviors(behaviors, klass) { return GenerateClassFromInfo({}, LegacyElementMixin(klass), behaviors); } +const LegacyElementClass = Polymer.LegacyElementMixin(HTMLElement); + // NOTE: // 1.x // Behaviors were mixed in *in reverse order* and de-duped on the fly. @@ -502,9 +505,10 @@ export const Class = function(info, mixin) { if (!info) { console.warn('Polymer.Class requires `info` argument'); } - let klass = mixin ? mixin(LegacyElementMixin(HTMLElement)) : - LegacyElementMixin(HTMLElement); + let klass = mixin ? mixin(LegacyElementClass) : + LegacyElementClass; klass = GenerateClassFromInfo(info, klass, info.behaviors); + klass = DisableUpgradeMixin(klass); // decorate klass with registration info klass.is = klass.prototype.is = info.is; return klass; diff --git a/lib/mixins/disable-upgrade-mixin.js b/lib/mixins/disable-upgrade-mixin.js index b7f46486e2..035c4a7d3f 100644 --- a/lib/mixins/disable-upgrade-mixin.js +++ b/lib/mixins/disable-upgrade-mixin.js @@ -7,22 +7,21 @@ The complete set of contributors may be found at http://polymer.github.io/CONTRI Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */ -import { ElementMixin } from './element-mixin.js'; -import { dedupingMixin } from '../utils/mixin.js'; - -const DISABLED_ATTR = 'disable-upgrade'; +const DISABLE_UPGRADE = 'disable-upgrade'; /** * Element class mixin that allows the element to boot up in a non-enabled * state when the `disable-upgrade` attribute is present. This mixin is * designed to be used with element classes like PolymerElement that perform * initial startup work when they are first connected. When the - * `disable-upgrade` attribute is removed, if the element is connected, it - * boots up and "enables" as it otherwise would; if it is not connected, the - * element boots up when it is next connected. + * `disable-upgrade` attribute is removed, the element + * boots up and "enables" as it otherwise would. + * + * For legacy elements, it also prevents the `created` method from being called + * and event listeners from being added. * - * Using `disable-upgrade` with PolymerElement prevents any data propagation + * Using `disable-upgrade` with Polymer.Element prevents any data propagation * to the element, any element DOM from stamping, or any work done in * connected/disconnctedCallback from occuring, but it does not prevent work * done in the element constructor. @@ -35,33 +34,28 @@ const DISABLED_ATTR = 'disable-upgrade'; * * @mixinFunction * @polymer - * @appliesMixin ElementMixin + * @appliesMixin Polymer.ElementMixin + * @memberof Polymer + * @param {Object} base base class on which to apply mixin + * @return {Object} class with mixin applied */ -export const DisableUpgradeMixin = dedupingMixin((base) => { - - /** - * @constructor - * @extends {base} - * @implements {Polymer_ElementMixin} - * @private - */ - const superClass = ElementMixin(base); +export const DisableUpgradeMixin = (base) => { /** * @polymer * @mixinClass * @implements {Polymer_DisableUpgradeMixin} */ - class DisableUpgradeClass extends superClass { + class DisableUpgradeClass extends base { /** @override */ static get observedAttributes() { - return super.observedAttributes.concat(DISABLED_ATTR); + return super.observedAttributes.concat(DISABLE_UPGRADE); } /** @override */ attributeChangedCallback(name, old, value, namespace) { - if (name == DISABLED_ATTR) { + if (name == DISABLE_UPGRADE) { if (!this.__dataEnabled && value == null && this.isConnected) { super.connectedCallback(); } @@ -70,18 +64,16 @@ export const DisableUpgradeMixin = dedupingMixin((base) => { } } - /* - NOTE: cannot gate on attribute because this is called before - attributes are delivered. Therefore, we stub this out and - call `super._initializeProperties()` manually. - */ - /** @override */ - _initializeProperties() {} + // disable while `disable-upgrade` is on + created() {} + + // disable while `disable-upgrade` is on + _applyListeners() {} // prevent user code in connected from running /** @override */ connectedCallback() { - if (this.__dataEnabled || !this.hasAttribute(DISABLED_ATTR)) { + if (this.__dataEnabled || !this.hasAttribute(DISABLE_UPGRADE)) { super.connectedCallback(); } } @@ -89,11 +81,19 @@ export const DisableUpgradeMixin = dedupingMixin((base) => { // prevent element from turning on properties /** @override */ _enableProperties() { - if (!this.hasAttribute(DISABLED_ATTR)) { - if (!this.__dataEnabled) { - super._initializeProperties(); + if (!this.__dataEnabled) { + if (!this.hasAttribute(DISABLE_UPGRADE)) { + // When enabling, run previously disabled lifecycle. + // NOTE: This alters the timing of disabled lifecycle for all + // elements that support `disable-upgrade` + if (super.created) { + super.created(); + } + if (super._applyListeners) { + super._applyListeners(); + } + super._enableProperties(); } - super._enableProperties(); } } @@ -109,4 +109,4 @@ export const DisableUpgradeMixin = dedupingMixin((base) => { return DisableUpgradeClass; -}); +}; diff --git a/lib/mixins/property-effects.js b/lib/mixins/property-effects.js index ac85472154..dd18e87479 100644 --- a/lib/mixins/property-effects.js +++ b/lib/mixins/property-effects.js @@ -39,6 +39,8 @@ const TYPES = { /** @const {RegExp} */ const capitalAttributeRegex = /[A-Z]/; +const DISABLE_UPGRADE = 'disable-upgrade'; + /** * @typedef {{ * name: (string | undefined), @@ -2550,6 +2552,9 @@ export const PropertyEffects = dedupingMixin(superClass => { } node.setAttribute(name, literal); } + if (kind == 'attribute' && name == DISABLE_UPGRADE) { + node.setAttribute(DISABLE_UPGRADE, ''); + } // 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 `$` diff --git a/test/unit/disable-upgrade.html b/test/unit/disable-upgrade.html index 1c1fc78d7e..7b7cd702f6 100644 --- a/test/unit/disable-upgrade.html +++ b/test/unit/disable-upgrade.html @@ -232,9 +232,6 @@

[[prop]]

}); test('elements call `registered` as expected with `disable-upgrade`', function() { - assert.notOk(el.$.disabledRegEl.hasRegistered); - assert.notOk(el.$.disabledRegBoundEl.hasRegistered); - el.enable(); assert.ok(el.$.disabledRegEl.hasRegistered); assert.ok(el.$.disabledRegBoundEl.hasRegistered); }); From c3bd4d6feeaa2802b32de3b08a8a173839c97632 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 7 Dec 2018 10:29:02 -0800 Subject: [PATCH 06/33] Revert "Manual merge from `perf-opt-disable-upgrade` branch." This reverts commit 0f022dfe4e2ca4714be4c59016efdfab2533d694. --- lib/legacy/class.js | 8 +--- lib/mixins/disable-upgrade-mixin.js | 68 ++++++++++++++--------------- lib/mixins/property-effects.js | 5 --- test/unit/disable-upgrade.html | 3 ++ 4 files changed, 39 insertions(+), 45 deletions(-) diff --git a/lib/legacy/class.js b/lib/legacy/class.js index aef7eb1f62..9206907764 100644 --- a/lib/legacy/class.js +++ b/lib/legacy/class.js @@ -10,7 +10,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN import { LegacyElementMixin } from './legacy-element-mixin.js'; import { legacyOptimizations } from '../utils/settings.js'; -import {DisableUpgradeMixin} from '../mixins/disable-upgrade-mixin.js'; const lifecycleProps = { attached: true, @@ -81,8 +80,6 @@ export function mixinBehaviors(behaviors, klass) { return GenerateClassFromInfo({}, LegacyElementMixin(klass), behaviors); } -const LegacyElementClass = Polymer.LegacyElementMixin(HTMLElement); - // NOTE: // 1.x // Behaviors were mixed in *in reverse order* and de-duped on the fly. @@ -505,10 +502,9 @@ export const Class = function(info, mixin) { if (!info) { console.warn('Polymer.Class requires `info` argument'); } - let klass = mixin ? mixin(LegacyElementClass) : - LegacyElementClass; + let klass = mixin ? mixin(LegacyElementMixin(HTMLElement)) : + LegacyElementMixin(HTMLElement); klass = GenerateClassFromInfo(info, klass, info.behaviors); - klass = DisableUpgradeMixin(klass); // decorate klass with registration info klass.is = klass.prototype.is = info.is; return klass; diff --git a/lib/mixins/disable-upgrade-mixin.js b/lib/mixins/disable-upgrade-mixin.js index 035c4a7d3f..b7f46486e2 100644 --- a/lib/mixins/disable-upgrade-mixin.js +++ b/lib/mixins/disable-upgrade-mixin.js @@ -7,21 +7,22 @@ The complete set of contributors may be found at http://polymer.github.io/CONTRI Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */ +import { ElementMixin } from './element-mixin.js'; -const DISABLE_UPGRADE = 'disable-upgrade'; +import { dedupingMixin } from '../utils/mixin.js'; + +const DISABLED_ATTR = 'disable-upgrade'; /** * Element class mixin that allows the element to boot up in a non-enabled * state when the `disable-upgrade` attribute is present. This mixin is * designed to be used with element classes like PolymerElement that perform * initial startup work when they are first connected. When the - * `disable-upgrade` attribute is removed, the element - * boots up and "enables" as it otherwise would. - * - * For legacy elements, it also prevents the `created` method from being called - * and event listeners from being added. + * `disable-upgrade` attribute is removed, if the element is connected, it + * boots up and "enables" as it otherwise would; if it is not connected, the + * element boots up when it is next connected. * - * Using `disable-upgrade` with Polymer.Element prevents any data propagation + * Using `disable-upgrade` with PolymerElement prevents any data propagation * to the element, any element DOM from stamping, or any work done in * connected/disconnctedCallback from occuring, but it does not prevent work * done in the element constructor. @@ -34,28 +35,33 @@ const DISABLE_UPGRADE = 'disable-upgrade'; * * @mixinFunction * @polymer - * @appliesMixin Polymer.ElementMixin - * @memberof Polymer - * @param {Object} base base class on which to apply mixin - * @return {Object} class with mixin applied + * @appliesMixin ElementMixin */ -export const DisableUpgradeMixin = (base) => { +export const DisableUpgradeMixin = dedupingMixin((base) => { + + /** + * @constructor + * @extends {base} + * @implements {Polymer_ElementMixin} + * @private + */ + const superClass = ElementMixin(base); /** * @polymer * @mixinClass * @implements {Polymer_DisableUpgradeMixin} */ - class DisableUpgradeClass extends base { + class DisableUpgradeClass extends superClass { /** @override */ static get observedAttributes() { - return super.observedAttributes.concat(DISABLE_UPGRADE); + return super.observedAttributes.concat(DISABLED_ATTR); } /** @override */ attributeChangedCallback(name, old, value, namespace) { - if (name == DISABLE_UPGRADE) { + if (name == DISABLED_ATTR) { if (!this.__dataEnabled && value == null && this.isConnected) { super.connectedCallback(); } @@ -64,16 +70,18 @@ export const DisableUpgradeMixin = (base) => { } } - // disable while `disable-upgrade` is on - created() {} - - // disable while `disable-upgrade` is on - _applyListeners() {} + /* + NOTE: cannot gate on attribute because this is called before + attributes are delivered. Therefore, we stub this out and + call `super._initializeProperties()` manually. + */ + /** @override */ + _initializeProperties() {} // prevent user code in connected from running /** @override */ connectedCallback() { - if (this.__dataEnabled || !this.hasAttribute(DISABLE_UPGRADE)) { + if (this.__dataEnabled || !this.hasAttribute(DISABLED_ATTR)) { super.connectedCallback(); } } @@ -81,19 +89,11 @@ export const DisableUpgradeMixin = (base) => { // prevent element from turning on properties /** @override */ _enableProperties() { - if (!this.__dataEnabled) { - if (!this.hasAttribute(DISABLE_UPGRADE)) { - // When enabling, run previously disabled lifecycle. - // NOTE: This alters the timing of disabled lifecycle for all - // elements that support `disable-upgrade` - if (super.created) { - super.created(); - } - if (super._applyListeners) { - super._applyListeners(); - } - super._enableProperties(); + if (!this.hasAttribute(DISABLED_ATTR)) { + if (!this.__dataEnabled) { + super._initializeProperties(); } + super._enableProperties(); } } @@ -109,4 +109,4 @@ export const DisableUpgradeMixin = (base) => { return DisableUpgradeClass; -}; +}); diff --git a/lib/mixins/property-effects.js b/lib/mixins/property-effects.js index dd18e87479..ac85472154 100644 --- a/lib/mixins/property-effects.js +++ b/lib/mixins/property-effects.js @@ -39,8 +39,6 @@ const TYPES = { /** @const {RegExp} */ const capitalAttributeRegex = /[A-Z]/; -const DISABLE_UPGRADE = 'disable-upgrade'; - /** * @typedef {{ * name: (string | undefined), @@ -2552,9 +2550,6 @@ export const PropertyEffects = dedupingMixin(superClass => { } node.setAttribute(name, literal); } - if (kind == 'attribute' && name == DISABLE_UPGRADE) { - node.setAttribute(DISABLE_UPGRADE, ''); - } // 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 `$` diff --git a/test/unit/disable-upgrade.html b/test/unit/disable-upgrade.html index 7b7cd702f6..1c1fc78d7e 100644 --- a/test/unit/disable-upgrade.html +++ b/test/unit/disable-upgrade.html @@ -232,6 +232,9 @@

[[prop]]

}); test('elements call `registered` as expected with `disable-upgrade`', function() { + assert.notOk(el.$.disabledRegEl.hasRegistered); + assert.notOk(el.$.disabledRegBoundEl.hasRegistered); + el.enable(); assert.ok(el.$.disabledRegEl.hasRegistered); assert.ok(el.$.disabledRegBoundEl.hasRegistered); }); From e3b3baa70c2d78f3bc0dc975c2d726ccab3e270c Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Fri, 7 Dec 2018 12:30:22 -0800 Subject: [PATCH 07/33] Update to match 2.x branch --- lib/elements/dom-if.js | 23 ++++++++++++----------- lib/elements/dom-repeat.js | 9 +++++---- lib/legacy/legacy-element-mixin.js | 19 +------------------ lib/legacy/polymer.dom.js | 12 +++++------- lib/mixins/element-mixin.js | 12 +++++++----- lib/utils/flattened-nodes-observer.js | 18 +++++++++--------- lib/utils/templatize.js | 10 ++++++---- lib/utils/wrap.js | 19 +++++++++++++++++++ test/runner.html | 1 + 9 files changed, 65 insertions(+), 58 deletions(-) create mode 100644 lib/utils/wrap.js diff --git a/lib/elements/dom-if.js b/lib/elements/dom-if.js index f7f41c24f4..54742cb237 100644 --- a/lib/elements/dom-if.js +++ b/lib/elements/dom-if.js @@ -14,6 +14,7 @@ import { Debouncer } from '../utils/debounce.js'; import { enqueueDebouncer, flush } from '../utils/flush.js'; import { microTask } from '../utils/async.js'; import { root } from '../utils/path.js'; +import { wrap } from '../utils/wrap.js'; /** * The `` element will stamp a light-dom `