diff --git a/lib/legacy/class.js b/lib/legacy/class.js index 47793460c1..d8ff532a3e 100644 --- a/lib/legacy/class.js +++ b/lib/legacy/class.js @@ -148,24 +148,6 @@ function GenerateClassFromInfo(info, Base) { return info.observers; } - /** - * @return {HTMLTemplateElement} template for this class - */ - static get template() { - if (!this.hasOwnProperty(JSCompiler_renameProperty('_template', this))) { - this._template = - // Accept template: _null to short-circuit dom-module lookup - info._template !== undefined ? info._template : - // Look in dom-module associated with this element's is - this._getTemplateFromDomModule() || - // Look up in the chain - Base.template || - // Use any template set on the prototype via registered callback - this.prototype._template; - } - return this._template; - } - /** * @return {void} */ diff --git a/lib/mixins/element-mixin.js b/lib/mixins/element-mixin.js index 11f2925825..cb74216440 100644 --- a/lib/mixins/element-mixin.js +++ b/lib/mixins/element-mixin.js @@ -270,6 +270,29 @@ export const ElementMixin = dedupingMixin(base => { } } + /** + * Look up template from dom-module for element + * + * @param {!string} is Element name to look up + * @return {!HTMLTemplateElement} Template found in dom module, or + * undefined if not found + * @protected + */ + function getTemplateFromDomModule(is) { + let template = null; + // Under strictTemplatePolicy in 3.x+, dom-module lookup is only allowed + // when opted-in via allowTemplateFromDomModule + if (is && (!strictTemplatePolicy || allowTemplateFromDomModule)) { + template = DomModule.import(is, 'template'); + // Under strictTemplatePolicy, require any element with an `is` + // specified to have a dom-module + if (strictTemplatePolicy && !template) { + throw new Error(`strictTemplatePolicy: expecting dom-module or null template for ${is}`); + } + } + return template; + } + /** * @polymer * @mixinClass @@ -341,30 +364,6 @@ export const ElementMixin = dedupingMixin(base => { } } - /** - * Look up template from dom-module for element - * - * @param {!string} is Element name to look up - * @return {!HTMLTemplateElement} Template found in dom module, or - * undefined if not found - * @protected - */ - static _getTemplateFromDomModule() { - let template = null; - const is = /** @type {PolymerElementConstructor}*/ (this).is; - // Under strictTemplatePolicy in 3.x+, dom-module lookup is only allowed - // when opted-in via allowTemplateFromDomModule - if (is && (!strictTemplatePolicy || allowTemplateFromDomModule)) { - template = DomModule.import(is, 'template'); - // Under strictTemplatePolicy, require any element with an `is` - // specified to have a dom-module - if (strictTemplatePolicy && !template) { - throw new Error(`strictTemplatePolicy: expecting dom-module or null template for ${is}`); - } - } - return template; - } - /** * Returns the template that will be stamped into this element's shadow root. * @@ -402,13 +401,30 @@ export const ElementMixin = dedupingMixin(base => { * @return {HTMLTemplateElement|string} Template to be stamped */ static get template() { + // Explanation of template-related properties: + // - constructor.template (this getter): the template for the class. + // This can come from the prototype (for legacy elements), from a + // dom-module, or from the super class's template (or can be overridden + // altogether by the user) + // - constructor._template: memoized version of constructor.template + // - prototype._template: working template for the element, which will be + // parsed and modified in place. It is a cloned version of + // constructor.template, saved in _finalizeClass(). Note that before + // this getter is called, for legacy elements this could be from a + // _template field on the info object passed to Polymer(), a behavior, + // or set in registered(); once the static getter runs, a clone of it + // will overwrite it on the prototype as the working template. if (!this.hasOwnProperty(JSCompiler_renameProperty('_template', this))) { this._template = + // If user has put template on prototype (e.g. in legacy via registered + // callback or info object), prefer that first + this.prototype.hasOwnProperty(JSCompiler_renameProperty('_template', this.prototype)) ? + this.prototype._template : // Look in dom-module associated with this element's is - this._getTemplateFromDomModule() || + (getTemplateFromDomModule(/** @type {PolymerElementConstructor}*/ (this).is) || // Next look for superclass template (call the super impl this // way so that `this` points to the superclass) - Object.getPrototypeOf(/** @type {PolymerElementConstructor}*/ (this).prototype).constructor.template; + Object.getPrototypeOf(/** @type {PolymerElementConstructor}*/ (this).prototype).constructor.template); } return this._template; }