diff --git a/lib/legacy/class.html b/lib/legacy/class.html
index ab052142..cf22f43b 100644
--- a/lib/legacy/class.html
+++ b/lib/legacy/class.html
@@ -153,24 +153,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
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.html b/lib/mixins/element-mixin.html
index a1f538d4..b3fd9f99 100644
--- a/lib/mixins/element-mixin.html
+++ b/lib/mixins/element-mixin.html
@@ -130,7 +130,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
/**
- * Returns a memoized version of the the `observers` array.
+ * Returns a memoized version of the `observers` array.
* @param {PolymerElementConstructor} constructor Element class
* @return {Array} Array containing own observers for the given class
* @protected
@@ -154,7 +154,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
* alter these settings. However, additional `observers` may be added
* by subclasses.
*
- * The info object should may contain property metadata as follows:
+ * The info object should contain property metadata as follows:
*
* * `type`: {function} type to which an attribute matching the property
* is deserialized. Note the property is camel-cased from a dash-cased
@@ -166,7 +166,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
* property 'foo',
*
* * `computed`: {string} creates a computed property. A computed property
- * also automatically is set to `readOnly: true`. The value is calculated
+ * is also automatically set to `readOnly: true`. The value is calculated
* by running a method and arguments parsed from the given string. For
* example 'compute(foo)' will compute a given property when the
* 'foo' property changes by executing the 'compute' method. This method
@@ -277,6 +277,27 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
/**
+ * 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;
+ if (is && Polymer.DomModule) {
+ template = Polymer.DomModule.import(is, 'template');
+ // Under strictTemplatePolicy, require any element with an `is`
+ // specified to have a dom-module
+ if (Polymer.strictTemplatePolicy && !template) {
+ throw new Error(`strictTemplatePolicy: expecting dom-module or null template for ${is}`);
+ }
+ }
+ return template;
+ }
+
+ /**
* @polymer
* @mixinClass
* @unrestricted
@@ -348,30 +369,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
}
- /**
- * 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 && Polymer.DomModule) {
- template = Polymer.DomModule.import(is, 'template');
- // Under strictTemplatePolicy, require any element with an `is`
- // specified to have a dom-module
- if (Polymer.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.
*
@@ -410,17 +407,43 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
* @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;
}
+ /**
+ * Set the template.
+ *
+ * @param {!HTMLTemplateElement|string} value Template to set.
+ */
+ static set template(value) {
+ this._template = value;
+ }
+
/**
* Path matching the url from which the element was imported.
*
@@ -428,7 +451,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
* The `importPath` property is also set on element instances and can be
* used to create bindings relative to the import path.
*
- * For elements defined in ES modules, users should implement
+ * For elements defined in ES modules, users should implement
* `static get importMeta() { return import.meta; }`, and the default
* implementation of `importPath` will return `import.meta.url`'s path.
* For elements defined in HTML imports, this getter will return the path
diff --git a/test/unit/strict-template-policy.html b/test/unit/strict-template-policy.html
index 4807c176..8596bda4 100644
--- a/test/unit/strict-template-policy.html
+++ b/test/unit/strict-template-policy.html
@@ -222,7 +222,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
assertThrows(function() {
el = document.createElement('trusted-element');
document.getElementById('target').appendChild(el);
- }, /expecting dom-module or null template/);
+ }, /expecting dom-module or null template for trusted-element/);
assert.notOk(el && el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
@@ -238,7 +238,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, /trusted-element re-registered/);
const el = document.createElement('trusted-element');
document.getElementById('target').appendChild(el);
- assert.notOk(el && el.shadowRoot);
+ assert.notOk(el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
@@ -273,7 +273,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
assertThrows(function() {
el = document.createElement('trusted-element-legacy');
document.getElementById('target').appendChild(el);
- }, /expecting dom-module or null template/);
+ }, /expecting dom-module or null template for trusted-element-legacy/);
assert.notOk(el && el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
@@ -287,9 +287,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
' `' +
'';
}, /trusted-element-legacy re-registered/);
- const el = document.createElement('trusted-element');
+ const el = document.createElement('trusted-element-legacy');
document.getElementById('target').appendChild(el);
- assert.notOk(el && el.shadowRoot);
+ assert.notOk(el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
@@ -303,7 +303,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
Polymer({
is: 'has-no-template-legacy',
_template: null
- }, /expecting dom-module or null template/);
+ });
let el = document.createElement('has-no-template-legacy');
document.getElementById('target').appendChild(el);
assert.notOk(el.shadowRoot);
@@ -331,7 +331,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, /expecting dom-module or null template/);
});
- test('template helpers in trusted templates work', function() {
+ test('template helpers in trusted templates work', function() {
var el = document.createElement('trusted-templates');
document.getElementById('target').appendChild(el);
Polymer.flush();
@@ -352,6 +352,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
});
});
+