diff --git a/lib/legacy/class.html b/lib/legacy/class.html
index 026fa98eef..0c8acab5b2 100644
--- a/lib/legacy/class.html
+++ b/lib/legacy/class.html
@@ -152,6 +152,24 @@
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 b2082f292a..032ad27708 100644
--- a/lib/mixins/element-mixin.html
+++ b/lib/mixins/element-mixin.html
@@ -275,27 +275,6 @@
}
}
- /**
- * 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;
- 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
@@ -368,6 +347,30 @@
}
}
+ /**
+ * 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.
*
@@ -408,11 +411,8 @@
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;
diff --git a/test/unit/behaviors.html b/test/unit/behaviors.html
index ffa011f562..3a9c915f50 100644
--- a/test/unit/behaviors.html
+++ b/test/unit/behaviors.html
@@ -22,7 +22,7 @@
-
+
should not be used
@@ -298,9 +298,9 @@
_template: Polymer.html``
};
- window.templateBehaviorFromRegister = {
+ window.templateBehaviorFromRegistered = {
registered: function() {
- this._template = Polymer.html``;
+ this._template = Polymer.html``;
}
};
@@ -311,6 +311,13 @@
}
});
+ Polymer({
+ is: 'template-from-base',
+ behaviors: [
+ window.templateBehavior1
+ ]
+ });
+
Polymer({
is: 'template-from-behavior',
behaviors: [
@@ -329,8 +336,7 @@
Polymer({
is: 'template-from-behavior-registered',
behaviors: [
- window.templateBehavior1,
- window.templateBehaviorFromRegister
+ window.templateBehaviorFromRegistered
]
});
@@ -367,6 +373,12 @@
+
+
+
+
+
+
@@ -588,9 +600,14 @@
assert.ok(el.shadowRoot.querySelector('#from-registered'));
});
+ test('template from base', function() {
+ var el = fixture('from-base');
+ assert.ok(el.shadowRoot.querySelector('#from-base'));
+ assert.notOk(el.shadowRoot.querySelector('#from-behavior1'));
+ });
+
test('template from behavior', function() {
var el = fixture('from-behavior');
- assert.notOk(el.shadowRoot.querySelector('#from-base'));
assert.ok(el.shadowRoot.querySelector('#from-behavior1'));
});
@@ -602,8 +619,7 @@
test('template from behavior registered callback', function() {
var el = fixture('from-behavior-registered');
- assert.notOk(el.shadowRoot.querySelector('#from-behavior1'));
- assert.ok(el.shadowRoot.querySelector('#behavior-from-register'));
+ assert.ok(el.shadowRoot.querySelector('#behavior-from-registered'));
});
});
diff --git a/test/unit/strict-template-policy.html b/test/unit/strict-template-policy.html
index 706273115c..982b3b97ff 100644
--- a/test/unit/strict-template-policy.html
+++ b/test/unit/strict-template-policy.html
@@ -128,11 +128,15 @@
const onerror = window.onerror;
const topOnerror = window.top.topOnerror;
- teardown(function() {
- // Restore mocha's onerror
+ function restoreOnError() {
window.onerror = onerror;
window.top.onerror = topOnerror;
window.uncaughtErrorFilter = window.top.uncaughtErrorFilter = null;
+ }
+
+ teardown(function() {
+ // Restore mocha's onerror
+ restoreOnError();
document.getElementById('target').textContent = '';
});
@@ -166,6 +170,7 @@
throw uncaughtError;
}
}, re);
+ restoreOnError();
}
test('dom-bind', function() {
@@ -213,9 +218,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/);
+ assert.notOk(el && el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
@@ -230,7 +238,7 @@
}, /trusted-element re-registered/);
const el = document.createElement('trusted-element');
document.getElementById('target').appendChild(el);
- assert.notOk(el.shadowRoot);
+ assert.notOk(el && el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
@@ -261,9 +269,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/);
+ assert.notOk(el && el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
@@ -276,9 +287,9 @@
' `' +
'';
}, /trusted-element-legacy re-registered/);
- const el = document.createElement('trusted-element-legacy');
+ const el = document.createElement('trusted-element');
document.getElementById('target').appendChild(el);
- assert.notOk(el.shadowRoot);
+ assert.notOk(el && el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
@@ -292,7 +303,7 @@
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);