Skip to content

Commit

Permalink
Adds disable-upgrade functionality directly to LegacyElementMixin
Browse files Browse the repository at this point in the history
  • Loading branch information
Steven Orvell committed Jan 8, 2020
1 parent 12c3913 commit a4b4723
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 167 deletions.
146 changes: 1 addition & 145 deletions lib/legacy/class.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.]
Expand Down Expand Up @@ -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) {
Expand All @@ -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}
*/
Expand Down Expand Up @@ -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
Expand Down
152 changes: 130 additions & 22 deletions lib/legacy/legacy-element-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -92,6 +98,9 @@ export const LegacyElementMixin = dedupingMixin((base) => {
this.__boundListeners;
/** @type {?Object<string, ?Function>} */
this._debouncers;
// NOTE: Inlined for perf from version of DisableUpgradeMixin.
/** @type {boolean|undefined} */
this.__isUpgradeDisabled;
}

/**
Expand All @@ -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`
Expand All @@ -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();
}
}

/**
Expand All @@ -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();
}
}

/**
Expand All @@ -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);
}
}
}

Expand All @@ -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();
}

/**
Expand Down

0 comments on commit a4b4723

Please sign in to comment.