mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
Runtime stamped dom-if
This commit is contained in:
@@ -16,6 +16,8 @@ import { microTask } from '../utils/async.js';
|
||||
import { root } from '../utils/path.js';
|
||||
import { wrap } from '../utils/wrap.js';
|
||||
import { hideElementsGlobally } from '../utils/hide-template-controls.js';
|
||||
import { fastDomIf, strictTemplatePolicy } from '../utils/settings.js';
|
||||
import { showHideChildren } from '../utils/templatize.js';
|
||||
|
||||
/**
|
||||
* The `<dom-if>` element will stamp a light-dom `<template>` child when
|
||||
@@ -85,7 +87,7 @@ export class DomIf extends PolymerElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.__renderDebouncer = null;
|
||||
this.__invalidProps = null;
|
||||
this.__syncProps = null;
|
||||
this.__instance = null;
|
||||
this._lastIf = false;
|
||||
this.__ctor = null;
|
||||
@@ -181,8 +183,11 @@ export class DomIf extends PolymerElement {
|
||||
let parentNode = wrap(this).parentNode;
|
||||
// Guard against element being detached while render was queued
|
||||
if (parentNode) {
|
||||
if (!this.__ctor) {
|
||||
let template = this._templateInfo ? this : /** @type {HTMLTemplateElement} */(wrap(this).querySelector('template'));
|
||||
if (!this.__template) {
|
||||
// When `removeNestedTemplates` is true, the "template" is the element
|
||||
// itself, which has been given a `_templateInfo` property
|
||||
let template = this._templateInfo ? this :
|
||||
/** @type {HTMLTemplateElement} */(wrap(this).querySelector('template'));
|
||||
if (!template) {
|
||||
// Wait until childList changes and template should be there by then
|
||||
let observer = new MutationObserver(() => {
|
||||
@@ -196,37 +201,63 @@ export class DomIf extends PolymerElement {
|
||||
observer.observe(this, {childList: true});
|
||||
return false;
|
||||
}
|
||||
this.__ctor = templatize(template, this, {
|
||||
// dom-if templatizer instances require `mutable: true`, as
|
||||
// `__syncHostProperties` relies on that behavior to sync objects
|
||||
mutableData: true,
|
||||
/**
|
||||
* @param {string} prop Property to forward
|
||||
* @param {*} value Value of property
|
||||
* @this {DomIf}
|
||||
*/
|
||||
forwardHostProp: function(prop, value) {
|
||||
if (this.__instance) {
|
||||
if (this.if) {
|
||||
this.__instance.forwardHostProp(prop, value);
|
||||
} else {
|
||||
// If we have an instance but are squelching host property
|
||||
// forwarding due to if being false, note the invalidated
|
||||
// properties so `__syncHostProperties` can sync them the next
|
||||
// time `if` becomes true
|
||||
this.__invalidProps = this.__invalidProps || Object.create(null);
|
||||
this.__invalidProps[root(prop)] = true;
|
||||
this.__template = template;
|
||||
if (!fastDomIf) {
|
||||
this.__ctor = templatize(template, this, {
|
||||
// dom-if templatizer instances require `mutable: true`, as
|
||||
// `__syncHostProperties` relies on that behavior to sync objects
|
||||
mutableData: true,
|
||||
/**
|
||||
* @param {string} prop Property to forward
|
||||
* @param {*} value Value of property
|
||||
* @this {DomIf}
|
||||
*/
|
||||
forwardHostProp: function(prop, value) {
|
||||
if (this.__instance) {
|
||||
if (this.if) {
|
||||
this.__instance.forwardHostProp(prop, value);
|
||||
} else {
|
||||
// If we have an instance but are squelching host property
|
||||
// forwarding due to if being false, note the invalidated
|
||||
// properties so `__syncHostProperties` can sync them the next
|
||||
// time `if` becomes true
|
||||
this.__syncProps = this.__syncProps || Object.create(null);
|
||||
this.__syncProps[root(prop)] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!this.__instance) {
|
||||
this.__instance = new this.__ctor();
|
||||
wrap(parentNode).insertBefore(this.__instance.root, this);
|
||||
if (fastDomIf) {
|
||||
const host = this.__dataHost || this;
|
||||
if (strictTemplatePolicy) {
|
||||
if (!this.__dataHost) {
|
||||
throw new Error('strictTemplatePolicy: template owner not trusted');
|
||||
}
|
||||
}
|
||||
// Pre-bind and link the template into the effects system
|
||||
const templateInfo = host._bindTemplate(this.__template, true);
|
||||
// Install runEffects hook that prevents running property effects
|
||||
// (and any nested template effects) when the `if` is false
|
||||
templateInfo.runEffects = runEffects => {
|
||||
if (this.if) {
|
||||
runEffects();
|
||||
} else {
|
||||
this.__syncProps = runEffects;
|
||||
}
|
||||
};
|
||||
// Stamp the template, and set its DocumentFragment to the "instance"
|
||||
this.__instance = host._stampTemplate(this.__template, templateInfo);
|
||||
wrap(parentNode).insertBefore(this.__instance, this);
|
||||
} else {
|
||||
this.__instance = new this.__ctor();
|
||||
wrap(parentNode).insertBefore(this.__instance.root, this);
|
||||
}
|
||||
} else {
|
||||
this.__syncHostProperties();
|
||||
let c$ = this.__instance.children;
|
||||
let c$ = fastDomIf ? this.__instance.templateInfo.childNodes :
|
||||
this.__instance.children;
|
||||
if (c$ && c$.length) {
|
||||
// Detect case where dom-if was re-attached in new position
|
||||
let lastChild = wrap(this).previousSibling;
|
||||
@@ -242,33 +273,41 @@ export class DomIf extends PolymerElement {
|
||||
}
|
||||
|
||||
__syncHostProperties() {
|
||||
let props = this.__invalidProps;
|
||||
let props = this.__syncProps;
|
||||
this.__syncProps = null;
|
||||
if (props) {
|
||||
for (let prop in props) {
|
||||
this.__instance._setPendingProperty(prop, this.__dataHost[prop]);
|
||||
if (fastDomIf) {
|
||||
props();
|
||||
} else {
|
||||
for (let prop in props) {
|
||||
this.__instance._setPendingProperty(prop, this.__dataHost[prop]);
|
||||
}
|
||||
this.__instance._flushProperties();
|
||||
}
|
||||
this.__invalidProps = null;
|
||||
this.__instance._flushProperties();
|
||||
}
|
||||
}
|
||||
|
||||
__teardownInstance() {
|
||||
if (this.__instance) {
|
||||
let c$ = this.__instance.children;
|
||||
if (c$ && c$.length) {
|
||||
// use first child parent, for case when dom-if may have been detached
|
||||
let parent = wrap(c$[0]).parentNode;
|
||||
// Instance children may be disconnected from parents when dom-if
|
||||
// detaches if a tree was innerHTML'ed
|
||||
if (parent) {
|
||||
parent = wrap(parent);
|
||||
for (let i=0, n; (i<c$.length) && (n=c$[i]); i++) {
|
||||
parent.removeChild(n);
|
||||
if (fastDomIf) {
|
||||
this._removeBoundDom(this.__instance);
|
||||
} else {
|
||||
let c$ = this.__instance.children;
|
||||
if (c$ && c$.length) {
|
||||
// use first child parent, for case when dom-if may have been detached
|
||||
let parent = wrap(c$[0]).parentNode;
|
||||
// Instance children may be disconnected from parents when dom-if
|
||||
// detaches if a tree was innerHTML'ed
|
||||
if (parent) {
|
||||
parent = wrap(parent);
|
||||
for (let i=0, n; (i<c$.length) && (n=c$[i]); i++) {
|
||||
parent.removeChild(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.__syncProps = null;
|
||||
this.__instance = null;
|
||||
this.__invalidProps = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +322,14 @@ export class DomIf extends PolymerElement {
|
||||
_showHideChildren() {
|
||||
let hidden = this.__hideTemplateChildren__ || !this.if;
|
||||
if (this.__instance) {
|
||||
this.__instance._showHideChildren(hidden);
|
||||
if (fastDomIf) {
|
||||
showHideChildren(hidden, this.__instance.templateInfo.childNodes);
|
||||
} else {
|
||||
this.__instance._showHideChildren(hidden);
|
||||
}
|
||||
if (!hidden) {
|
||||
this.__syncHostProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -339,7 +339,10 @@ export class DomRepeat extends domRepeatBase {
|
||||
// until ready, since won't have its template content handed back to
|
||||
// it until then
|
||||
if (!this.__ctor) {
|
||||
let template = this.template = this._templateInfo ? this : /** @type {HTMLTemplateElement} */(this.querySelector('template'));
|
||||
// When `removeNestedTemplates` is true, the "template" is the element
|
||||
// itself, which has been given a `_templateInfo` property
|
||||
let template = this.template = this._templateInfo ? this :
|
||||
/** @type {HTMLTemplateElement} */(this.querySelector('template'));
|
||||
if (!template) {
|
||||
// // Wait until childList changes and template should be there by then
|
||||
let observer = new MutationObserver(() => {
|
||||
|
||||
@@ -19,9 +19,7 @@ import { camelToDashCase, dashToCamelCase } from '../utils/case-map.js';
|
||||
import { PropertyAccessors } from './property-accessors.js';
|
||||
/* for annotated effects */
|
||||
import { TemplateStamp } from './template-stamp.js';
|
||||
import { sanitizeDOMValue, legacyUndefined, legacyNoBatch, legacyNotifyOrder, orderedComputed } from '../utils/settings.js';
|
||||
|
||||
const btp = window.location.search.match(/btp/);
|
||||
import { sanitizeDOMValue, legacyUndefined, legacyNoBatch, legacyNotifyOrder, orderedComputed, removeNestedTemplates, fastDomIf } from '../utils/settings.js';
|
||||
|
||||
// Monotonically increasing unique ID used for de-duping effects triggered
|
||||
// from multiple properties in the same turn
|
||||
@@ -1974,11 +1972,23 @@ export const PropertyEffects = dedupingMixin(superClass => {
|
||||
if (this[TYPES.PROPAGATE]) {
|
||||
runEffects(this, this[TYPES.PROPAGATE], changedProps, oldProps, hasPaths);
|
||||
}
|
||||
let templateInfo = this.__templateInfo;
|
||||
while (templateInfo) {
|
||||
if (this.__templateInfo) {
|
||||
this._runEffectsForTemplate(this.__templateInfo, changedProps, oldProps, hasPaths);
|
||||
}
|
||||
}
|
||||
|
||||
_runEffectsForTemplate(templateInfo, changedProps, oldProps, hasPaths) {
|
||||
const baseRunEffects = () => {
|
||||
runEffects(this, templateInfo.propertyEffects, changedProps, oldProps,
|
||||
hasPaths, templateInfo.nodeList);
|
||||
templateInfo = templateInfo.nextTemplateInfo;
|
||||
for (let info=templateInfo.firstChild; info; info=info.nextSibling) {
|
||||
this._runEffectsForTemplate(info, changedProps, oldProps, hasPaths);
|
||||
}
|
||||
};
|
||||
if (templateInfo.runEffects) {
|
||||
templateInfo.runEffects(baseRunEffects);
|
||||
} else {
|
||||
baseRunEffects();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2684,14 +2694,23 @@ export const PropertyEffects = dedupingMixin(superClass => {
|
||||
// and link into list of templates if necessary
|
||||
templateInfo = /** @type {!TemplateInfo} */(Object.create(templateInfo));
|
||||
templateInfo.wasPreBound = wasPreBound;
|
||||
if (!wasPreBound && this.__templateInfo) {
|
||||
let last = this.__templateInfoLast || this.__templateInfo;
|
||||
this.__templateInfoLast = last.nextTemplateInfo = templateInfo;
|
||||
templateInfo.previousTemplateInfo = last;
|
||||
return templateInfo;
|
||||
if (wasPreBound || !this.__templateInfo) {
|
||||
this.__templateInfo = templateInfo;
|
||||
} else {
|
||||
const parent = templateInfo.parent || this.__templateInfo;
|
||||
const previous = parent.lastChild;
|
||||
parent.lastChild = templateInfo;
|
||||
templateInfo.previousSibling = previous;
|
||||
if (previous) {
|
||||
previous.nextSibling = templateInfo;
|
||||
} else {
|
||||
parent.firstChild = templateInfo;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.__templateInfo = templateInfo;
|
||||
}
|
||||
return this.__templateInfo = templateInfo;
|
||||
return templateInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2736,13 +2755,13 @@ export const PropertyEffects = dedupingMixin(superClass => {
|
||||
* @override
|
||||
* @protected
|
||||
*/
|
||||
_stampTemplate(template) {
|
||||
_stampTemplate(template, templateInfo) {
|
||||
templateInfo = templateInfo || /** @type {!TemplateInfo} */(this._bindTemplate(template, true));
|
||||
// Ensures that created dom is `_enqueueClient`'d to this element so
|
||||
// that it can be flushed on next call to `_flushProperties`
|
||||
hostStack.beginHosting(this);
|
||||
let dom = super._stampTemplate(template);
|
||||
let dom = super._stampTemplate(template, templateInfo);
|
||||
hostStack.endHosting(this);
|
||||
let templateInfo = /** @type {!TemplateInfo} */(this._bindTemplate(template, true));
|
||||
// Add template-instance-specific data to instanced templateInfo
|
||||
templateInfo.nodeList = dom.nodeList;
|
||||
// Capture child nodes to allow unstamping of non-prototypical templates
|
||||
@@ -2757,8 +2776,7 @@ export const PropertyEffects = dedupingMixin(superClass => {
|
||||
setupBindings(this, templateInfo);
|
||||
// Flush properties into template nodes if already booted
|
||||
if (this.__dataReady) {
|
||||
runEffects(this, templateInfo.propertyEffects, this.__data, null,
|
||||
false, templateInfo.nodeList);
|
||||
this._runEffectsForTemplate(templateInfo, this.__data, null, false);
|
||||
}
|
||||
return dom;
|
||||
}
|
||||
@@ -2776,23 +2794,22 @@ export const PropertyEffects = dedupingMixin(superClass => {
|
||||
_removeBoundDom(dom) {
|
||||
// Unlink template info
|
||||
let templateInfo = dom.templateInfo;
|
||||
if (templateInfo.previousTemplateInfo) {
|
||||
templateInfo.previousTemplateInfo.nextTemplateInfo =
|
||||
templateInfo.nextTemplateInfo;
|
||||
const {previousSibling, nextSibling, parent} = templateInfo;
|
||||
if (previousSibling) {
|
||||
previousSibling.nextSibling = nextSibling;
|
||||
} else if (parent) {
|
||||
parent.firstChild = nextSibling;
|
||||
}
|
||||
if (templateInfo.nextTemplateInfo) {
|
||||
templateInfo.nextTemplateInfo.previousTemplateInfo =
|
||||
templateInfo.previousTemplateInfo;
|
||||
if (nextSibling) {
|
||||
nextSibling.previousSibling = previousSibling;
|
||||
} else if (parent) {
|
||||
parent.lastChild = previousSibling;
|
||||
}
|
||||
if (this.__templateInfoLast == templateInfo) {
|
||||
this.__templateInfoLast = templateInfo.previousTemplateInfo;
|
||||
}
|
||||
templateInfo.previousTemplateInfo = templateInfo.nextTemplateInfo = null;
|
||||
// Remove stamped nodes
|
||||
let nodes = templateInfo.childNodes;
|
||||
for (let i=0; i<nodes.length; i++) {
|
||||
let node = nodes[i];
|
||||
node.parentNode.removeChild(node);
|
||||
wrap(wrap(node).parentNode).removeChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2923,18 +2940,33 @@ export const PropertyEffects = dedupingMixin(superClass => {
|
||||
this, node, templateInfo, nodeInfo);
|
||||
const parent = node.parentNode;
|
||||
const nestedTemplateInfo = nodeInfo.templateInfo;
|
||||
if (btp && parent.localName.match(/(dom-repeat|dom-if)/)) {
|
||||
const isDomIf = parent.localName === 'dom-if';
|
||||
const isDomRepeat = parent.localName === 'dom-repeat';
|
||||
// Remove nested template and redirect its host bindings & templateInfo
|
||||
// onto the parent (dom-if/repeat element)'s nodeInfo
|
||||
if (removeNestedTemplates && (isDomIf || isDomRepeat)) {
|
||||
parent.removeChild(node);
|
||||
nodeInfo.parentInfo.templateInfo = nestedTemplateInfo;
|
||||
nodeInfo = nodeInfo.parentInfo;
|
||||
nodeInfo.noted = true;
|
||||
noted = false;
|
||||
}
|
||||
// Merge host props into outer template and add bindings
|
||||
let hostProps = nestedTemplateInfo.hostProps;
|
||||
let mode = '{';
|
||||
for (let source in hostProps) {
|
||||
let parts = [{ mode, source, dependencies: [source], hostProp: true }];
|
||||
addBinding(this, templateInfo, nodeInfo, 'property', '_host_' + source, parts);
|
||||
if (fastDomIf && isDomIf) {
|
||||
if (hostProps) {
|
||||
if (!removeNestedTemplates) {
|
||||
nodeInfo.parentInfo.noted = true;
|
||||
}
|
||||
templateInfo.hostProps =
|
||||
Object.assign(nestedTemplateInfo.hostProps || {}, hostProps);
|
||||
}
|
||||
} else {
|
||||
let mode = '{';
|
||||
for (let source in hostProps) {
|
||||
let parts = [{ mode, source, dependencies: [source], hostProp: true }];
|
||||
addBinding(this, templateInfo, nodeInfo, 'property', '_host_' + source, parts);
|
||||
}
|
||||
}
|
||||
return noted;
|
||||
}
|
||||
|
||||
@@ -72,9 +72,11 @@ function applyEventListener(inst, node, nodeInfo) {
|
||||
}
|
||||
|
||||
// push configuration references at configure time
|
||||
function applyTemplateContent(inst, node, nodeInfo) {
|
||||
function applyTemplateContent(inst, node, nodeInfo, parentTemplateInfo) {
|
||||
if (nodeInfo.templateInfo) {
|
||||
node._templateInfo = nodeInfo.templateInfo;
|
||||
// Give the node an instance of this templateInfo and set its parent
|
||||
node._templateInfo = Object.create(nodeInfo.templateInfo);
|
||||
node._templateInfo.parent = parentTemplateInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,7 +257,7 @@ export const TemplateStamp = dedupingMixin(
|
||||
if (element.hasAttributes && element.hasAttributes()) {
|
||||
noted = this._parseTemplateNodeAttributes(element, templateInfo, nodeInfo) || noted;
|
||||
}
|
||||
return noted;
|
||||
return noted || nodeInfo.noted;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -437,13 +439,13 @@ export const TemplateStamp = dedupingMixin(
|
||||
* @return {!StampedTemplate} Cloned template content
|
||||
* @override
|
||||
*/
|
||||
_stampTemplate(template) {
|
||||
_stampTemplate(template, templateInfo) {
|
||||
// Polyfill support: bootstrap the template if it has not already been
|
||||
if (template && !template.content &&
|
||||
window.HTMLTemplateElement && HTMLTemplateElement.decorate) {
|
||||
HTMLTemplateElement.decorate(template);
|
||||
}
|
||||
let templateInfo = this.constructor._parseTemplate(template);
|
||||
templateInfo = templateInfo || this.constructor._parseTemplate(template);
|
||||
let nodeInfo = templateInfo.nodeInfoList;
|
||||
let content = templateInfo.content || template.content;
|
||||
let dom = /** @type {DocumentFragment} */ (document.importNode(content, true));
|
||||
@@ -454,7 +456,7 @@ export const TemplateStamp = dedupingMixin(
|
||||
for (let i=0, l=nodeInfo.length, info; (i<l) && (info=nodeInfo[i]); i++) {
|
||||
let node = nodes[i] = findTemplateNode(dom, info);
|
||||
applyIdToMap(this, dom.$, node, info);
|
||||
applyTemplateContent(this, node, info);
|
||||
applyTemplateContent(this, node, info, templateInfo);
|
||||
applyEventListener(this, node, info);
|
||||
}
|
||||
dom = /** @type {!StampedTemplate} */(dom); // eslint-disable-line no-self-assign
|
||||
|
||||
@@ -263,3 +263,43 @@ export let cancelSyntheticClickEvents = true;
|
||||
export const setCancelSyntheticClickEvents = function(useCancelSyntheticClickEvents) {
|
||||
cancelSyntheticClickEvents = useCancelSyntheticClickEvents;
|
||||
};
|
||||
|
||||
/**
|
||||
* Setting to remove nested templates inside `dom-if` and `dom-repeat` as
|
||||
* part of element template parsing. This is a performance optimization that
|
||||
* eliminates most of the tax of needing two elements due to the loss of
|
||||
* type-extended templates as a result of the V1 specification changes.
|
||||
*/
|
||||
export let removeNestedTemplates = true;
|
||||
|
||||
/**
|
||||
* Sets `removeNestedTemplates` globally, to eliminate nested templates
|
||||
* inside `dom-if` and `dom-repeat` as part of template parsing.
|
||||
*
|
||||
* @param {boolean} useCemoveNestedTemplates enable or disable removing nested
|
||||
* templates during parsing
|
||||
* @return {void}
|
||||
*/
|
||||
export const setRemoveNestedTemplates = function(useCemoveNestedTemplates) {
|
||||
removeNestedTemplates = useCemoveNestedTemplates;
|
||||
};
|
||||
|
||||
/**
|
||||
* Setting to place `dom-if` elements in a performance-optimized mode that takes
|
||||
* advantage of lighter-weight host runtime template stamping to eliminate the
|
||||
* need for an intermediate Templatizer `TemplateInstance` to mange the nodes
|
||||
* stamped by `dom-if`. Under this setting, any Templatizer-provided API's
|
||||
* such as `modelForElement` will not be available for nodes stamped by
|
||||
* `dom-if`.
|
||||
*/
|
||||
export let fastDomIf = true;
|
||||
|
||||
/**
|
||||
* Sets `fastDomIf` globally, to put `dom-if` in a performance-optimized mode.
|
||||
*
|
||||
* @param {boolean} useFastDomIf enable or disable `dom-if` fast-mode
|
||||
* @return {void}
|
||||
*/
|
||||
export const setFastDomIf = function(useFastDomIf) {
|
||||
fastDomIf = useFastDomIf;
|
||||
};
|
||||
|
||||
@@ -103,6 +103,48 @@ function upgradeTemplate(template, constructor) {
|
||||
*/
|
||||
const templateInstanceBase = PropertyEffects(class {});
|
||||
|
||||
export function showHideChildren(hide, children) {
|
||||
for (let i=0; i<children.length; i++) {
|
||||
let n = children[i];
|
||||
// Ignore non-changes
|
||||
if (Boolean(hide) != Boolean(n.__hideTemplateChildren__)) {
|
||||
// clear and restore text
|
||||
if (n.nodeType === Node.TEXT_NODE) {
|
||||
if (hide) {
|
||||
n.__polymerTextContent__ = n.textContent;
|
||||
n.textContent = '';
|
||||
} else {
|
||||
n.textContent = n.__polymerTextContent__;
|
||||
}
|
||||
// remove and replace slot
|
||||
} else if (n.localName === 'slot') {
|
||||
if (hide) {
|
||||
n.__polymerReplaced__ = document.createComment('hidden-slot');
|
||||
wrap(wrap(n).parentNode).replaceChild(n.__polymerReplaced__, n);
|
||||
} else {
|
||||
const replace = n.__polymerReplaced__;
|
||||
if (replace) {
|
||||
wrap(wrap(replace).parentNode).replaceChild(n, replace);
|
||||
}
|
||||
}
|
||||
}
|
||||
// hide and show nodes
|
||||
else if (n.style) {
|
||||
if (hide) {
|
||||
n.__polymerDisplay__ = n.style.display;
|
||||
n.style.display = 'none';
|
||||
} else {
|
||||
n.style.display = n.__polymerDisplay__;
|
||||
}
|
||||
}
|
||||
}
|
||||
n.__hideTemplateChildren__ = hide;
|
||||
if (n._showHideChildren) {
|
||||
n._showHideChildren(hide);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @polymer
|
||||
* @customElement
|
||||
@@ -206,45 +248,7 @@ class TemplateInstanceBase extends templateInstanceBase {
|
||||
* @protected
|
||||
*/
|
||||
_showHideChildren(hide) {
|
||||
let c = this.children;
|
||||
for (let i=0; i<c.length; i++) {
|
||||
let n = c[i];
|
||||
// Ignore non-changes
|
||||
if (Boolean(hide) != Boolean(n.__hideTemplateChildren__)) {
|
||||
if (n.nodeType === Node.TEXT_NODE) {
|
||||
if (hide) {
|
||||
n.__polymerTextContent__ = n.textContent;
|
||||
n.textContent = '';
|
||||
} else {
|
||||
n.textContent = n.__polymerTextContent__;
|
||||
}
|
||||
// remove and replace slot
|
||||
} else if (n.localName === 'slot') {
|
||||
if (hide) {
|
||||
n.__polymerReplaced__ = document.createComment('hidden-slot');
|
||||
wrap(wrap(n).parentNode).replaceChild(n.__polymerReplaced__, n);
|
||||
} else {
|
||||
const replace = n.__polymerReplaced__;
|
||||
if (replace) {
|
||||
wrap(wrap(replace).parentNode).replaceChild(n, replace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (n.style) {
|
||||
if (hide) {
|
||||
n.__polymerDisplay__ = n.style.display;
|
||||
n.style.display = 'none';
|
||||
} else {
|
||||
n.style.display = n.__polymerDisplay__;
|
||||
}
|
||||
}
|
||||
}
|
||||
n.__hideTemplateChildren__ = hide;
|
||||
if (n._showHideChildren) {
|
||||
n._showHideChildren(hide);
|
||||
}
|
||||
}
|
||||
showHideChildren(hide, this.children);
|
||||
}
|
||||
/**
|
||||
* Overrides default property-effects implementation to intercept
|
||||
@@ -365,10 +369,14 @@ function createTemplatizerClass(template, templateInfo, options) {
|
||||
*
|
||||
* @suppress {missingProperties} class.prototype is not defined for some reason
|
||||
*/
|
||||
function addPropagateEffects(template, templateInfo, options, methodHost) {
|
||||
function addPropagateEffects(target, templateInfo, options, methodHost) {
|
||||
let userForwardHostProp = options.forwardHostProp;
|
||||
if (userForwardHostProp && templateInfo.hasHostProps) {
|
||||
const isTemplate = template.localName == 'template';
|
||||
// Under the `removeNestedTemplates` optimization, a custom element like
|
||||
// `dom-if` or `dom-repeat` can itself be treated as the "template"; this
|
||||
// flag is used to switch between upgrading a `<template>` to be a property
|
||||
// effects client vs. adding the effects directly to the custom element
|
||||
const isTemplate = target.localName == 'template';
|
||||
// Provide data API and property effects on memoized template class
|
||||
let klass = templateInfo.templatizeTemplateClass;
|
||||
if (!klass) {
|
||||
@@ -382,7 +390,9 @@ function addPropagateEffects(template, templateInfo, options, methodHost) {
|
||||
klass = templateInfo.templatizeTemplateClass =
|
||||
class TemplatizedTemplate extends templatizedBase {};
|
||||
} else {
|
||||
klass = class TemplatizedTemplateExtension extends template.constructor {};
|
||||
// Create a cached subclass of the base custom element class onto which
|
||||
// to put the template-specific propagate effects
|
||||
klass = class TemplatizedTemplateExtension extends target.constructor {};
|
||||
}
|
||||
// Add template - >instances effects
|
||||
// and host <- template effects
|
||||
@@ -398,21 +408,31 @@ function addPropagateEffects(template, templateInfo, options, methodHost) {
|
||||
}
|
||||
}
|
||||
if (isTemplate) {
|
||||
upgradeTemplate(template, klass);
|
||||
upgradeTemplate(target, klass);
|
||||
// Clear any pending data for performance
|
||||
template.__dataTemp = {};
|
||||
template.__dataPending = null;
|
||||
template.__dataOld = null;
|
||||
template._enableProperties();
|
||||
target.__dataTemp = {};
|
||||
target.__dataPending = null;
|
||||
target.__dataOld = null;
|
||||
target._enableProperties();
|
||||
} else {
|
||||
Object.setPrototypeOf(template, klass.prototype);
|
||||
// Swizzle the cached subclass prototype onto the custom element
|
||||
Object.setPrototypeOf(target, klass.prototype);
|
||||
const hostProps = templateInfo.hostProps;
|
||||
for (let prop in hostProps) {
|
||||
prop = '_host_' + prop;
|
||||
if (prop in target) {
|
||||
const val = target[prop];
|
||||
delete target[prop];
|
||||
target.__data[prop] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mix any pre-bound data into __data; no need to flush this to
|
||||
// instances since they pull from the template at instance-time
|
||||
if (template.__dataProto) {
|
||||
if (target.__dataProto) {
|
||||
// Note, generally `__dataProto` could be chained, but it's guaranteed
|
||||
// to not be since this is a vanilla template we just added effects to
|
||||
Object.assign(template.__data, template.__dataProto);
|
||||
Object.assign(target.__data, target.__dataProto);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -632,7 +652,7 @@ export function modelForElement(template, node) {
|
||||
// An element with a __templatizeInstance marks the top boundary
|
||||
// of a scope; walk up until we find one, and then ensure that
|
||||
// its __dataHost matches `this`, meaning this dom-repeat stamped it
|
||||
if ((model = node.__templatizeInstance)) {
|
||||
if ((model = node.__dataHost ? node : node.__templatizeInstance)) {
|
||||
// Found an element stamped by another template; keep walking up
|
||||
// from its __dataHost
|
||||
if (model.__dataHost != template) {
|
||||
|
||||
@@ -71,7 +71,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
'unit/path.html',
|
||||
'unit/templatize.html',
|
||||
'unit/dom-repeat.html',
|
||||
'unit/dom-repeat.html?removeNestedTemplates=true',
|
||||
'unit/dom-if.html',
|
||||
'unit/dom-if.html?removeNestedTemplates=true',
|
||||
'unit/dom-if.html?fastDomIf=true',
|
||||
'unit/dom-if.html?removeNestedTemplates=true&fastDomIf=true',
|
||||
'unit/dom-bind.html',
|
||||
'unit/array-selector.html',
|
||||
'unit/polymer-dom.html',
|
||||
|
||||
@@ -14,6 +14,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
<script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
|
||||
<script src="wct-browser-config.js"></script>
|
||||
<script src="../../node_modules/wct-browser-legacy/browser.js"></script>
|
||||
<script type="module">
|
||||
import { setRemoveNestedTemplates, setFastDomIf } from '../../lib/utils/settings.js';
|
||||
setRemoveNestedTemplates(location.search.match(/removeNestedTemplates/));
|
||||
setFastDomIf(location.search.match(/fastDomIf/));
|
||||
</script>
|
||||
<script type="module" src="../../polymer-legacy.js"></script>
|
||||
<script type="module" src="./dom-if-elements.js"></script>
|
||||
</head>
|
||||
|
||||
@@ -464,9 +464,9 @@ Polymer({
|
||||
Polymer({
|
||||
_template: html`
|
||||
<template is="dom-repeat" items="{{items}}" id="outer">
|
||||
<template is="dom-if" if="">
|
||||
<template is="dom-if" if="" name="outerIf">
|
||||
<template is="dom-repeat" items="{{item.items}}" id="inner">
|
||||
<template is="dom-if" if="">
|
||||
<template is="dom-if" if="" name="innerIf">
|
||||
<button on-click="handleClick">{{item.prop}}</button>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -14,6 +14,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
<script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
|
||||
<script src="wct-browser-config.js"></script>
|
||||
<script src="../../node_modules/wct-browser-legacy/browser.js"></script>
|
||||
<script type="module">
|
||||
import { setRemoveNestedTemplates } from '../../lib/utils/settings.js';
|
||||
setRemoveNestedTemplates(location.search.match(/removeNestedTemplates/));
|
||||
</script>
|
||||
<script type="module" src="../../polymer-legacy.js"></script>
|
||||
<script type="module" src="./dom-repeat-elements.js"></script>
|
||||
<style>
|
||||
@@ -108,7 +112,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
</dom-repeat>
|
||||
</div>
|
||||
|
||||
|
||||
<test-fixture id="primitiveLarge">
|
||||
<template>
|
||||
<x-primitive-large></x-primitive-large>
|
||||
|
||||
Reference in New Issue
Block a user