From ff25283a51d96ecbee72eea4b143cd9866744f75 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Mon, 1 Jul 2019 16:14:05 -0700 Subject: [PATCH] Closure type fixes. --- lib/elements/dom-if.js | 163 ++++++++++++++++++++++++--------- lib/elements/dom-repeat.js | 11 ++- lib/mixins/property-effects.js | 8 +- lib/mixins/template-stamp.js | 5 +- lib/utils/settings.js | 4 +- lib/utils/templatize.js | 30 +++--- 6 files changed, 147 insertions(+), 74 deletions(-) diff --git a/lib/elements/dom-if.js b/lib/elements/dom-if.js index eb049c5592..fdf567cdcc 100644 --- a/lib/elements/dom-if.js +++ b/lib/elements/dom-if.js @@ -89,6 +89,10 @@ class DomIfBase extends PolymerElement { this.__renderDebouncer = null; this._lastIf = false; this.__hideTemplateChildren__ = false; + /** @type {!HTMLTemplateElement|undefined} */ + this.__template; + /** @type {!TemplateInfo|undefined} */ + this._templateInfo; } __debounceRender() { @@ -145,19 +149,23 @@ class DomIfBase extends PolymerElement { /** * Ensures a template has been assigned to `this.__template`. If it has not * yet been, it querySelectors for it in its children and if it does not yet - * exist (e.g. in parser-generated case), opens a mutation observer and + * exist (e.g. in parser-generated case), opens a mutation observer and * waits for it to appear (returns false if it has not yet been found, * otherwise true). In the `removeNestedTemplates` case, the "template" will * be the `dom-if` element itself. - * + * * @return {boolean} True when a template has been found, false otherwise */ __ensureTemplate() { if (!this.__template) { // When `removeNestedTemplates` is true, the "template" is the element // itself, which has been given a `_templateInfo` property - let template = this._templateInfo ? this : - /** @type {HTMLTemplateElement} */(wrap(this).querySelector('template')); + const thisAsTemplate = /** @type {!HTMLTemplateElement} */ ( + /** @type {!HTMLElement} */ (this)); + let template = thisAsTemplate._templateInfo ? + thisAsTemplate : + /** @type {!HTMLTemplateElement} */ + (wrap(thisAsTemplate).querySelector('template')); if (!template) { // Wait until childList changes and template should be there by then let observer = new MutationObserver(() => { @@ -183,12 +191,12 @@ class DomIfBase extends PolymerElement { * connection or the template-finding mutation observer firing will queue * another render, causing this method to be called again at a more * appropriate time). - * + * * Subclasses should implement the following methods called here: * - `__hasInstance` * - `__createAndInsertInstance` * - `__getInstanceNodes` - * + * * @return {boolean} True if the instance was created, false otherwise. */ __ensureInstance() { @@ -225,7 +233,7 @@ class DomIfBase extends PolymerElement { * that multiple changes trigger only a single render. The render method * should be called if, for example, template rendering is required to * validate application state. - * + * * @return {void} */ render() { @@ -238,7 +246,7 @@ class DomIfBase extends PolymerElement { * 2. Remove the template instance (when false and restamp:true) * 3. Sync the hidden state of the instance nodes with the if/restamp state * 4. Fires the `dom-change` event when necessary - * + * * @return {void} */ __render() { @@ -259,6 +267,54 @@ class DomIfBase extends PolymerElement { this._lastIf = this.if; } } + + /** + * Abstract API to be implemented by subclass: Returns true if a template + * instance has been created and inserted. + * + * @protected + * @return {boolean} True when an instance has been created. + */ + __hasInstance() { } + + /** + * Abstract API to be implemented by subclass: Returns the child nodes stamped + * from a template instance. + * + * @protected + * @return {Array} Array of child nodes stamped from the template + * instance. + */ + __getInstanceNodes() { } + + /** + * Abstract API to be implemented by subclass: Creates an instance of the + * template and inserts it into the given parent node. + * + * @protected + * @param {Node} parentNode The parent node to insert the instance into + * @return {void} + */ + __createAndInsertInstance(parentNode) { } + + /** + * Abstract API to be implemented by subclass: Removes nodes created by an + * instance of a template and any associated cleanup. + * + * @protected + * @return {void} + */ + __teardownInstance() { } + + /** + * Abstract API to be implemented by subclass: Shows or hides any template + * instance childNodes based on the `if` state of the element and its + * `__hideTemplateChildren__` property. + * + * @protected + * @return {void} + */ + _showHideChildren() { } } /** @@ -291,7 +347,8 @@ class DomIfFast extends DomIfBase { /** * Implementation of abstract API needed by DomIfBase. - * + * + * @override * @return {boolean} True when an instance has been created. */ __hasInstance() { @@ -301,6 +358,7 @@ class DomIfFast extends DomIfBase { /** * Implementation of abstract API needed by DomIfBase. * + * @override * @return {Array} Array of child nodes stamped from the template * instance. */ @@ -314,6 +372,7 @@ class DomIfFast extends DomIfBase { * Stamps the template by calling `_stampTemplate` on the `__dataHost` of this * element and then inserts the resulting nodes into the given `parentNode`. * + * @override * @param {Node} parentNode The parent node to insert the instance into * @return {void} */ @@ -325,7 +384,8 @@ class DomIfFast extends DomIfBase { } } // Pre-bind and link the template into the effects system - const templateInfo = host._bindTemplate(this.__template, true); + const templateInfo = host._bindTemplate( + /** @type {!HTMLTemplateElement} */ (this.__template), true); // Install runEffects hook that prevents running property effects // (and any nested template effects) when the `if` is false templateInfo.runEffects = (runEffects, changedProps) => { @@ -354,13 +414,14 @@ class DomIfFast extends DomIfBase { } }; // Stamp the template, and set its DocumentFragment to the "instance" - this.__instance = host._stampTemplate(this.__template, templateInfo); + this.__instance = host._stampTemplate( + /** @type {!HTMLTemplateElement} */ (this.__template), templateInfo); wrap(parentNode).insertBefore(this.__instance, this); } /** * Run effects for any properties that changed while the `if` was false. - * + * * @return {void} */ __syncHostProperties() { @@ -373,25 +434,29 @@ class DomIfFast extends DomIfBase { /** * Implementation of abstract API needed by DomIfBase. - * + * * Remove the instance and any nodes it created. Uses the `__dataHost`'s * runtime `_removeBoundDom` method. - * + * + * @override * @return {void} */ __teardownInstance() { const host = this.__dataHost || this; if (this.__instance) { host._removeBoundDom(this.__instance); - this.__syncProps = null; this.__instance = null; } } /** + * Implementation of abstract API needed by DomIfBase. + * * Shows or hides the template instance top level child nodes. For * text nodes, `textContent` is removed while "hidden" and replaced when * "shown." + * + * @override * @return {void} * @protected * @suppress {visibility} @@ -410,7 +475,7 @@ class DomIfFast extends DomIfBase { /** * The "legacy" implementation of `dom-if`, implemented using `Templatizer`. - * + * * In this version, `this.__instance` is the `TemplateInstance` returned * from the templatized constructor. */ @@ -425,7 +490,8 @@ class DomIfLegacy extends DomIfBase { /** * Implementation of abstract API needed by DomIfBase. - * + * + * @override * @return {boolean} True when an instance has been created. */ __hasInstance() { @@ -435,6 +501,7 @@ class DomIfLegacy extends DomIfBase { /** * Implementation of abstract API needed by DomIfBase. * + * @override * @return {Array} Array of child nodes stamped from the template * instance. */ @@ -449,36 +516,39 @@ class DomIfLegacy extends DomIfBase { * constructor (which is created lazily if it does not yet exist), and then * inserts its resulting `root` doc fragment into the given `parentNode`. * + * @override * @param {Node} parentNode The parent node to insert the instance into * @return {void} */ __createAndInsertInstance(parentNode) { // Ensure we have an instance constructor if (!this.__ctor) { - this.__ctor = templatize(this.__template, this, { - // dom-if templatizer instances require `mutable: true`, as - // `__syncHostProperties` relies on that behavior to sync objects - mutableData: true, - /** - * @param {string} prop Property to forward - * @param {*} value Value of property - * @this {DomIf} - */ - forwardHostProp: function(prop, value) { - if (this.__instance) { - if (this.if) { - this.__instance.forwardHostProp(prop, value); - } else { - // If we have an instance but are squelching host property - // forwarding due to if being false, note the invalidated - // properties so `__syncHostProperties` can sync them the next - // time `if` becomes true - this.__invalidProps = this.__invalidProps || Object.create(null); - this.__invalidProps[root(prop)] = true; + this.__ctor = templatize( + /** @type {!HTMLTemplateElement} */ (this.__template), this, { + // dom-if templatizer instances require `mutable: true`, as + // `__syncHostProperties` relies on that behavior to sync objects + mutableData: true, + /** + * @param {string} prop Property to forward + * @param {*} value Value of property + * @this {DomIfLegacy} + */ + forwardHostProp: function(prop, value) { + if (this.__instance) { + if (this.if) { + this.__instance.forwardHostProp(prop, value); + } else { + // If we have an instance but are squelching host property + // forwarding due to if being false, note the invalidated + // properties so `__syncHostProperties` can sync them the next + // time `if` becomes true + this.__invalidProps = + this.__invalidProps || Object.create(null); + this.__invalidProps[root(prop)] = true; + } + } } - } - } - }); + }); } // Create and insert the instance this.__instance = new this.__ctor(); @@ -487,9 +557,10 @@ class DomIfLegacy extends DomIfBase { /** * Implementation of abstract API needed by DomIfBase. - * + * * Removes the instance and any nodes it created. - * + * + * @override * @return {void} */ __teardownInstance() { @@ -515,7 +586,7 @@ class DomIfLegacy extends DomIfBase { /** * Forwards any properties that changed while the `if` was false into the * template instance and flushes it. - * + * * @return {void} */ __syncHostProperties() { @@ -530,11 +601,15 @@ class DomIfLegacy extends DomIfBase { } /** + * Implementation of abstract API needed by DomIfBase. + * * Shows or hides the template instance top level child elements. For * text nodes, `textContent` is removed while "hidden" and replaced when * "shown." - * @return {void} + * + * @override * @protected + * @return {void} * @suppress {visibility} */ _showHideChildren() { diff --git a/lib/elements/dom-repeat.js b/lib/elements/dom-repeat.js index a12e797d40..85204d840a 100644 --- a/lib/elements/dom-repeat.js +++ b/lib/elements/dom-repeat.js @@ -301,6 +301,8 @@ export class DomRepeat extends domRepeatBase { this.__ctor = null; this.__isDetached = true; this.template = null; + /** @type {TemplateInfo} */ + this._templateInfo; } /** @@ -341,10 +343,13 @@ export class DomRepeat extends domRepeatBase { if (!this.__ctor) { // When `removeNestedTemplates` is true, the "template" is the element // itself, which has been given a `_templateInfo` property - let template = this.template = this._templateInfo ? this : - /** @type {HTMLTemplateElement} */(this.querySelector('template')); + const thisAsTemplate = /** @type {!HTMLTemplateElement} */ ( + /** @type {!HTMLElement} */ (this)); + let template = this.template = thisAsTemplate._templateInfo ? + thisAsTemplate : + /** @type {!HTMLTemplateElement} */ (this.querySelector('template')); if (!template) { - // // Wait until childList changes and template should be there by then + // Wait until childList changes and template should be there by then let observer = new MutationObserver(() => { if (this.querySelector('template')) { observer.disconnect(); diff --git a/lib/mixins/property-effects.js b/lib/mixins/property-effects.js index 9335b9a73e..190690ab7c 100644 --- a/lib/mixins/property-effects.js +++ b/lib/mixins/property-effects.js @@ -1274,9 +1274,6 @@ function upper(name) { * @appliesMixin PropertyAccessors * @summary Element class mixin that provides meta-programming for Polymer's * template binding and data observation system. - * @template T - * @param {function(new:T)} superClass Class to apply mixin to. - * @return {function(new:T)} superClass with mixin applied. */ export const PropertyEffects = dedupingMixin(superClass => { @@ -1350,9 +1347,6 @@ export const PropertyEffects = dedupingMixin(superClass => { this.__templateInfo; } - /** - * @return {!Object} Effect prototype property name map. - */ get PROPERTY_EFFECT_TYPES() { return TYPES; } @@ -2762,7 +2756,7 @@ export const PropertyEffects = dedupingMixin(superClass => { * in the main element template. * * @param {!HTMLTemplateElement} template Template to stamp - * @param {Object=} templateInfo Optional bound template info associated + * @param {TemplateInfo=} templateInfo Optional bound template info associated * with the template to be stamped; if omitted the template will be * automatically bound. * @return {!StampedTemplate} Cloned template content diff --git a/lib/mixins/template-stamp.js b/lib/mixins/template-stamp.js index 7f32fbf0a2..f2d194f2e7 100644 --- a/lib/mixins/template-stamp.js +++ b/lib/mixins/template-stamp.js @@ -106,9 +106,6 @@ function createNodeEventHandler(context, eventName, methodName) { * @mixinFunction * @polymer * @summary Element class mixin that provides basic template parsing and stamping - * @template T - * @param {function(new:T)} superClass Class to apply mixin to. - * @return {function(new:T)} superClass with mixin applied. */ export const TemplateStamp = dedupingMixin( /** @@ -439,7 +436,7 @@ export const TemplateStamp = dedupingMixin( * is removed and stored in notes as well. * * @param {!HTMLTemplateElement} template Template to stamp - * @param {Object=} templateInfo Optional template info associated + * @param {TemplateInfo=} templateInfo Optional template info associated * with the template to be stamped; if omitted the template will be * automatically parsed. * @return {!StampedTemplate} Cloned template content diff --git a/lib/utils/settings.js b/lib/utils/settings.js index 42040591e5..6e61d6cad9 100644 --- a/lib/utils/settings.js +++ b/lib/utils/settings.js @@ -23,7 +23,7 @@ export const useNativeCustomElements = !(window.customElements.polyfillWrapFlush * `rootPath` to provide a stable application mount path when * using client side routing. */ -export let rootPath = window.Polymer && window.Polymer.rootPath || +export let rootPath = window.Polymer && window.Polymer.rootPath || pathFromUrl(document.baseURI || window.location.href); /** @@ -279,7 +279,7 @@ export const setCancelSyntheticClickEvents = function(useCancelSyntheticClickEve /** * Setting to remove nested templates inside `dom-if` and `dom-repeat` as * part of element template parsing. This is a performance optimization that - * eliminates most of the tax of needing two elements due to the loss of + * eliminates most of the tax of needing two elements due to the loss of * type-extended templates as a result of the V1 specification changes. */ export let removeNestedTemplates = diff --git a/lib/utils/templatize.js b/lib/utils/templatize.js index ecfd8c4af0..a51dd76c65 100644 --- a/lib/utils/templatize.js +++ b/lib/utils/templatize.js @@ -102,10 +102,7 @@ function upgradeTemplate(template, constructor) { * @implements {Polymer_PropertyEffects} * @private */ -const templateInstanceBase = PropertyEffects( - // This cast shouldn't be neccessary, but Closure doesn't understand that - // "class {}" is a constructor function. - /** @type {function(new:Object)} */(class {})); +const templateInstanceBase = PropertyEffects(class {}); export function showHideChildren(hide, children) { for (let i=0; iinstances effects // and host <- template effects @@ -637,7 +639,7 @@ function warnOnUndeclaredProperties(templateInfo, options, methodHost) { } } } - } + } } /**