Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow undefined in legacy _template field to fall-through to normal lookup path #5622

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions lib/mixins/element-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -487,11 +487,17 @@ export const ElementMixin = dedupingMixin(base => {
// 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))) {
const protoTemplate = this.prototype.hasOwnProperty(
JSCompiler_renameProperty('_template', this.prototype)) ?
this.prototype._template : undefined;
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 :
// callback or info object), prefer that first. Note that `null` is
// used as a sentinel to indicate "no template" and can be used to
// override a super template, whereas `undefined` is used as a
// sentinel to mean "fall-back to default template lookup" via
// dom-module and/or super.template.
protoTemplate !== undefined ? protoTemplate :
// Look in dom-module associated with this element's is
((this.hasOwnProperty(JSCompiler_renameProperty('is', this)) &&
(getTemplateFromDomModule(/** @type {PolymerElementConstructor}*/ (this).is))) ||
Expand Down
86 changes: 86 additions & 0 deletions test/unit/inheritance.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@
<script type="module" src="../../polymer-legacy.js"></script>
<body>

<dom-module id="uses-underscore-template">
<template><div>error</div></template>
</dom-module>

<dom-module id="uses-dom-module">
<template><div>from-dom-module</div></template>
</dom-module>

<dom-module id="no-template">
<template><div>error</div></template>
</dom-module>

<dom-module id="base-el">
<template>
<style>
Expand Down Expand Up @@ -147,6 +159,9 @@
</test-fixture>

<script type="module">
import { html } from '../../lib/utils/html-tag.js';
import { Polymer } from '../../polymer-legacy.js';

suite('ChildElement extends BaseElement', function() {
test('child has base properties', function() {
var f = fixture('basic');
Expand Down Expand Up @@ -266,6 +281,77 @@
assert.equal(el.shadowRoot, null);
});
});

suite('Legacy _template property: null/undefined', function() {

let el;
teardown(function() {
if (el) {
document.body.removeChild(el);
}
});

test('_template: returning template works', function() {
Polymer({
is: 'uses-underscore-template',
_template: html`<div>from-underscore-template</div>`
});
const el = document.createElement('uses-underscore-template');
document.body.appendChild(el);
assert.equal(el.shadowRoot.firstChild.textContent, 'from-underscore-template');
});

test('_template: undefined falls back to dom-module', function() {
Polymer({
is: 'uses-dom-module',
_template: undefined
});
const el = document.createElement('uses-dom-module');
document.body.appendChild(el);
assert.equal(el.shadowRoot.firstChild.textContent, 'from-dom-module');
});

test('_template: null overrides dom-module', function() {
Polymer({
is: 'no-template',
_template: null
});
const el = document.createElement('no-template');
document.body.appendChild(el);
assert.notOk(el.shadowRoot);
});

test('_template: returning template works in sub-class', function() {
customElements.define('sub-uses-underscore-template', class extends customElements.get('uses-underscore-template') {
get _template() { return this._$tmpl || html`<div>sub-from-underscore-template</div>`; }
set _template(v) { this._$tmpl = v; }
});
const el = document.createElement('sub-uses-underscore-template');
document.body.appendChild(el);
assert.equal(el.shadowRoot.firstChild.textContent, 'sub-from-underscore-template');
});

test('_template: undefined falls back to dom-module in sub-class', function() {
customElements.define('sub-uses-dom-module', class extends customElements.get('uses-dom-module') {
get _template() { return this._$tmpl || undefined; }
set _template(v) { this._$tmpl = v; }
});
const el = document.createElement('sub-uses-dom-module');
document.body.appendChild(el);
assert.equal(el.shadowRoot.firstChild.textContent, 'from-dom-module');
});

test('_template: null overrides dom-module in sub-class', function() {
customElements.define('sub-no-template', class extends customElements.get('no-template') {
get _template() { return this._$tmpl || null; }
set _template(v) { this._$tmpl = v; }
});
const el = document.createElement('sub-no-template');
document.body.appendChild(el);
assert.notOk(el.shadowRoot);
});

});
</script>
</body>
</html>