diff --git a/lib/legacy/class.js b/lib/legacy/class.js index f28f15d93f..5e7062c764 100644 --- a/lib/legacy/class.js +++ b/lib/legacy/class.js @@ -175,6 +175,10 @@ function mergeProperties(target, source) { } } +const DISABLED_ATTR = 'disable-upgrade'; + +let observedAttributesGetter; + /* Note about construction and extension of legacy classes. [Changed in Q4 2018 to optimize performance.] @@ -211,9 +215,85 @@ function GenerateClassFromInfo(info, Base, behaviors) { let behaviorList; const lifecycle = {}; + // Work around for closure bug #126934458. Using `super` in a property + // getter does not work so instead we search the Base prototype for an + // implementation of observedAttributes so that we can override and call + // the `super` getter. Note, this is done one time ever because we assume + // that `Base` is always comes from `Polymer.LegacyElementMixn`. + if (!observedAttributesGetter) { + let ctor = Base; + while (ctor && !observedAttributesGetter) { + const desc = Object.getOwnPropertyDescriptor(ctor, 'observedAttributes'); + if (desc) { + observedAttributesGetter = desc.get; + } + ctor = Object.getPrototypeOf(ctor.prototype).constructor; + } + } + /** @private */ class PolymerGenerated extends Base { + static get observedAttributes() { + return observedAttributesGetter.call(this).concat(DISABLED_ATTR); + } + + /** + * @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) { + if (!this.__dataEnabled && value == null && this.isConnected) { + super.connectedCallback(); + } + } else { + super.attributeChangedCallback( + name, old, value, /** @type {null|string} */ (namespace)); + } + } + + + // prevent user code in connected from running + /** @override */ + connectedCallback() { + if (this.__dataEnabled || !this.hasAttribute(DISABLED_ATTR)) { + super.connectedCallback(); + } + } + + _initializeProperties() { + if (!this.hasAttribute(DISABLED_ATTR)) { + super._initializeProperties(); + } else { + this.__wasDisabled = true; + } + } + + // prevent element from turning on properties + /** @override */ + _enableProperties() { + if (this.__wasDisabled) { + this.__wasDisabled = false; + super._initializeProperties(); + } + if (!this.hasAttribute(DISABLED_ATTR)) { + super._enableProperties(); + } + } + + // only go if "enabled" + /** @override */ + disconnectedCallback() { + if (this.__dataEnabled) { + super.disconnectedCallback(); + } + } + // explicitly not calling super._finalizeClass /** @nocollapse */ static _finalizeClass() { diff --git a/lib/legacy/legacy-element-mixin.js b/lib/legacy/legacy-element-mixin.js index c4aa7a0286..47ff986954 100644 --- a/lib/legacy/legacy-element-mixin.js +++ b/lib/legacy/legacy-element-mixin.js @@ -8,7 +8,7 @@ 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 '@webcomponents/shadycss/entrypoints/apply-shim.js'; -import { ElementMixin } from '../mixins/element-mixin.js'; +import { ElementMixin, builtCSS } from '../mixins/element-mixin.js'; import { GestureEventListeners } from '../mixins/gesture-event-listeners.js'; import { DirMixin } from '../mixins/dir-mixin.js'; import { dedupingMixin } from '../utils/mixin.js'; @@ -39,6 +39,12 @@ let styleInterface = window.ShadyCSS; * @summary Element class mixin that provides Polymer's "legacy" API */ export const LegacyElementMixin = dedupingMixin((base) => { + + const GesturesElement = GestureEventListeners(ElementMixin(base)); + + // Note, the DirMixin does nothing if css is built so avoid including it + // in that case. + /** * @constructor * @implements {Polymer_ElementMixin} @@ -47,7 +53,8 @@ export const LegacyElementMixin = dedupingMixin((base) => { * @extends {HTMLElement} * @private */ - const legacyElementBase = DirMixin(GestureEventListeners(ElementMixin(base))); + const legacyElementBase = builtCSS ? GesturesElement : + DirMixin(GesturesElement); /** * Map of simple names to touch action names diff --git a/lib/mixins/element-mixin.js b/lib/mixins/element-mixin.js index dd3a8708a2..c655411d36 100644 --- a/lib/mixins/element-mixin.js +++ b/lib/mixins/element-mixin.js @@ -26,7 +26,7 @@ import { wrap } from '../utils/wrap.js'; */ export const version = '3.2.0'; -const builtCSS = window.ShadyCSS && window.ShadyCSS['cssBuild']; +export const builtCSS = window.ShadyCSS && window.ShadyCSS['cssBuild']; /** * Element class mixin that provides the core API for Polymer's meta-programming @@ -801,7 +801,7 @@ export const ElementMixin = dedupingMixin(base => { // shorthand when attribute deserialization is not important. if (legacyWarnings && !(prop in this._properties) && // Methods used in templates with no dependencies (or only literal - // dependencies) become accessors with template effects; ignore these + // dependencies) become accessors with template effects; ignore these !(effect.info.part.signature && effect.info.part.signature.static) && // Warnings for bindings added to nested templates are handled by // templatizer so ignore both the host-to-template bindings diff --git a/lib/mixins/property-effects.js b/lib/mixins/property-effects.js index e5af97ce51..410f3c9de5 100644 --- a/lib/mixins/property-effects.js +++ b/lib/mixins/property-effects.js @@ -2880,6 +2880,10 @@ export const PropertyEffects = dedupingMixin(superClass => { } node.setAttribute(name, literal); } + // support disable-upgrade + if (kind == 'attribute' && origName == 'disable-upgrade$') { + node.setAttribute(name, ''); + } // 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 `$`