diff --git a/lib/legacy/class.js b/lib/legacy/class.js index d8ff532a3e..47793460c1 100644 --- a/lib/legacy/class.js +++ b/lib/legacy/class.js @@ -148,6 +148,24 @@ 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 4336256176..11f2925825 100644 --- a/lib/mixins/element-mixin.js +++ b/lib/mixins/element-mixin.js @@ -270,29 +270,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 - * @private - */ - 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 @@ -364,6 +341,30 @@ 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. * @@ -403,17 +404,14 @@ export const ElementMixin = dedupingMixin(base => { static get template() { if (!this.hasOwnProperty(JSCompiler_renameProperty('_template', this))) { this._template = - // Take any template set on the prototype, including null (for legacy - // support, setting in registered callback, etc.) - this.prototype._template !== undefined ? this.prototype._template : // Look in dom-module associated with this element's is - getTemplateFromDomModule(/** @type {PolymerElementConstructor}*/ (this).is) || + this._getTemplateFromDomModule() || // 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; } return this._template; - } + } /** * Path matching the url from which the element was imported. diff --git a/test/unit/behaviors.html b/test/unit/behaviors.html index 916d138440..ca1204576e 100644 --- a/test/unit/behaviors.html +++ b/test/unit/behaviors.html @@ -23,7 +23,7 @@ - + @@ -299,9 +299,9 @@ _template: html`
` }; -window.templateBehaviorFromRegister = { +window.templateBehaviorFromRegistered = { registered: function() { - this._template = html`
`; + this._template = html`
`; } }; @@ -312,6 +312,13 @@ } }); +Polymer({ + is: 'template-from-base', + behaviors: [ + window.templateBehavior1 + ] +}); + Polymer({ is: 'template-from-behavior', behaviors: [ @@ -330,8 +337,7 @@ Polymer({ is: 'template-from-behavior-registered', behaviors: [ - window.templateBehavior1, - window.templateBehaviorFromRegister + window.templateBehaviorFromRegistered ] }); @@ -366,6 +372,12 @@ + + + + `' + '
'; }, /trusted-element re-registered/); - const el = document.createElement('trusted-element'); - document.getElementById('target').appendChild(el); - assert.notOk(el.shadowRoot); + let el; + assertThrows(function() { + el = document.createElement('trusted-element'); + document.getElementById('target').appendChild(el); + }, /expecting dom-module or null template for trusted-element/); + assert.notOk(el && el.shadowRoot); assert.notOk(document.getElementById('injected')); }); @@ -229,9 +237,12 @@ ' `' + '
'; }, /trusted-element-legacy re-registered/); - const el = document.createElement('trusted-element-legacy'); - document.getElementById('target').appendChild(el); - assert.notOk(el.shadowRoot); + let el; + assertThrows(function() { + el = document.createElement('trusted-element-legacy'); + document.getElementById('target').appendChild(el); + }, /expecting dom-module or null template for trusted-element-legacy/); + assert.notOk(el && el.shadowRoot); assert.notOk(document.getElementById('injected')); });