UNPKG

@polymer/polymer

Version:

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

167 lines (151 loc) 5.98 kB
/** * @fileoverview * @suppress {checkPrototypalTypes} * @license Copyright (c) 2017 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt The complete set of authors may be found * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by * Google as part of the polymer project is also subject to an additional IP * rights grant found at http://polymer.github.io/PATENTS.txt */ import { ElementMixin } from './element-mixin.js'; import { dedupingMixin } from '../utils/mixin.js'; import { wrap } from '../utils/wrap.js'; const DISABLED_ATTR = 'disable-upgrade'; export const findObservedAttributesGetter = (ctor) => { while (ctor) { const desc = Object.getOwnPropertyDescriptor(ctor, 'observedAttributes'); if (desc) { return desc.get; } ctor = Object.getPrototypeOf(ctor.prototype).constructor; } return () => []; }; /** * 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. * * 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. * * Note, this mixin must be applied on top of any element class that * itself implements a `connectedCallback` so that it can control the work * done in `connectedCallback`. For example, * * MyClass = DisableUpgradeMixin(class extends BaseClass {...}); * * @mixinFunction * @polymer * @appliesMixin ElementMixin * @template T * @param {function(new:T)} superClass Class to apply mixin to. * @return {function(new:T)} superClass with mixin applied. */ export const DisableUpgradeMixin = dedupingMixin((base) => { /** * @constructor * @implements {Polymer_ElementMixin} * @extends {HTMLElement} * @private */ const superClass = ElementMixin(base); // 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`. let observedAttributesGetter = findObservedAttributesGetter(superClass); /** * @polymer * @mixinClass * @implements {Polymer_DisableUpgradeMixin} */ class DisableUpgradeClass extends superClass { constructor() { super(); /** @type {boolean|undefined} */ this.__isUpgradeDisabled; } static get observedAttributes() { return observedAttributesGetter.call(this).concat(DISABLED_ATTR); } // Prevent element from initializing properties when it's upgrade disabled. /** @override */ _initializeProperties() { if (this.hasAttribute(DISABLED_ATTR)) { this.__isUpgradeDisabled = true; } else { super._initializeProperties(); } } // 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(); } } // 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)); } /** * @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, initialize 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)); } } // 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(); } } // 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(); } } } return DisableUpgradeClass; });