diff --git a/lib/legacy/class.js b/lib/legacy/class.js index 23a52a198a..aee2511be1 100644 --- a/lib/legacy/class.js +++ b/lib/legacy/class.js @@ -9,11 +9,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN */ import { LegacyElementMixin } from './legacy-element-mixin.js'; -import { legacyOptimizations, legacyNoObservedAttributes } from '../utils/settings.js'; -import { findObservedAttributesGetter } from '../mixins/disable-upgrade-mixin.js'; -import { wrap } from '../utils/wrap.js'; - -const DISABLED_ATTR = 'disable-upgrade'; +import { legacyOptimizations } from '../utils/settings.js'; const lifecycleProps = { attached: true, @@ -180,7 +176,6 @@ function mergeProperties(target, source) { } const LegacyElement = LegacyElementMixin(HTMLElement); -const observedAttributesGetter = findObservedAttributesGetter(LegacyElement); /* Note about construction and extension of legacy classes. [Changed in Q4 2018 to optimize performance.] @@ -286,14 +281,6 @@ function GenerateClassFromInfo(info, Base, behaviors) { * @return {void} */ created() { - // Pull all attribute values 1x if `legacyNoObservedAttributes` is set. - if (legacyNoObservedAttributes && this.hasAttributes()) { - const a = this.attributes; - for (let i=0, l=a.length; i < l; i++) { - const attr = a[i]; - this.__attributeReaction(attr.name, null, attr.value); - } - } super.created(); const list = lifecycle.created; if (list) { @@ -303,42 +290,6 @@ function GenerateClassFromInfo(info, Base, behaviors) { } } - /** - * Processes an attribute reaction when the `legacyNoObservedAttributes` - * setting is in use. - * @param {string} name Name of attribute that changed - * @param {?string} old Old attribute value - * @param {?string} value New attribute value - * @return {void} - */ - __attributeReaction(name, old, value) { - if ((this.__dataAttributes && this.__dataAttributes[name]) || name === DISABLED_ATTR) { - this.attributeChangedCallback(name, old, value); - } - } - - /** @override */ - setAttribute(name, value) { - if (legacyNoObservedAttributes) { - const oldValue = this.getAttribute(name); - super.setAttribute(name, value); - this.__attributeReaction(name, oldValue, value); - } else { - super.setAttribute(name, value); - } - } - - /** @override */ - removeAttribute(name) { - if (legacyNoObservedAttributes) { - const oldValue = this.getAttribute(name); - super.removeAttribute(name); - this.__attributeReaction(name, oldValue, null); - } else { - super.removeAttribute(name); - } - } - /** * @return {void} */ @@ -473,101 +424,6 @@ function GenerateClassFromInfo(info, Base, behaviors) { } } } - - // NOTE: Inlined for perf from version of DisableUpgradeMixin. - constructor() { - super(); - /** @type {boolean|undefined} */ - this.__isUpgradeDisabled; - } - - // NOTE: Inlined for perf from version of DisableUpgradeMixin. - /** @override */ - static get observedAttributes() { - return legacyNoObservedAttributes ? [] : - observedAttributesGetter.call(this).concat(DISABLED_ATTR); - } - - // NOTE: Inlined for perf from version of DisableUpgradeMixin. - // Prevent element from initializing properties when it's upgrade disabled. - /** @override */ - _initializeProperties() { - if (this.hasAttribute(DISABLED_ATTR)) { - this.__isUpgradeDisabled = true; - } else { - super._initializeProperties(); - } - } - - // NOTE: Inlined for perf from version of DisableUpgradeMixin. - // Prevent element from enabling properties when it's upgrade disabled. - // Normally overriding connectedCallback would be enough, but dom-* elements - /** @override */ - _enableProperties() { - if (!this.__isUpgradeDisabled) { - super._enableProperties(); - } - } - - // NOTE: Inlined for perf from version of DisableUpgradeMixin. - // If the element starts upgrade-disabled and a property is set for - // which an accessor exists, the default should not be applied. - // This additional check is needed because defaults are applied via - // `_initializeProperties` which is called after initial properties - // have been set when the element starts upgrade-disabled. - /** @override */ - _canApplyPropertyDefault(property) { - return super._canApplyPropertyDefault(property) && - !(this.__isUpgradeDisabled && this._isPropertyPending(property)); - } - - // NOTE: Inlined for perf from version of DisableUpgradeMixin. - /** - * @override - * @param {string} name Attribute name. - * @param {?string} old The previous value for the attribute. - * @param {?string} value The new value for the attribute. - * @param {?string} namespace The XML namespace for the attribute. - * @return {void} - */ - attributeChangedCallback(name, old, value, namespace) { - if (name == DISABLED_ATTR) { - // When disable-upgrade is removed, intialize properties and - // provoke connectedCallback if the element is already connected. - if (this.__isUpgradeDisabled && value == null) { - super._initializeProperties(); - this.__isUpgradeDisabled = false; - if (wrap(this).isConnected) { - super.connectedCallback(); - } - } - } else { - super.attributeChangedCallback( - name, old, value, /** @type {null|string} */ (namespace)); - } - } - - // NOTE: Inlined for perf from version of DisableUpgradeMixin. - // Prevent element from connecting when it's upgrade disabled. - // This prevents user code in `attached` from being called. - /** @override */ - connectedCallback() { - if (!this.__isUpgradeDisabled) { - super.connectedCallback(); - } - } - - // NOTE: Inlined for perf from version of DisableUpgradeMixin. - // Prevent element from disconnecting when it's upgrade disabled. - // This avoids allowing user code `detached` from being called without a - // paired call to `attached`. - /** @override */ - disconnectedCallback() { - if (!this.__isUpgradeDisabled) { - super.disconnectedCallback(); - } - } - } // apply behaviors, note actual copying is done lazily at first instance creation diff --git a/lib/legacy/legacy-element-mixin.js b/lib/legacy/legacy-element-mixin.js index 963e496853..53a4c18d59 100644 --- a/lib/legacy/legacy-element-mixin.js +++ b/lib/legacy/legacy-element-mixin.js @@ -21,6 +21,10 @@ import { timeOut, microTask } from '../utils/async.js'; import { get } from '../utils/path.js'; import { wrap } from '../utils/wrap.js'; import { scopeSubtree } from '../utils/scope-subtree.js'; +import { legacyNoObservedAttributes } from '../utils/settings.js'; +import { findObservedAttributesGetter } from '../mixins/disable-upgrade-mixin.js'; + +const DISABLED_ATTR = 'disable-upgrade'; let styleInterface = window.ShadyCSS; @@ -64,6 +68,8 @@ export const LegacyElementMixin = dedupingMixin((base) => { const legacyElementBase = builtCSS ? GesturesElement : DirMixin(GesturesElement); + const observedAttributesGetter = findObservedAttributesGetter(legacyElementBase); + /** * Map of simple names to touch action names * @dict @@ -92,6 +98,9 @@ export const LegacyElementMixin = dedupingMixin((base) => { this.__boundListeners; /** @type {?Object} */ this._debouncers; + // NOTE: Inlined for perf from version of DisableUpgradeMixin. + /** @type {boolean|undefined} */ + this.__isUpgradeDisabled; } /** @@ -113,7 +122,82 @@ export const LegacyElementMixin = dedupingMixin((base) => { * @override * @return {void} */ - created() {} + created() { + // Pull all attribute values 1x if `legacyNoObservedAttributes` is set. + if (legacyNoObservedAttributes && this.hasAttributes()) { + const a = this.attributes; + for (let i=0, l=a.length; i < l; i++) { + const attr = a[i]; + this.__attributeReaction(attr.name, null, attr.value); + } + } + } + + /** + * Processes an attribute reaction when the `legacyNoObservedAttributes` + * setting is in use. + * @param {string} name Name of attribute that changed + * @param {?string} old Old attribute value + * @param {?string} value New attribute value + * @return {void} + */ + __attributeReaction(name, old, value) { + if ((this.__dataAttributes && this.__dataAttributes[name]) || name === DISABLED_ATTR) { + this.attributeChangedCallback(name, old, value, null); + } + } + + /** @override */ + setAttribute(name, value) { + if (legacyNoObservedAttributes) { + const oldValue = this.getAttribute(name); + super.setAttribute(name, value); + // value coerced to String for closure's benefit + this.__attributeReaction(name, oldValue, String(value)); + } else { + super.setAttribute(name, value); + } + } + + /** @override */ + removeAttribute(name) { + if (legacyNoObservedAttributes) { + const oldValue = this.getAttribute(name); + super.removeAttribute(name); + this.__attributeReaction(name, oldValue, null); + } else { + super.removeAttribute(name); + } + } + + // NOTE: Inlined for perf from version of DisableUpgradeMixin. + /** @override */ + static get observedAttributes() { + return legacyNoObservedAttributes ? [] : + observedAttributesGetter.call(this).concat(DISABLED_ATTR); + } + + // NOTE: Inlined for perf from version of DisableUpgradeMixin. + // Prevent element from enabling properties when it's upgrade disabled. + // Normally overriding connectedCallback would be enough, but dom-* elements + /** @override */ + _enableProperties() { + if (!this.__isUpgradeDisabled) { + super._enableProperties(); + } + } + + // NOTE: Inlined for perf from version of DisableUpgradeMixin. + // If the element starts upgrade-disabled and a property is set for + // which an accessor exists, the default should not be applied. + // This additional check is needed because defaults are applied via + // `_initializeProperties` which is called after initial properties + // have been set when the element starts upgrade-disabled. + /** @override */ + _canApplyPropertyDefault(property) { + return super._canApplyPropertyDefault(property) && + !(this.__isUpgradeDisabled && this._isPropertyPending(property)); + } /** * Provides an implementation of `connectedCallback` @@ -122,9 +206,12 @@ export const LegacyElementMixin = dedupingMixin((base) => { * @override */ connectedCallback() { - super.connectedCallback(); - this.isAttached = true; - this.attached(); + // NOTE: Inlined for perf from version of DisableUpgradeMixin. + if (!this.__isUpgradeDisabled) { + super.connectedCallback(); + this.isAttached = true; + this.attached(); + } } /** @@ -142,9 +229,12 @@ export const LegacyElementMixin = dedupingMixin((base) => { * @override */ disconnectedCallback() { - super.disconnectedCallback(); - this.isAttached = false; - this.detached(); + // NOTE: Inlined for perf from version of DisableUpgradeMixin. + if (!this.__isUpgradeDisabled) { + super.disconnectedCallback(); + this.isAttached = false; + this.detached(); + } } /** @@ -167,8 +257,21 @@ export const LegacyElementMixin = dedupingMixin((base) => { */ attributeChangedCallback(name, old, value, namespace) { if (old !== value) { - super.attributeChangedCallback(name, old, value, namespace); - this.attributeChanged(name, old, value); + // NOTE: Inlined for perf from version of DisableUpgradeMixin. + if (name == DISABLED_ATTR) { + // When disable-upgrade is removed, intialize properties and + // provoke connectedCallback if the element is already connected. + if (this.__isUpgradeDisabled && value == null) { + this._initializeProperties(); + this.__isUpgradeDisabled = false; + if (wrap(this).isConnected) { + this.connectedCallback(); + } + } + } else { + super.attributeChangedCallback(name, old, value, namespace); + this.attributeChanged(name, old, value); + } } } @@ -193,20 +296,25 @@ export const LegacyElementMixin = dedupingMixin((base) => { * @suppress {invalidCasts} */ _initializeProperties() { - let proto = Object.getPrototypeOf(this); - if (!proto.hasOwnProperty(JSCompiler_renameProperty('__hasRegisterFinished', proto))) { - this._registered(); - // backstop in case the `_registered` implementation does not set this - proto.__hasRegisterFinished = true; + // NOTE: Inlined for perf from version of DisableUpgradeMixin. + if (this.hasAttribute(DISABLED_ATTR)) { + this.__isUpgradeDisabled = true; + } else { + let proto = Object.getPrototypeOf(this); + if (!proto.hasOwnProperty(JSCompiler_renameProperty('__hasRegisterFinished', proto))) { + this._registered(); + // backstop in case the `_registered` implementation does not set this + proto.__hasRegisterFinished = true; + } + super._initializeProperties(); + this.root = /** @type {HTMLElement} */(this); + this.created(); + // Ensure listeners are applied immediately so that they are + // added before declarative event listeners. This allows an element to + // decorate itself via an event prior to any declarative listeners + // seeing the event. Note, this ensures compatibility with 1.x ordering. + this._applyListeners(); } - super._initializeProperties(); - this.root = /** @type {HTMLElement} */(this); - this.created(); - // Ensure listeners are applied immediately so that they are - // added before declarative event listeners. This allows an element to - // decorate itself via an event prior to any declarative listeners - // seeing the event. Note, this ensures compatibility with 1.x ordering. - this._applyListeners(); } /**