Socket
Socket
Sign inDemoInstall

@polymer/polymer

Package Overview
Dependencies
1
Maintainers
10
Versions
49
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.3.1 to 3.4.0

181

externs/closure-types.js

@@ -33,3 +33,2 @@ /**

* @param {string} property Name of the property
* @return {void}
*/

@@ -83,2 +82,7 @@ Polymer_PropertiesChanged.prototype._addPropertyToAttributeMap = function(property){};

/**
* @param {string} property Name of the property
* @return {boolean}
*/
Polymer_PropertiesChanged.prototype._isPropertyPending = function(property){};
/**
* @override

@@ -214,2 +218,8 @@ * @return {void}

* @override
* @param {string} prop Property name
* @return {boolean}
*/
Polymer_PropertyAccessors.prototype._isPropertyPending = function(prop){};
/**
* @override
* @param {*} value Property value to serialize.

@@ -247,8 +257,2 @@ * @return {(string | undefined)}

/**
* @override
* @param {string} prop Property name
* @return {boolean}
*/
Polymer_PropertyAccessors.prototype._isPropertyPending = function(prop){};
/**
* @param {string} property Property to convert

@@ -269,5 +273,8 @@ * @return {string}

* @param {!HTMLTemplateElement} template Template to stamp
* @param {TemplateInfo=} templateInfo Optional template info associated
with the template to be stamped; if omitted the template will be
automatically parsed.
* @return {!StampedTemplate}
*/
Polymer_TemplateStamp.prototype._stampTemplate = function(template){};
Polymer_TemplateStamp.prototype._stampTemplate = function(template, templateInfo){};
/**

@@ -403,2 +410,5 @@ * @override

/** @type {Object} */
Polymer_PropertyEffects.prototype.__computeInfo;
/** @type {Object} */
Polymer_PropertyEffects.prototype.__reflectEffects;

@@ -421,3 +431,6 @@

/** @type {!Object.<string, string>} */
/** @type {boolean} */
Polymer_PropertyEffects.prototype._overrideLegacyUndefined;
/** @type {undefined} */
Polymer_PropertyEffects.prototype.PROPERTY_EFFECT_TYPES;

@@ -428,5 +441,8 @@

* @param {!HTMLTemplateElement} template Template to stamp
* @param {TemplateInfo=} templateInfo Optional bound template info associated
with the template to be stamped; if omitted the template will be
automatically bound.
* @return {!StampedTemplate}
*/
Polymer_PropertyEffects.prototype._stampTemplate = function(template){};
Polymer_PropertyEffects.prototype._stampTemplate = function(template, templateInfo){};
/**

@@ -471,7 +487,2 @@ * @override

* @override
* @return {void}
*/
Polymer_PropertyEffects.prototype._flushProperties = function(){};
/**
* @override
* @param {!Object} currentProps Bag of all current accessor values

@@ -492,2 +503,6 @@ * @param {?Object} changedProps Bag of properties changed since the last

/**
* @return {void}
*/
Polymer_PropertyEffects.prototype._registerHost = function(){};
/**
* @override

@@ -596,2 +611,10 @@ * @param {string} property Property that should trigger the effect

/**
* @param {*} templateInfo
* @param {*} changedProps
* @param {*} oldProps
* @param {*} hasPaths
* @return {void}
*/
Polymer_PropertyEffects.prototype._runEffectsForTemplate = function(templateInfo, changedProps, oldProps, hasPaths){};
/**
* @override

@@ -674,3 +697,3 @@ * @param {(string | !Array.<(string | number)>)} to Target path to link.

* @param {...*} items Items to insert into array.
* @return {Array}
* @return {!Array}
*/

@@ -748,8 +771,8 @@ Polymer_PropertyEffects.prototype.splice = function(path, start, deleteCount, items){};

* @param {!HTMLTemplateElement} template Template containing binding
bindings
bindings
* @param {boolean=} instanceBinding When false (default), performs
"prototypical" binding of the template and overwrites any previously
bound template for the class. When true (as passed from
`_stampTemplate`), the template info is instanced and linked into
the list of bound templates.
"prototypical" binding of the template and overwrites any previously
bound template for the class. When true (as passed from
`_stampTemplate`), the template info is instanced and linked into the
list of bound templates.
* @return {!TemplateInfo}

@@ -943,2 +966,8 @@ */

* @override
* @param {string} property Name of the property
* @return {boolean}
*/
Polymer_ElementMixin.prototype._canApplyPropertyDefault = function(property){};
/**
* @override
* @param {StampedTemplate} dom to attach to the element.

@@ -1067,3 +1096,45 @@ * @return {ShadowRoot}

* @extends {Polymer_ElementMixin}
*/
function Polymer_DisableUpgradeMixin(){}
/** @type {(boolean | undefined)} */
Polymer_DisableUpgradeMixin.prototype.__isUpgradeDisabled;
/**
* @override
* @return {void}
*/
Polymer_DisableUpgradeMixin.prototype._initializeProperties = function(){};
/**
* @override
* @return {void}
*/
Polymer_DisableUpgradeMixin.prototype._enableProperties = function(){};
/**
* @override
* @param {string} name Attribute name.
* @param {?string} old The previous value for the attribute.
* @param {?string} value The new value for the attribute.
* @param {?string} namespace The XML namespace for the attribute.
* @return {void}
*/
Polymer_DisableUpgradeMixin.prototype.attributeChangedCallback = function(name, old, value, namespace){};
/**
* @override
* @return {void}
*/
Polymer_DisableUpgradeMixin.prototype.connectedCallback = function(){};
/**
* @override
* @return {void}
*/
Polymer_DisableUpgradeMixin.prototype.disconnectedCallback = function(){};
/**
* @override
*/
Polymer_DisableUpgradeMixin.prototype._canApplyPropertyDefault = function(property){};
/**
* @interface
* @extends {Polymer_ElementMixin}
* @extends {Polymer_GestureEventListeners}
* @extends {Polymer_DirMixin}
*/

@@ -1080,2 +1151,11 @@ function Polymer_LegacyElementMixin(){}

/** @type {(boolean | undefined)} */
Polymer_LegacyElementMixin.prototype.__isUpgradeDisabled;
/** @type {(boolean | undefined)} */
Polymer_LegacyElementMixin.prototype.__needsAttributesAtConnected;
/** @type {(boolean | undefined)} */
Polymer_LegacyElementMixin.prototype._legacyForceObservedAttributes;
/** @type {?Node} */

@@ -1099,2 +1179,7 @@ Polymer_LegacyElementMixin.prototype.domHost;

* @override
* @return {void}
*/
Polymer_LegacyElementMixin.prototype._enableProperties = function(){};
/**
* @override
* @param {string} name Name of attribute.

@@ -1119,2 +1204,6 @@ * @param {?string} old Old value of attribute.

* @override
*/
Polymer_LegacyElementMixin.prototype._canApplyPropertyDefault = function(property){};
/**
* @override
* @return {void}

@@ -1127,2 +1216,12 @@ */

*/
Polymer_LegacyElementMixin.prototype.setAttribute = function(name, value){};
/**
* @override
* @return {void}
*/
Polymer_LegacyElementMixin.prototype.removeAttribute = function(name){};
/**
* @override
* @return {void}
*/
Polymer_LegacyElementMixin.prototype.attached = function(){};

@@ -1143,2 +1242,6 @@ /**

/**
* @return {void}
*/
Polymer_LegacyElementMixin.prototype._takeAttributes = function(){};
/**
* @override

@@ -1469,3 +1572,3 @@ * @return {void}

* @param {...*} args Array of strings or objects to log
* @return {Array}
* @return {!Array}
*/

@@ -1572,37 +1675,3 @@ Polymer_LegacyElementMixin.prototype._logf = function(methodName, args){};

* @interface
* @extends {Polymer_ElementMixin}
*/
function Polymer_DisableUpgradeMixin(){}
/**
* @override
* @return {void}
*/
Polymer_DisableUpgradeMixin.prototype._initializeProperties = function(){};
/**
* @override
* @return {void}
*/
Polymer_DisableUpgradeMixin.prototype._enableProperties = function(){};
/**
* @override
* @param {string} name Attribute name.
* @param {?string} old The previous value for the attribute.
* @param {?string} value The new value for the attribute.
* @param {?string} namespace The XML namespace for the attribute.
* @return {void}
*/
Polymer_DisableUpgradeMixin.prototype.attributeChangedCallback = function(name, old, value, namespace){};
/**
* @override
* @return {void}
*/
Polymer_DisableUpgradeMixin.prototype.connectedCallback = function(){};
/**
* @override
* @return {void}
*/
Polymer_DisableUpgradeMixin.prototype.disconnectedCallback = function(){};
/**
* @interface
*/
function Polymer_LegacyDataMixin(){}

@@ -1609,0 +1678,0 @@ /**

@@ -17,3 +17,3 @@ /**

*/
let PolymerDomApi = function() {};
var PolymerDomApi = function() {};

@@ -20,0 +20,0 @@ /**

@@ -138,2 +138,26 @@ /**

/** @type {boolean} */
Polymer.legacyUndefined;
/** @type {boolean} */
Polymer.legacyNoBatch;
/** @type {boolean} */
Polymer.legacyWarnings;
/** @type {boolean} */
Polymer.legacyNotifyOrder;
/** @type {boolean} */
Polymer.orderedComputed;
/** @type {boolean} */
Polymer.fastDomIf;
/** @type {boolean} */
Polymer.removeNestedTemplates;
/** @type {boolean} */
Polymer.suppressTemplateNotifications;
// nb. This is explicitly 'var', as Closure Compiler checks that this is the case.

@@ -140,0 +164,0 @@ /**

@@ -64,5 +64,9 @@ /**

/** @type {TemplateInfo | undefined} */
TemplateInfo.prototype.nextTemplateInfo;
TemplateInfo.prototype.nextSibling;
/** @type {TemplateInfo | undefined} */
TemplateInfo.prototype.previousTemplateInfo;
TemplateInfo.prototype.previousSibling;
/** @type {TemplateInfo | undefined} */
TemplateInfo.prototype.firstChild;
/** @type {TemplateInfo | undefined} */
TemplateInfo.prototype.parent;
/** @type {!Array<!Node>} */

@@ -69,0 +73,0 @@ TemplateInfo.prototype.childNodes;

/**
* @fileoverview Externs for webcomponents polyfills
* @externs
* @suppress {duplicate}
*

@@ -15,39 +16,46 @@ * @license

var HTMLImports = {
/**
* @param {function()} callback
*/
whenReady(callback) {},
/**
* @param {!Node} element
* @return {?HTMLLinkElement|?Document|undefined}
*/
importForElement(element) {}
};
var HTMLImports = {};
/**
* @param {function()=} callback
*/
HTMLImports.whenReady = function(callback) {};
/**
* Returns the import document containing the element.
* @param {!Node} element
* @return {?HTMLLinkElement|?Document|undefined}
*/
HTMLImports.importForElement = function(element) {};
window.HTMLImports = HTMLImports;
var ShadyDOM = {
inUse: false,
flush() {},
/**
* @param {!Node} target
* @param {function(Array<MutationRecord>, MutationObserver)} callback
* @return {MutationObserver}
*/
observeChildren(target, callback) {},
/**
* @param {MutationObserver} observer
*/
unobserveChildren(observer) {},
/**
* @param {Node} node
*/
patch(node) {},
/**
* @param {!ShadowRoot} shadowroot
*/
flushInitial(shadowroot) {}
};
var ShadyDOM = {};
ShadyDOM.inUse;
ShadyDOM.flush = function() {};
/**
* @param {!Node} target
* @param {function(Array<MutationRecord>, MutationObserver)} callback
* @return {MutationObserver}
*/
ShadyDOM.observeChildren = function(target, callback) {};
/**
* @param {MutationObserver} observer
*/
ShadyDOM.unobserveChildren = function(observer) {};
/**
* @param {Node} node
*/
ShadyDOM.patch = function(node) {};
/**
* @param {!ShadowRoot} shadowroot
*/
ShadyDOM.flushInitial = function(shadowroot) {};
window.ShadyDOM = ShadyDOM;

@@ -70,1 +78,6 @@

CustomElementRegistry.prototype.polyfillWrapFlushCallback = function(cb){};
/**
* @param {string} cssText
*/
CSSStyleSheet.prototype.replaceSync = function(cssText) {};

@@ -119,4 +119,2 @@ /**

propertyEffects: Object;
nextTemplateInfo?: TemplateInfo;
previousTemplateInfo?: TemplateInfo;
childNodes: Node[];

@@ -123,0 +121,0 @@ wasPreBound: boolean;

@@ -16,4 +16,2 @@ /**

import {templatize} from '../utils/templatize.js';
import {Debouncer} from '../utils/debounce.js';

@@ -29,20 +27,6 @@

export {DomIf};
import {showHideChildren, templatize} from '../utils/templatize.js';
/**
* The `<dom-if>` element will stamp a light-dom `<template>` child when
* the `if` property becomes truthy, and the template can use Polymer
* data-binding and declarative event features when used in the context of
* a Polymer element's template.
*
* When `if` becomes falsy, the stamped content is hidden but not
* removed from dom. When `if` subsequently becomes truthy again, the content
* is simply re-shown. This approach is used due to its favorable performance
* characteristics: the expense of creating template content is paid only
* once and lazily.
*
* Set the `restamp` property to true to force the stamped content to be
* created / destroyed when the `if` condition changes.
*/
declare class DomIf extends PolymerElement {
declare class DomIfBase extends PolymerElement {
_templateInfo: TemplateInfo|undefined;

@@ -62,2 +46,9 @@ /**

restamp: boolean|null|undefined;
/**
* When the global `suppressTemplateNotifications` setting is used, setting
* `notifyDomChange: true` will enable firing `dom-change` events on this
* element.
*/
notifyDomChange: boolean|null|undefined;
connectedCallback(): void;

@@ -76,6 +67,37 @@ disconnectedCallback(): void;

/**
* Shows or hides the template instance top level child elements. For
* text nodes, `textContent` is removed while "hidden" and replaced when
* "shown."
* Abstract API to be implemented by subclass: Returns true if a template
* instance has been created and inserted.
*
* @returns True when an instance has been created.
*/
__hasInstance(): boolean;
/**
* Abstract API to be implemented by subclass: Returns the child nodes stamped
* from a template instance.
*
* @returns Array of child nodes stamped from the template
* instance.
*/
__getInstanceNodes(): Array<Node|null>|null;
/**
* Abstract API to be implemented by subclass: Creates an instance of the
* template and inserts it into the given parent node.
*
* @param parentNode The parent node to insert the instance into
*/
__createAndInsertInstance(parentNode: Node|null): void;
/**
* Abstract API to be implemented by subclass: Removes nodes created by an
* instance of a template and any associated cleanup.
*/
__teardownInstance(): void;
/**
* Abstract API to be implemented by subclass: Shows or hides any template
* instance childNodes based on the `if` state of the element and its
* `__hideTemplateChildren__` property.
*/
_showHideChildren(): void;

@@ -87,4 +109,77 @@ }

interface HTMLElementTagNameMap {
"dom-if": DomIf;
"dom-if": DomIfBase;
}
}
/**
* The version of DomIf used when `fastDomIf` setting is in use, which is
* optimized for first-render (but adds a tax to all subsequent property updates
* on the host, whether they were used in a given `dom-if` or not).
*
* This implementation avoids use of `Templatizer`, which introduces a new scope
* (a non-element PropertyEffects instance), which is not strictly necessary
* since `dom-if` never introduces new properties to its scope (unlike
* `dom-repeat`). Taking advantage of this fact, the `dom-if` reaches up to its
* `__dataHost` and stamps the template directly from the host using the host's
* runtime `_stampTemplate` API, which binds the property effects of the
* template directly to the host. This both avoids the intermediary
* `Templatizer` instance, but also avoids the need to bind host properties to
* the `<template>` element and forward those into the template instance.
*
* In this version of `dom-if`, the `this.__instance` method is the
* `DocumentFragment` returned from `_stampTemplate`, which also serves as the
* handle for later removing it using the `_removeBoundDom` method.
*/
declare class DomIfFast extends DomIfBase {
constructor();
/**
* Implementation of abstract API needed by DomIfBase.
*
* Shows or hides the template instance top level child nodes. For
* text nodes, `textContent` is removed while "hidden" and replaced when
* "shown."
*/
_showHideChildren(): void;
}
/**
* The "legacy" implementation of `dom-if`, implemented using `Templatizer`.
*
* In this version, `this.__instance` is the `TemplateInstance` returned
* from the templatized constructor.
*/
declare class DomIfLegacy extends DomIfBase {
constructor();
/**
* Implementation of abstract API needed by DomIfBase.
*
* Shows or hides the template instance top level child elements. For
* text nodes, `textContent` is removed while "hidden" and replaced when
* "shown."
*/
_showHideChildren(): void;
}
export {DomIf};
/**
* The `<dom-if>` element will stamp a light-dom `<template>` child when
* the `if` property becomes truthy, and the template can use Polymer
* data-binding and declarative event features when used in the context of
* a Polymer element's template.
*
* When `if` becomes falsy, the stamped content is hidden but not
* removed from dom. When `if` subsequently becomes truthy again, the content
* is simply re-shown. This approach is used due to its favorable performance
* characteristics: the expense of creating template content is paid only
* once and lazily.
*
* Set the `restamp` property to true to force the stamped content to be
* created / destroyed when the `if` condition changes.
*/
declare class DomIf extends DomIfBase {
}
import {TemplateInfo} from '../../interfaces';

@@ -12,3 +12,2 @@ /**

import { templatize } from '../utils/templatize.js';
import { Debouncer } from '../utils/debounce.js';

@@ -20,25 +19,13 @@ import { enqueueDebouncer, flush } from '../utils/flush.js';

import { hideElementsGlobally } from '../utils/hide-template-controls.js';
import { fastDomIf, strictTemplatePolicy, suppressTemplateNotifications } from '../utils/settings.js';
import { showHideChildren, templatize } from '../utils/templatize.js';
/**
* The `<dom-if>` element will stamp a light-dom `<template>` child when
* the `if` property becomes truthy, and the template can use Polymer
* data-binding and declarative event features when used in the context of
* a Polymer element's template.
*
* When `if` becomes falsy, the stamped content is hidden but not
* removed from dom. When `if` subsequently becomes truthy again, the content
* is simply re-shown. This approach is used due to its favorable performance
* characteristics: the expense of creating template content is paid only
* once and lazily.
*
* Set the `restamp` property to true to force the stamped content to be
* created / destroyed when the `if` condition changes.
*
* @customElement
* @polymer
* @extends PolymerElement
* @summary Custom element that conditionally stamps and hides or removes
* template content based on a boolean flag.
* @summary Base class for dom-if element; subclassed into concrete
* implementation.
*/
export class DomIf extends PolymerElement {
class DomIfBase extends PolymerElement {

@@ -81,4 +68,12 @@ // Not needed to find template; can be removed once the analyzer

observer: '__debounceRender'
},
/**
* When the global `suppressTemplateNotifications` setting is used, setting
* `notifyDomChange: true` will enable firing `dom-change` events on this
* element.
*/
notifyDomChange: {
type: Boolean
}
};

@@ -91,7 +86,8 @@

this.__renderDebouncer = null;
this.__invalidProps = null;
this.__instance = null;
this._lastIf = false;
this.__ctor = null;
this.__hideTemplateChildren__ = false;
/** @type {!HTMLTemplateElement|undefined} */
this.__template;
/** @type {!TemplateInfo|undefined} */
this._templateInfo;
}

@@ -151,2 +147,83 @@

/**
* Ensures a template has been assigned to `this.__template`. If it has not
* yet been, it querySelectors for it in its children and if it does not yet
* exist (e.g. in parser-generated case), opens a mutation observer and
* waits for it to appear (returns false if it has not yet been found,
* otherwise true). In the `removeNestedTemplates` case, the "template" will
* be the `dom-if` element itself.
*
* @return {boolean} True when a template has been found, false otherwise
*/
__ensureTemplate() {
if (!this.__template) {
// When `removeNestedTemplates` is true, the "template" is the element
// itself, which has been given a `_templateInfo` property
const thisAsTemplate = /** @type {!HTMLTemplateElement} */ (
/** @type {!HTMLElement} */ (this));
let template = thisAsTemplate._templateInfo ?
thisAsTemplate :
/** @type {!HTMLTemplateElement} */
(wrap(thisAsTemplate).querySelector('template'));
if (!template) {
// Wait until childList changes and template should be there by then
let observer = new MutationObserver(() => {
if (wrap(this).querySelector('template')) {
observer.disconnect();
this.__render();
} else {
throw new Error('dom-if requires a <template> child');
}
});
observer.observe(this, {childList: true});
return false;
}
this.__template = template;
}
return true;
}
/**
* Ensures a an instance of the template has been created and inserted. This
* method may return false if the template has not yet been found or if
* there is no `parentNode` to insert the template into (in either case,
* connection or the template-finding mutation observer firing will queue
* another render, causing this method to be called again at a more
* appropriate time).
*
* Subclasses should implement the following methods called here:
* - `__hasInstance`
* - `__createAndInsertInstance`
* - `__getInstanceNodes`
*
* @return {boolean} True if the instance was created, false otherwise.
*/
__ensureInstance() {
let parentNode = wrap(this).parentNode;
if (!this.__hasInstance()) {
// Guard against element being detached while render was queued
if (!parentNode) {
return false;
}
// Find the template (when false, there was no template yet)
if (!this.__ensureTemplate()) {
return false;
}
this.__createAndInsertInstance(parentNode);
} else {
// Move instance children if necessary
let children = this.__getInstanceNodes();
if (children && children.length) {
// Detect case where dom-if was re-attached in new position
let lastChild = wrap(this).previousSibling;
if (lastChild !== children[children.length-1]) {
for (let i=0, n; (i<children.length) && (n=children[i]); i++) {
wrap(parentNode).insertBefore(n, this);
}
}
}
}
return true;
}
/**
* Forces the element to render its content. Normally rendering is

@@ -157,2 +234,3 @@ * asynchronous to a provoking change. This is done for efficiency so

* validate application state.
*
* @return {void}

@@ -164,2 +242,11 @@ */

/**
* Performs the key rendering steps:
* 1. Ensure a template instance has been stamped (when true)
* 2. Remove the template instance (when false and restamp:true)
* 3. Sync the hidden state of the instance nodes with the if/restamp state
* 4. Fires the `dom-change` event when necessary
*
* @return {void}
*/
__render() {

@@ -171,10 +258,8 @@ if (this.if) {

}
this._showHideChildren();
} else if (this.restamp) {
this.__teardownInstance();
}
if (!this.restamp && this.__instance) {
this._showHideChildren();
}
if (this.if != this._lastIf) {
this._showHideChildren();
if ((!suppressTemplateNotifications || this.notifyDomChange)
&& this.if != this._lastIf) {
this.dispatchEvent(new CustomEvent('dom-change', {

@@ -188,79 +273,321 @@ bubbles: true,

__ensureInstance() {
let parentNode = wrap(this).parentNode;
// Guard against element being detached while render was queued
if (parentNode) {
if (!this.__ctor) {
let template = /** @type {HTMLTemplateElement} */(wrap(this).querySelector('template'));
if (!template) {
// Wait until childList changes and template should be there by then
let observer = new MutationObserver(() => {
if (wrap(this).querySelector('template')) {
observer.disconnect();
this.__render();
} else {
throw new Error('dom-if requires a <template> child');
}
});
observer.observe(this, {childList: true});
return false;
// Ideally these would be annotated as abstract methods in an abstract class,
// but closure compiler is finnicky
/* eslint-disable valid-jsdoc */
/**
* Abstract API to be implemented by subclass: Returns true if a template
* instance has been created and inserted.
*
* @protected
* @return {boolean} True when an instance has been created.
*/
__hasInstance() { }
/**
* Abstract API to be implemented by subclass: Returns the child nodes stamped
* from a template instance.
*
* @protected
* @return {Array<Node>} Array of child nodes stamped from the template
* instance.
*/
__getInstanceNodes() { }
/**
* Abstract API to be implemented by subclass: Creates an instance of the
* template and inserts it into the given parent node.
*
* @protected
* @param {Node} parentNode The parent node to insert the instance into
* @return {void}
*/
__createAndInsertInstance(parentNode) { } // eslint-disable-line no-unused-vars
/**
* Abstract API to be implemented by subclass: Removes nodes created by an
* instance of a template and any associated cleanup.
*
* @protected
* @return {void}
*/
__teardownInstance() { }
/**
* Abstract API to be implemented by subclass: Shows or hides any template
* instance childNodes based on the `if` state of the element and its
* `__hideTemplateChildren__` property.
*
* @protected
* @return {void}
*/
_showHideChildren() { }
/* eslint-enable valid-jsdoc */
}
/**
* The version of DomIf used when `fastDomIf` setting is in use, which is
* optimized for first-render (but adds a tax to all subsequent property updates
* on the host, whether they were used in a given `dom-if` or not).
*
* This implementation avoids use of `Templatizer`, which introduces a new scope
* (a non-element PropertyEffects instance), which is not strictly necessary
* since `dom-if` never introduces new properties to its scope (unlike
* `dom-repeat`). Taking advantage of this fact, the `dom-if` reaches up to its
* `__dataHost` and stamps the template directly from the host using the host's
* runtime `_stampTemplate` API, which binds the property effects of the
* template directly to the host. This both avoids the intermediary
* `Templatizer` instance, but also avoids the need to bind host properties to
* the `<template>` element and forward those into the template instance.
*
* In this version of `dom-if`, the `this.__instance` method is the
* `DocumentFragment` returned from `_stampTemplate`, which also serves as the
* handle for later removing it using the `_removeBoundDom` method.
*/
class DomIfFast extends DomIfBase {
constructor() {
super();
this.__instance = null;
this.__syncInfo = null;
}
/**
* Implementation of abstract API needed by DomIfBase.
*
* @override
* @return {boolean} True when an instance has been created.
*/
__hasInstance() {
return Boolean(this.__instance);
}
/**
* Implementation of abstract API needed by DomIfBase.
*
* @override
* @return {Array<Node>} Array of child nodes stamped from the template
* instance.
*/
__getInstanceNodes() {
return this.__instance.templateInfo.childNodes;
}
/**
* Implementation of abstract API needed by DomIfBase.
*
* Stamps the template by calling `_stampTemplate` on the `__dataHost` of this
* element and then inserts the resulting nodes into the given `parentNode`.
*
* @override
* @param {Node} parentNode The parent node to insert the instance into
* @return {void}
*/
__createAndInsertInstance(parentNode) {
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(
/** @type {!HTMLTemplateElement} */ (this.__template), true);
// Install runEffects hook that prevents running property effects
// (and any nested template effects) when the `if` is false
templateInfo.runEffects = (runEffects, changedProps, hasPaths) => {
let syncInfo = this.__syncInfo;
if (this.if) {
// Mix any props that changed while the `if` was false into `changedProps`
if (syncInfo) {
// If there were properties received while the `if` was false, it is
// important to sync the hidden state with the element _first_, so that
// new bindings to e.g. `textContent` do not get stomped on by
// pre-hidden values if `_showHideChildren` were to be called later at
// the next render. Clearing `__invalidProps` here ensures
// `_showHideChildren`'s call to `__syncHostProperties` no-ops, so
// that we don't call `runEffects` more often than necessary.
this.__syncInfo = null;
this._showHideChildren();
changedProps = Object.assign(syncInfo.changedProps, changedProps);
}
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;
}
}
runEffects(changedProps, hasPaths);
} else {
// Accumulate any values changed while `if` was false, along with the
// runEffects method to sync them, so that we can replay them once `if`
// becomes true
if (this.__instance) {
if (!syncInfo) {
syncInfo = this.__syncInfo = { runEffects, changedProps: {} };
}
});
}
if (!this.__instance) {
this.__instance = new this.__ctor();
wrap(parentNode).insertBefore(this.__instance.root, this);
} else {
this.__syncHostProperties();
let c$ = this.__instance.children;
if (c$ && c$.length) {
// Detect case where dom-if was re-attached in new position
let lastChild = wrap(this).previousSibling;
if (lastChild !== c$[c$.length-1]) {
for (let i=0, n; (i<c$.length) && (n=c$[i]); i++) {
wrap(parentNode).insertBefore(n, this);
if (hasPaths) {
// Store root object of any paths; this will ensure direct bindings
// like [[obj.foo]] bindings run after a `set('obj.foo', v)`, but
// note that path notifications like `set('obj.foo.bar', v)` will
// not propagate. Since batched path notifications are not
// supported, we cannot simply accumulate path notifications. This
// is equivalent to the non-fastDomIf case, which stores root(p) in
// __invalidProps.
for (const p in changedProps) {
const rootProp = root(p);
syncInfo.changedProps[rootProp] = this.__dataHost[rootProp];
}
} else {
Object.assign(syncInfo.changedProps, changedProps);
}
}
}
}
return true;
};
// Stamp the template, and set its DocumentFragment to the "instance"
this.__instance = host._stampTemplate(
/** @type {!HTMLTemplateElement} */ (this.__template), templateInfo);
wrap(parentNode).insertBefore(this.__instance, this);
}
/**
* Run effects for any properties that changed while the `if` was false.
*
* @return {void}
*/
__syncHostProperties() {
let props = this.__invalidProps;
if (props) {
for (let prop in props) {
this.__instance._setPendingProperty(prop, this.__dataHost[prop]);
}
this.__invalidProps = null;
this.__instance._flushProperties();
const syncInfo = this.__syncInfo;
if (syncInfo) {
this.__syncInfo = null;
syncInfo.runEffects(syncInfo.changedProps, false);
}
}
/**
* Implementation of abstract API needed by DomIfBase.
*
* Remove the instance and any nodes it created. Uses the `__dataHost`'s
* runtime `_removeBoundDom` method.
*
* @override
* @return {void}
*/
__teardownInstance() {
const host = this.__dataHost || this;
if (this.__instance) {
host._removeBoundDom(this.__instance);
this.__instance = null;
this.__syncInfo = null;
}
}
/**
* Implementation of abstract API needed by DomIfBase.
*
* Shows or hides the template instance top level child nodes. For
* text nodes, `textContent` is removed while "hidden" and replaced when
* "shown."
*
* @override
* @return {void}
* @protected
* @suppress {visibility}
*/
_showHideChildren() {
const hidden = this.__hideTemplateChildren__ || !this.if;
if (this.__instance && Boolean(this.__instance.__hidden) !== hidden) {
this.__instance.__hidden = hidden;
showHideChildren(hidden, this.__instance.templateInfo.childNodes);
}
if (!hidden) {
this.__syncHostProperties();
}
}
}
/**
* The "legacy" implementation of `dom-if`, implemented using `Templatizer`.
*
* In this version, `this.__instance` is the `TemplateInstance` returned
* from the templatized constructor.
*/
class DomIfLegacy extends DomIfBase {
constructor() {
super();
this.__ctor = null;
this.__instance = null;
this.__invalidProps = null;
}
/**
* Implementation of abstract API needed by DomIfBase.
*
* @override
* @return {boolean} True when an instance has been created.
*/
__hasInstance() {
return Boolean(this.__instance);
}
/**
* Implementation of abstract API needed by DomIfBase.
*
* @override
* @return {Array<Node>} Array of child nodes stamped from the template
* instance.
*/
__getInstanceNodes() {
return this.__instance.children;
}
/**
* Implementation of abstract API needed by DomIfBase.
*
* Stamps the template by creating a new instance of the templatized
* constructor (which is created lazily if it does not yet exist), and then
* inserts its resulting `root` doc fragment into the given `parentNode`.
*
* @override
* @param {Node} parentNode The parent node to insert the instance into
* @return {void}
*/
__createAndInsertInstance(parentNode) {
// Ensure we have an instance constructor
if (!this.__ctor) {
this.__ctor = templatize(
/** @type {!HTMLTemplateElement} */ (this.__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 {DomIfLegacy}
*/
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;
}
}
}
});
}
// Create and insert the instance
this.__instance = new this.__ctor();
wrap(parentNode).insertBefore(this.__instance.root, this);
}
/**
* Implementation of abstract API needed by DomIfBase.
*
* Removes the instance and any nodes it created.
*
* @override
* @return {void}
*/
__teardownInstance() {
if (this.__instance) {
let c$ = this.__instance.children;

@@ -279,4 +606,21 @@ if (c$ && c$.length) {

}
this.__invalidProps = null;
this.__instance = null;
}
}
/**
* Forwards any properties that changed while the `if` was false into the
* template instance and flushes it.
*
* @return {void}
*/
__syncHostProperties() {
let props = this.__invalidProps;
if (props) {
this.__invalidProps = null;
for (let prop in props) {
this.__instance._setPendingProperty(prop, this.__dataHost[prop]);
}
this.__instance._flushProperties();
}

@@ -286,18 +630,49 @@ }

/**
* Implementation of abstract API needed by DomIfBase.
*
* Shows or hides the template instance top level child elements. For
* text nodes, `textContent` is removed while "hidden" and replaced when
* "shown."
*
* @override
* @protected
* @return {void}
* @protected
* @suppress {visibility}
*/
_showHideChildren() {
let hidden = this.__hideTemplateChildren__ || !this.if;
if (this.__instance) {
const hidden = this.__hideTemplateChildren__ || !this.if;
if (this.__instance && Boolean(this.__instance.__hidden) !== hidden) {
this.__instance.__hidden = hidden;
this.__instance._showHideChildren(hidden);
}
if (!hidden) {
this.__syncHostProperties();
}
}
}
/**
* The `<dom-if>` element will stamp a light-dom `<template>` child when
* the `if` property becomes truthy, and the template can use Polymer
* data-binding and declarative event features when used in the context of
* a Polymer element's template.
*
* When `if` becomes falsy, the stamped content is hidden but not
* removed from dom. When `if` subsequently becomes truthy again, the content
* is simply re-shown. This approach is used due to its favorable performance
* characteristics: the expense of creating template content is paid only
* once and lazily.
*
* Set the `restamp` property to true to force the stamped content to be
* created / destroyed when the `if` condition changes.
*
* @customElement
* @polymer
* @extends DomIfBase
* @constructor
* @summary Custom element that conditionally stamps and hides or removes
* template content based on a boolean flag.
*/
export const DomIf = fastDomIf ? DomIfFast : DomIfLegacy;
customElements.define(DomIf.is, DomIf);

@@ -131,2 +131,3 @@ /**

PolymerElement) {
_templateInfo: TemplateInfo|null;

@@ -205,7 +206,8 @@ /**

/**
* Defines an initial count of template instances to render after setting
* the `items` array, before the next paint, and puts the `dom-repeat`
* into "chunking mode". The remaining items will be created and rendered
* incrementally at each animation frame therof until all instances have
* been rendered.
* When greater than zero, defines an initial count of template instances
* to render after setting the `items` array, before the next paint, and
* puts the `dom-repeat` into "chunking mode". The remaining items (and
* any future items as a result of pushing onto the array) will be created
* and rendered incrementally at each animation frame thereof until all
* instances have been rendered.
*/

@@ -228,2 +230,26 @@ initialCount: number|null|undefined;

readonly _targetFrameTime: number|null|undefined;
/**
* When the global `suppressTemplateNotifications` setting is used, setting
* `notifyDomChange: true` will enable firing `dom-change` events on this
* element.
*/
notifyDomChange: boolean|null|undefined;
/**
* When chunking is enabled via `initialCount` and the `items` array is
* set to a new array, this flag controls whether the previously rendered
* instances are reused or not.
*
* When `true`, any previously rendered template instances are updated in
* place to their new item values synchronously in one shot, and then any
* further items (if any) are chunked out. When `false`, the list is
* returned back to its `initialCount` (any instances over the initial
* count are discarded) and the remainder of the list is chunked back in.
* Set this to `true` to avoid re-creating the list and losing scroll
* position, although note that when changing the list to completely
* different data the render thread will be blocked until all existing
* instances are updated to their new data.
*/
reuseChunkedInstances: boolean|null|undefined;
connectedCallback(): void;

@@ -301,1 +327,3 @@ disconnectedCallback(): void;

}
import {TemplateInfo} from '../../interfaces';

@@ -20,2 +20,3 @@ /**

import { hideElementsGlobally } from '../utils/hide-template-controls.js';
import { suppressTemplateNotifications } from '../utils/settings.js';

@@ -243,3 +244,3 @@ /**

type: Number,
notify: true,
notify: !suppressTemplateNotifications,
readOnly: true

@@ -249,11 +250,11 @@ },

/**
* Defines an initial count of template instances to render after setting
* the `items` array, before the next paint, and puts the `dom-repeat`
* into "chunking mode". The remaining items will be created and rendered
* incrementally at each animation frame therof until all instances have
* been rendered.
* When greater than zero, defines an initial count of template instances
* to render after setting the `items` array, before the next paint, and
* puts the `dom-repeat` into "chunking mode". The remaining items (and
* any future items as a result of pushing onto the array) will be created
* and rendered incrementally at each animation frame thereof until all
* instances have been rendered.
*/
initialCount: {
type: Number,
observer: '__initializeChunking'
type: Number
},

@@ -281,2 +282,30 @@

computed: '__computeFrameTime(targetFramerate)'
},
/**
* When the global `suppressTemplateNotifications` setting is used, setting
* `notifyDomChange: true` will enable firing `dom-change` events on this
* element.
*/
notifyDomChange: {
type: Boolean
},
/**
* When chunking is enabled via `initialCount` and the `items` array is
* set to a new array, this flag controls whether the previously rendered
* instances are reused or not.
*
* When `true`, any previously rendered template instances are updated in
* place to their new item values synchronously in one shot, and then any
* further items (if any) are chunked out. When `false`, the list is
* returned back to its `initialCount` (any instances over the initial
* count are discarded) and the remainder of the list is chunked back in.
* Set this to `true` to avoid re-creating the list and losing scroll
* position, although note that when changing the list to completely
* different data the render thread will be blocked until all existing
* instances are updated to their new data.
*/
reuseChunkedInstances: {
type: Boolean
}

@@ -295,8 +324,10 @@

this.__instances = [];
this.__limit = Infinity;
this.__pool = [];
this.__renderDebouncer = null;
this.__itemsIdxToInstIdx = {};
this.__chunkCount = null;
this.__lastChunkTime = null;
this.__renderStartTime = null;
this.__itemsArrayChanged = false;
this.__shouldMeasureChunk = false;
this.__shouldContinueChunking = false;
this.__chunkingId = 0;
this.__sortFn = null;

@@ -309,2 +340,4 @@ this.__filterFn = null;

this.template = null;
/** @type {TemplateInfo} */
this._templateInfo;
}

@@ -348,5 +381,11 @@

if (!this.__ctor) {
let template = this.template = /** @type {HTMLTemplateElement} */(this.querySelector('template'));
// When `removeNestedTemplates` is true, the "template" is the element
// itself, which has been given a `_templateInfo` property
const thisAsTemplate = /** @type {!HTMLTemplateElement} */ (
/** @type {!HTMLElement} */ (this));
let template = this.template = thisAsTemplate._templateInfo ?
thisAsTemplate :
/** @type {!HTMLTemplateElement} */ (this.querySelector('template'));
if (!template) {
// // Wait until childList changes and template should be there by then
// Wait until childList changes and template should be there by then
let observer = new MutationObserver(() => {

@@ -437,34 +476,2 @@ if (this.querySelector('template')) {

__initializeChunking() {
if (this.initialCount) {
this.__limit = this.initialCount;
this.__chunkCount = this.initialCount;
this.__lastChunkTime = performance.now();
}
}
__tryRenderChunk() {
// Debounced so that multiple calls through `_render` between animation
// frames only queue one new rAF (e.g. array mutation & chunked render)
if (this.items && this.__limit < this.items.length) {
this.__debounceRender(this.__requestRenderChunk);
}
}
__requestRenderChunk() {
requestAnimationFrame(()=>this.__renderChunk());
}
__renderChunk() {
// Simple auto chunkSize throttling algorithm based on feedback loop:
// measure actual time between frames and scale chunk count by ratio
// of target/actual frame time
let currChunkTime = performance.now();
let ratio = this._targetFrameTime / (currChunkTime - this.__lastChunkTime);
this.__chunkCount = Math.round(this.__chunkCount * ratio) || 1;
this.__limit += this.__chunkCount;
this.__lastChunkTime = currChunkTime;
this.__debounceRender(this.__render);
}
__observeChanged() {

@@ -475,16 +482,2 @@ this.__observePaths = this.observe &&

__itemsChanged(change) {
if (this.items && !Array.isArray(this.items)) {
console.warn('dom-repeat expected array for `items`, found', this.items);
}
// If path was to an item (e.g. 'items.3' or 'items.3.foo'), forward the
// path to that instance synchronously (returns false for non-item paths)
if (!this.__handleItemPath(change.path, change.value)) {
// Otherwise, the array was reset ('items') or spliced ('items.splices'),
// so queue a full refresh
this.__initializeChunking();
this.__debounceRender(this.__render);
}
}
__handleObservedPaths(path) {

@@ -508,2 +501,19 @@ // Handle cases where path changes should cause a re-sort/filter

__itemsChanged(change) {
if (this.items && !Array.isArray(this.items)) {
console.warn('dom-repeat expected array for `items`, found', this.items);
}
// If path was to an item (e.g. 'items.3' or 'items.3.foo'), forward the
// path to that instance synchronously (returns false for non-item paths)
if (!this.__handleItemPath(change.path, change.value)) {
// Otherwise, the array was reset ('items') or spliced ('items.splices'),
// so queue a render. Restart chunking when the items changed (for
// backward compatibility), unless `reuseChunkedInstances` option is set
if (change.path === 'items') {
this.__itemsArrayChanged = true;
}
this.__debounceRender(this.__render);
}
}
/**

@@ -540,22 +550,32 @@ * @param {function(this:DomRepeat)} fn Function to debounce.

}
this.__applyFullRefresh();
// Reset the pool
// TODO(kschaaf): Reuse pool across turns and nested templates
// Now that objects/arrays are re-evaluated when set, we can safely
// reuse pooled instances across turns, however we still need to decide
// semantics regarding how long to hold, how many to hold, etc.
this.__pool.length = 0;
let items = this.items || [];
// Sort and filter the items into a mapping array from instance->item
const isntIdxToItemsIdx = this.__sortAndFilterItems(items);
// If we're chunking, increase the limit if there are new instances to
// create and schedule the next chunk
const limit = this.__calculateLimit(isntIdxToItemsIdx.length);
// Create, update, and/or remove instances
this.__updateInstances(items, limit, isntIdxToItemsIdx);
// If we're chunking, schedule a rAF task to measure/continue chunking.
// Do this before any notifying events (renderedItemCount & dom-change)
// since those could modify items and enqueue a new full render which will
// pre-empt this measurement.
if (this.initialCount &&
(this.__shouldMeasureChunk || this.__shouldContinueChunking)) {
cancelAnimationFrame(this.__chunkingId);
this.__chunkingId = requestAnimationFrame(() => this.__continueChunking());
}
// Set rendered item count
this._setRenderedItemCount(this.__instances.length);
// Notify users
this.dispatchEvent(new CustomEvent('dom-change', {
bubbles: true,
composed: true
}));
// Check to see if we need to render more items
this.__tryRenderChunk();
if (!suppressTemplateNotifications || this.notifyDomChange) {
this.dispatchEvent(new CustomEvent('dom-change', {
bubbles: true,
composed: true
}));
}
}
__applyFullRefresh() {
let items = this.items || [];
__sortAndFilterItems(items) {
// Generate array maping the instance index to the items array index
let isntIdxToItemsIdx = new Array(items.length);

@@ -574,8 +594,65 @@ for (let i=0; i<items.length; i++) {

}
return isntIdxToItemsIdx;
}
__calculateLimit(filteredItemCount) {
let limit = filteredItemCount;
const currentCount = this.__instances.length;
// When chunking, we increase the limit from the currently rendered count
// by the chunk count that is re-calculated after each rAF (with special
// cases for reseting the limit to initialCount after changing items)
if (this.initialCount) {
let newCount;
if (!this.__chunkCount ||
(this.__itemsArrayChanged && !this.reuseChunkedInstances)) {
// Limit next render to the initial count
limit = Math.min(filteredItemCount, this.initialCount);
// Subtract off any existing instances to determine the number of
// instances that will be created
newCount = Math.max(limit - currentCount, 0);
// Initialize the chunk size with how many items we're creating
this.__chunkCount = newCount || 1;
} else {
// The number of new instances that will be created is based on the
// existing instances, the new list size, and the chunk size
newCount = Math.min(
Math.max(filteredItemCount - currentCount, 0),
this.__chunkCount);
// Update the limit based on how many new items we're making, limited
// buy the total size of the list
limit = Math.min(currentCount + newCount, filteredItemCount);
}
// Record some state about chunking for use in `__continueChunking`
this.__shouldMeasureChunk = newCount === this.__chunkCount;
this.__shouldContinueChunking = limit < filteredItemCount;
this.__renderStartTime = performance.now();
}
this.__itemsArrayChanged = false;
return limit;
}
__continueChunking() {
// Simple auto chunkSize throttling algorithm based on feedback loop:
// measure actual time between frames and scale chunk count by ratio of
// target/actual frame time. Only modify chunk size if our measurement
// reflects the cost of a creating a full chunk's worth of instances; this
// avoids scaling up the chunk size if we e.g. quickly re-rendered instances
// in place
if (this.__shouldMeasureChunk) {
const renderTime = performance.now() - this.__renderStartTime;
const ratio = this._targetFrameTime / renderTime;
this.__chunkCount = Math.round(this.__chunkCount * ratio) || 1;
}
// Enqueue a new render if we haven't reached the full size of the list
if (this.__shouldContinueChunking) {
this.__debounceRender(this.__render);
}
}
__updateInstances(items, limit, isntIdxToItemsIdx) {
// items->inst map kept for item path forwarding
const itemsIdxToInstIdx = this.__itemsIdxToInstIdx = {};
let instIdx = 0;
let instIdx;
// Generate instances and assign items
const limit = Math.min(isntIdxToItemsIdx.length, this.__limit);
for (; instIdx<limit; instIdx++) {
for (instIdx=0; instIdx<limit; instIdx++) {
let inst = this.__instances[instIdx];

@@ -617,6 +694,3 @@ let itemIdx = isntIdxToItemsIdx[instIdx];

__detachAndRemoveInstance(idx) {
let inst = this.__detachInstance(idx);
if (inst) {
this.__pool.push(inst);
}
this.__detachInstance(idx);
this.__instances.splice(idx, 1);

@@ -634,13 +708,3 @@ }

__insertInstance(item, instIdx, itemIdx) {
let inst = this.__pool.pop();
if (inst) {
// TODO(kschaaf): If the pool is shared across turns, hostProps
// need to be re-set to reused instances in addition to item
inst._setPendingProperty(this.as, item);
inst._setPendingProperty(this.indexAs, instIdx);
inst._setPendingProperty(this.itemsIndexAs, itemIdx);
inst._flushProperties();
} else {
inst = this.__stampInstance(item, instIdx, itemIdx);
}
const inst = this.__stampInstance(item, instIdx, itemIdx);
let beforeRow = this.__instances[instIdx + 1];

@@ -647,0 +711,0 @@ let beforeNode = beforeRow ? beforeRow.children[0] : this;

@@ -178,2 +178,4 @@ /**

const LegacyElement = LegacyElementMixin(HTMLElement);
/* Note about construction and extension of legacy classes.

@@ -534,4 +536,4 @@ [Changed in Q4 2018 to optimize performance.]

}
let klass = mixin ? mixin(LegacyElementMixin(HTMLElement)) :
LegacyElementMixin(HTMLElement);
let klass = mixin ? mixin(LegacyElement) :
LegacyElement;
klass = GenerateClassFromInfo(info, klass, info.behaviors);

@@ -538,0 +540,0 @@ // decorate klass with registration info

@@ -35,2 +35,6 @@ /**

import {findObservedAttributesGetter} from '../mixins/disable-upgrade-mixin.js';
import {register} from '../utils/telemetry.js';
export {LegacyElementMixin};

@@ -45,3 +49,3 @@

*/
declare function LegacyElementMixin<T extends new (...args: any[]) => {}>(base: T): T & LegacyElementMixinConstructor & ElementMixinConstructor & PropertyEffectsConstructor & TemplateStampConstructor & PropertyAccessorsConstructor & PropertiesChangedConstructor & PropertiesMixinConstructor & GestureEventListenersConstructor;
declare function LegacyElementMixin<T extends new (...args: any[]) => {}>(base: T): T & LegacyElementMixinConstructor & ElementMixinConstructor & PropertyEffectsConstructor & TemplateStampConstructor & PropertyAccessorsConstructor & PropertiesChangedConstructor & PropertiesMixinConstructor & GestureEventListenersConstructor & DirMixinConstructor;

@@ -62,2 +66,4 @@ import {ElementMixinConstructor} from '../mixins/element-mixin.js';

import {DirMixinConstructor} from '../mixins/dir-mixin.js';
interface LegacyElementMixinConstructor {

@@ -69,5 +75,6 @@ new(...args: any[]): LegacyElementMixin;

interface LegacyElementMixin extends ElementMixin, PropertyEffects, TemplateStamp, PropertyAccessors, PropertiesChanged, PropertiesMixin, GestureEventListeners {
interface LegacyElementMixin extends ElementMixin, PropertyEffects, TemplateStamp, PropertyAccessors, PropertiesChanged, PropertiesMixin, GestureEventListeners, DirMixin {
isAttached: boolean;
_debouncers: {[key: string]: Function|null}|null;
_legacyForceObservedAttributes: boolean|undefined;

@@ -94,2 +101,3 @@ /**

_initializeProperties(): void;
_enableProperties(): void;

@@ -118,2 +126,3 @@ /**

disconnectedCallback(): void;
_canApplyPropertyDefault(property: any): any;

@@ -125,2 +134,4 @@ /**

created(): void;
setAttribute(name: any, value: any): void;
removeAttribute(name: any): void;

@@ -148,2 +159,3 @@ /**

attributeChanged(name: string, old: string|null, value: string|null): void;
_takeAttributes(): void;

@@ -658,3 +670,3 @@ /**

*/
_logf(methodName: string, ...args: any[]): any[]|null;
_logf(methodName: string, ...args: any[]): any[];
}

@@ -11,3 +11,3 @@ /**

import '@webcomponents/shadycss/entrypoints/apply-shim.js';
import { ElementMixin } from '../mixins/element-mixin.js';
import { ElementMixin, builtCSS } from '../mixins/element-mixin.js';
import { GestureEventListeners } from '../mixins/gesture-event-listeners.js';

@@ -25,3 +25,8 @@ import { DirMixin } from '../mixins/dir-mixin.js';

import { scopeSubtree } from '../utils/scope-subtree.js';
import { legacyOptimizations, legacyNoObservedAttributes } from '../utils/settings.js';
import { findObservedAttributesGetter } from '../mixins/disable-upgrade-mixin.js';
import { register } from '../utils/telemetry.js';
const DISABLED_ATTR = 'disable-upgrade';
let styleInterface = window.ShadyCSS;

@@ -39,2 +44,3 @@

* @appliesMixin GestureEventListeners
* @appliesMixin DirMixin
* @property isAttached {boolean} Set to `true` in this element's

@@ -45,2 +51,5 @@ * `connectedCallback` and `false` in `disconnectedCallback`

export const LegacyElementMixin = dedupingMixin((base) => {
// TODO(kschaaf): Note, the `@implements {Polymer_DirMixin}` is required here
// (rather than on legacyElementBase) for unknown reasons.
/**

@@ -54,5 +63,18 @@ * @constructor

*/
const legacyElementBase = DirMixin(GestureEventListeners(ElementMixin(base)));
const GesturesElement = GestureEventListeners(ElementMixin(base));
// Note, the DirMixin does nothing if css is built so avoid including it
// in that case.
/**
* @constructor
* @extends {GesturesElement}
* @private
*/
const legacyElementBase = builtCSS ? GesturesElement :
DirMixin(GesturesElement);
const observedAttributesGetter = findObservedAttributesGetter(legacyElementBase);
/**
* Map of simple names to touch action names

@@ -85,2 +107,9 @@ * @dict

this._debouncers;
// NOTE: Inlined for perf from version of DisableUpgradeMixin.
/** @type {boolean|undefined} */
this.__isUpgradeDisabled;
/** @type {boolean|undefined} */
this.__needsAttributesAtConnected;
/** @type {boolean|undefined} */
this._legacyForceObservedAttributes;
}

@@ -110,2 +139,75 @@

/**
* Processes an attribute reaction when the `legacyNoObservedAttributes`
* setting is in use.
* @param {string} name Name of attribute that changed
* @param {?string} old Old attribute value
* @param {?string} value New attribute value
* @return {void}
*/
__attributeReaction(name, old, value) {
if ((this.__dataAttributes && this.__dataAttributes[name]) || name === DISABLED_ATTR) {
this.attributeChangedCallback(name, old, value, null);
}
}
/** @override */
setAttribute(name, value) {
if (legacyNoObservedAttributes && !this._legacyForceObservedAttributes) {
const oldValue = this.getAttribute(name);
super.setAttribute(name, value);
// value coerced to String for closure's benefit
this.__attributeReaction(name, oldValue, String(value));
} else {
super.setAttribute(name, value);
}
}
/** @override */
removeAttribute(name) {
if (legacyNoObservedAttributes && !this._legacyForceObservedAttributes) {
const oldValue = this.getAttribute(name);
super.removeAttribute(name);
this.__attributeReaction(name, oldValue, null);
} else {
super.removeAttribute(name);
}
}
// NOTE: Inlined for perf from version of DisableUpgradeMixin.
static get observedAttributes() {
if (legacyNoObservedAttributes && !this.prototype._legacyForceObservedAttributes) {
// Ensure this element is property registered with the telemetry system.
if (!this.hasOwnProperty(JSCompiler_renameProperty('__observedAttributes', this))) {
this.__observedAttributes = [];
register(this.prototype);
}
return this.__observedAttributes;
} else {
return observedAttributesGetter.call(this).concat(DISABLED_ATTR);
}
}
// NOTE: Inlined for perf from version of DisableUpgradeMixin.
// Prevent element from enabling properties when it's upgrade disabled.
// Normally overriding connectedCallback would be enough, but dom-* elements
/** @override */
_enableProperties() {
if (!this.__isUpgradeDisabled) {
super._enableProperties();
}
}
// NOTE: Inlined for perf from version of DisableUpgradeMixin.
// If the element starts upgrade-disabled and a property is set for
// which an accessor exists, the default should not be applied.
// This additional check is needed because defaults are applied via
// `_initializeProperties` which is called after initial properties
// have been set when the element starts upgrade-disabled.
/** @override */
_canApplyPropertyDefault(property) {
return super._canApplyPropertyDefault(property) &&
!(this.__isUpgradeDisabled && this._isPropertyPending(property));
}
/**
* Provides an implementation of `connectedCallback`

@@ -117,5 +219,11 @@ * which adds Polymer legacy API's `attached` method.

connectedCallback() {
super.connectedCallback();
this.isAttached = true;
this.attached();
if (this.__needsAttributesAtConnected) {
this._takeAttributes();
}
// NOTE: Inlined for perf from version of DisableUpgradeMixin.
if (!this.__isUpgradeDisabled) {
super.connectedCallback();
this.isAttached = true;
this.attached();
}
}

@@ -138,5 +246,8 @@

disconnectedCallback() {
super.disconnectedCallback();
this.isAttached = false;
this.detached();
// NOTE: Inlined for perf from version of DisableUpgradeMixin.
if (!this.__isUpgradeDisabled) {
super.disconnectedCallback();
this.isAttached = false;
this.detached();
}
}

@@ -164,4 +275,17 @@

if (old !== value) {
super.attributeChangedCallback(name, old, value, namespace);
this.attributeChanged(name, old, value);
// NOTE: Inlined for perf from version of DisableUpgradeMixin.
if (name == DISABLED_ATTR) {
// When disable-upgrade is removed, intialize properties and
// provoke connectedCallback if the element is already connected.
if (this.__isUpgradeDisabled && value == null) {
this._initializeProperties();
this.__isUpgradeDisabled = false;
if (wrap(this).isConnected) {
this.connectedCallback();
}
}
} else {
super.attributeChangedCallback(name, old, value, namespace);
this.attributeChanged(name, old, value);
}
}

@@ -191,18 +315,41 @@ }

_initializeProperties() {
let proto = Object.getPrototypeOf(this);
if (!proto.hasOwnProperty(JSCompiler_renameProperty('__hasRegisterFinished', proto))) {
this._registered();
// backstop in case the `_registered` implementation does not set this
proto.__hasRegisterFinished = true;
// NOTE: Inlined for perf from version of DisableUpgradeMixin.
// Only auto-use disable-upgrade if legacyOptimizations is set.
if (legacyOptimizations && this.hasAttribute(DISABLED_ATTR)) {
this.__isUpgradeDisabled = true;
} else {
let proto = Object.getPrototypeOf(this);
if (!proto.hasOwnProperty(JSCompiler_renameProperty('__hasRegisterFinished', proto))) {
this._registered();
// backstop in case the `_registered` implementation does not set this
proto.__hasRegisterFinished = true;
}
super._initializeProperties();
this.root = /** @type {HTMLElement} */(this);
this.created();
// Pull all attribute values 1x if `legacyNoObservedAttributes` is set.
if (legacyNoObservedAttributes && !this._legacyForceObservedAttributes) {
if (this.hasAttributes()) {
this._takeAttributes();
// Element created from scratch or parser generated
} else if (!this.parentNode) {
this.__needsAttributesAtConnected = true;
}
}
// Ensure listeners are applied immediately so that they are
// added before declarative event listeners. This allows an element to
// decorate itself via an event prior to any declarative listeners
// seeing the event. Note, this ensures compatibility with 1.x ordering.
this._applyListeners();
}
super._initializeProperties();
this.root = /** @type {HTMLElement} */(this);
this.created();
// Ensure listeners are applied immediately so that they are
// added before declarative event listeners. This allows an element to
// decorate itself via an event prior to any declarative listeners
// seeing the event. Note, this ensures compatibility with 1.x ordering.
this._applyListeners();
}
_takeAttributes() {
const a = this.attributes;
for (let i=0, l=a.length; i < l; i++) {
const attr = a[i];
this.__attributeReaction(attr.name, null, attr.value);
}
}
/**

@@ -1065,3 +1212,3 @@ * Called automatically when an element is initializing.

* @param {...*} args Array of strings or objects to log
* @return {Array} Array with formatting information for `console`
* @return {!Array} Array with formatting information for `console`
* logging.

@@ -1068,0 +1215,0 @@ * @override

@@ -42,2 +42,6 @@ /**

}
// Copy opt out for `legacyNoObservedAttributes` from info object to class.
if (info._legacyForceObservedAttributes) {
klass.prototype._legacyForceObservedAttributes = info._legacyForceObservedAttributes;
}
customElements.define(klass.is, /** @type {!HTMLElement} */(klass));

@@ -44,0 +48,0 @@ return klass;

@@ -106,3 +106,3 @@ /**

*/
getOwnerRoot(): Node|null;
getOwnerRoot(): Node;

@@ -109,0 +109,0 @@ /**

@@ -116,3 +116,3 @@ /**

*
* @return {Node} Top most element in the dom tree in which the node
* @return {!Node} Top most element in the dom tree in which the node
* exists. If the node is connected to a document this is either a

@@ -119,0 +119,0 @@ * shadowRoot or the document; otherwise, it may be the node

@@ -19,2 +19,6 @@ /**

export {findObservedAttributesGetter};
declare function findObservedAttributesGetter(): any;
export {DisableUpgradeMixin};

@@ -76,2 +80,3 @@

disconnectedCallback(): void;
_canApplyPropertyDefault(property: any): any;
}

@@ -13,7 +13,18 @@ /**

import { ElementMixin } from './element-mixin.js';
import { dedupingMixin } from '../utils/mixin.js';
import { wrap } from '../utils/wrap.js';
const DISABLED_ATTR = 'disable-upgrade';
export const findObservedAttributesGetter = (ctor) => {
while (ctor) {
const desc = Object.getOwnPropertyDescriptor(ctor, 'observedAttributes');
if (desc) {
return desc.get;
}
ctor = Object.getPrototypeOf(ctor.prototype).constructor;
}
return () => [];
};
/**

@@ -55,2 +66,9 @@ * Element class mixin that allows the element to boot up in a non-enabled

// Work around for closure bug #126934458. Using `super` in a property
// getter does not work so instead we search the Base prototype for an
// implementation of observedAttributes so that we can override and call
// the `super` getter. Note, this is done one time ever because we assume
// that `Base` is always comes from `Polymer.LegacyElementMixn`.
let observedAttributesGetter = findObservedAttributesGetter(superClass);
/**

@@ -63,9 +81,42 @@ * @polymer

/**
* @suppress {missingProperties} go/missingfnprops
*/
constructor() {
super();
/** @type {boolean|undefined} */
this.__isUpgradeDisabled;
}
static get observedAttributes() {
return super.observedAttributes.concat(DISABLED_ATTR);
return observedAttributesGetter.call(this).concat(DISABLED_ATTR);
}
// Prevent element from initializing properties when it's upgrade disabled.
/** @override */
_initializeProperties() {
if (this.hasAttribute(DISABLED_ATTR)) {
this.__isUpgradeDisabled = true;
} else {
super._initializeProperties();
}
}
// Prevent element from enabling properties when it's upgrade disabled.
// Normally overriding connectedCallback would be enough, but dom-* elements
/** @override */
_enableProperties() {
if (!this.__isUpgradeDisabled) {
super._enableProperties();
}
}
// If the element starts upgrade-disabled and a property is set for
// which an accessor exists, the default should not be applied.
// This additional check is needed because defaults are applied via
// `_initializeProperties` which is called after initial properties
// have been set when the element starts upgrade-disabled.
/** @override */
_canApplyPropertyDefault(property) {
return super._canApplyPropertyDefault(property) &&
!(this.__isUpgradeDisabled && this._isPropertyPending(property));
}
/**

@@ -81,4 +132,10 @@ * @override

if (name == DISABLED_ATTR) {
if (!this.__dataEnabled && value == null && this.isConnected) {
super.connectedCallback();
// When disable-upgrade is removed, intialize properties and
// provoke connectedCallback if the element is already connected.
if (this.__isUpgradeDisabled && value == null) {
super._initializeProperties();
this.__isUpgradeDisabled = false;
if (wrap(this).isConnected) {
super.connectedCallback();
}
}

@@ -91,14 +148,7 @@ } else {

/*
NOTE: cannot gate on attribute because this is called before
attributes are delivered. Therefore, we stub this out and
call `super._initializeProperties()` manually.
*/
// Prevent element from connecting when it's upgrade disabled.
// This prevents user code in `attached` from being called.
/** @override */
_initializeProperties() {}
// prevent user code in connected from running
/** @override */
connectedCallback() {
if (this.__dataEnabled || !this.hasAttribute(DISABLED_ATTR)) {
if (!this.__isUpgradeDisabled) {
super.connectedCallback();

@@ -108,17 +158,8 @@ }

// prevent element from turning on properties
// Prevent element from disconnecting when it's upgrade disabled.
// This avoids allowing user code `detached` from being called without a
// paired call to `attached`.
/** @override */
_enableProperties() {
if (!this.hasAttribute(DISABLED_ATTR)) {
if (!this.__dataEnabled) {
super._initializeProperties();
}
super._enableProperties();
}
}
// only go if "enabled"
/** @override */
disconnectedCallback() {
if (this.__dataEnabled) {
if (!this.__isUpgradeDisabled) {
super.disconnectedCallback();

@@ -125,0 +166,0 @@ }

@@ -214,2 +214,12 @@ /**

/**
* Determines if a property dfeault can be applied. For example, this
* prevents a default from being applied when a property that has no
* accessor is overridden by its host before upgrade (e.g. via a binding).
*
* @param property Name of the property
* @returns Returns true if the property default can be applied.
*/
_canApplyPropertyDefault(property: string): boolean;
/**
* Attaches an element's stamped dom to itself. By default,

@@ -216,0 +226,0 @@ * this method creates a `shadowRoot` and adds the dom to it.

@@ -14,3 +14,3 @@ /**

import { rootPath, strictTemplatePolicy, allowTemplateFromDomModule, legacyOptimizations, syncInitialRender } from '../utils/settings.js';
import { rootPath, strictTemplatePolicy, allowTemplateFromDomModule, legacyOptimizations, legacyWarnings, syncInitialRender, supportsAdoptingStyleSheets, useAdoptedStyleSheetsWithBuiltCSS } from '../utils/settings.js';
import { dedupingMixin } from '../utils/mixin.js';

@@ -28,5 +28,5 @@ import { stylesFromTemplate, stylesFromModuleImports } from '../utils/style-gather.js';

*/
export const version = '3.3.1';
export const version = '3.4.0';
const builtCSS = window.ShadyCSS && window.ShadyCSS['cssBuild'];
export const builtCSS = window.ShadyCSS && window.ShadyCSS['cssBuild'];

@@ -299,2 +299,26 @@ /**

}
// Support for `adoptedStylesheets` relies on using native Shadow DOM
// and built CSS. Built CSS is required because runtime transformation of
// `@apply` is not supported. This is because ShadyCSS relies on being able
// to update a `style` element in the element template and this is
// removed when using `adoptedStyleSheets`.
// Note, it would be more efficient to allow style includes to become
// separate stylesheets; however, because of `@apply` these are
// potentially not shareable and sharing the ones that could be shared
// would require some coordination. To keep it simple, all the includes
// and styles are collapsed into a single shareable stylesheet.
if (useAdoptedStyleSheetsWithBuiltCSS && builtCSS &&
supportsAdoptingStyleSheets) {
// Remove styles in template and make a shareable stylesheet
const styles = template.content.querySelectorAll('style');
if (styles) {
let css = '';
Array.from(styles).forEach(s => {
css += s.textContent;
s.parentNode.removeChild(s);
});
klass._styleSheet = new CSSStyleSheet();
klass._styleSheet.replaceSync(css);
}
}
}

@@ -417,5 +441,9 @@

*
* If a `static get is()` getter is defined, the default implementation
* will return the first `<template>` in a `dom-module` whose `id`
* matches this element's `is`.
* If a `static get is()` getter is defined, the default implementation will
* return the first `<template>` in a `dom-module` whose `id` matches this
* element's `is` (note that a `_template` property on the class prototype
* takes precedence over the `dom-module` template, to maintain legacy
* element semantics; a subclass will subsequently fall back to its super
* class template if neither a `prototype._template` or a `dom-module` for
* the class's `is` was found).
*

@@ -467,9 +495,16 @@ * Users may override this getter to return an arbitrary 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
(getTemplateFromDomModule(/** @type {PolymerElementConstructor}*/ (this).is) ||
((this.hasOwnProperty(JSCompiler_renameProperty('is', this)) &&
(getTemplateFromDomModule(/** @type {PolymerElementConstructor}*/ (this).is))) ||
// Next look for superclass template (call the super impl this

@@ -570,6 +605,3 @@ // way so that `this` points to the superclass)

let info = p$[p];
// Don't set default value if there is already an own property, which
// happens when a `properties` property with default but no effects had
// a property set (e.g. bound) by its host before upgrade
if (!this.hasOwnProperty(p)) {
if (this._canApplyPropertyDefault(p)) {
let value = typeof info.value == 'function' ?

@@ -590,2 +622,14 @@ info.value.call(this) :

/**
* Determines if a property dfeault can be applied. For example, this
* prevents a default from being applied when a property that has no
* accessor is overridden by its host before upgrade (e.g. via a binding).
* @override
* @param {string} property Name of the property
* @return {boolean} Returns true if the property default can be applied.
*/
_canApplyPropertyDefault(property) {
return !this.hasOwnProperty(property);
}
/**
* Gather style text for a style element in the template.

@@ -701,2 +745,7 @@ *

n.shadowRoot.appendChild(dom);
// When `adoptedStyleSheets` is supported a stylesheet is made
// available on the element constructor.
if (this.constructor._styleSheet) {
n.shadowRoot.adoptedStyleSheets = [this.constructor._styleSheet];
}
}

@@ -810,3 +859,11 @@ if (syncInitialRender && window.ShadyDOM) {

// shorthand when attribute deserialization is not important.
if (legacyOptimizations && !(prop in this._properties)) {
if (legacyWarnings && !(prop in this._properties) &&
// Methods used in templates with no dependencies (or only literal
// dependencies) become accessors with template effects; ignore these
!(effect.info.part.signature && effect.info.part.signature.static) &&
// Warnings for bindings added to nested templates are handled by
// templatizer so ignore both the host-to-template bindings
// (`hostProp`) and TemplateInstance-to-child bindings
// (`nestedTemplate`)
!effect.info.part.hostProp && !templateInfo.nestedTemplate) {
console.warn(`Property '${prop}' used in template but not declared in 'properties'; ` +

@@ -813,0 +870,0 @@ `attribute will not be observed.`);

@@ -93,3 +93,3 @@ /**

*/
_addPropertyToAttributeMap(property: string): void;
_addPropertyToAttributeMap(property: string): any;

@@ -169,2 +169,8 @@ /**

/**
* @param property Name of the property
* @returns Returns true if the property is pending.
*/
_isPropertyPending(property: string): boolean;
/**
* Marks the properties as invalid, and enqueues an async

@@ -171,0 +177,0 @@ * `_propertiesChanged` callback.

@@ -137,6 +137,14 @@ /**

}
if (!this.__dataAttributes[property]) {
const attr = this.constructor.attributeNameForProperty(property);
// This check is technically not correct; it's an optimization that
// assumes that if a _property_ name is already in the map (note this is
// an attr->property map), the property mapped directly to the attribute
// and it has already been mapped. This would fail if
// `attributeNameForProperty` were overridden such that this was not the
// case.
let attr = this.__dataAttributes[property];
if (!attr) {
attr = this.constructor.attributeNameForProperty(property);
this.__dataAttributes[attr] = property;
}
return attr;
}

@@ -156,7 +164,11 @@

get() {
return this._getProperty(property);
// Inline for perf instead of using `_getProperty`
return this.__data[property];
},
/** @this {PropertiesChanged} */
set: readOnly ? function () {} : function (value) {
this._setProperty(property, value);
// Inline for perf instead of using `_setProperty`
if (this._setPendingProperty(property, value, true)) {
this._invalidateProperties();
}
}

@@ -177,2 +189,5 @@ /* eslint-enable */

this.__dataInstanceProps = null;
/** @type {number} */
// NOTE: used to track re-entrant calls to `_flushProperties`
this.__dataCounter = 0;
this.__serializing = false;

@@ -304,2 +319,10 @@ this._initializeProperties();

/**
* @param {string} property Name of the property
* @return {boolean} Returns true if the property is pending.
*/
_isPropertyPending(property) {
return !!(this.__dataPending && this.__dataPending.hasOwnProperty(property));
}
/**
* Marks the properties as invalid, and enqueues an async

@@ -358,2 +381,3 @@ * `_propertiesChanged` callback.

_flushProperties() {
this.__dataCounter++;
const props = this.__data;

@@ -367,2 +391,3 @@ const changedProps = this.__dataPending;

}
this.__dataCounter--;
}

@@ -369,0 +394,0 @@

@@ -20,4 +20,4 @@ /**

*
* @param {Object} props Properties to normalize
* @return {Object} Copy of input `props` with normalized properties that
* @param {!Object} props Properties to normalize
* @return {!Object} Copy of input `props` with normalized properties that
* are in the form {type: Type}

@@ -126,3 +126,3 @@ * @private

const props = this._properties;
this.__observedAttributes = props ? Object.keys(props).map(p => this.attributeNameForProperty(p)) : [];
this.__observedAttributes = props ? Object.keys(props).map(p => this.prototype._addPropertyToAttributeMap(p)) : [];
}

@@ -129,0 +129,0 @@ return this.__observedAttributes;

@@ -102,2 +102,10 @@ /**

/**
* Returns true if the specified property has a pending change.
*
* @param prop Property name
* @returns True if property has a pending change
*/
_isPropertyPending(prop: string): boolean;
/**
* Overrides PropertiesChanged implemention to serialize objects as JSON.

@@ -156,10 +164,2 @@ *

_hasAccessor(property: string): boolean;
/**
* Returns true if the specified property has a pending change.
*
* @param prop Property name
* @returns True if property has a pending change
*/
_isPropertyPending(prop: string): boolean;
}

@@ -309,3 +309,4 @@ /**

interface PropertyEffects extends TemplateStamp, PropertyAccessors, PropertiesChanged {
readonly PROPERTY_EFFECT_TYPES: {[key: string]: string};
_overrideLegacyUndefined: boolean;
readonly PROPERTY_EFFECT_TYPES: any;

@@ -328,5 +329,8 @@ /**

* @param template Template to stamp
* @param templateInfo Optional bound template info associated
* with the template to be stamped; if omitted the template will be
* automatically bound.
* @returns Cloned template content
*/
_stampTemplate(template: HTMLTemplateElement): StampedTemplate;
_stampTemplate(template: HTMLTemplateElement, templateInfo?: TemplateInfo|null): StampedTemplate;

@@ -404,7 +408,2 @@ /**

/**
* Overrides superclass implementation.
*/
_flushProperties(): void;
/**
* Implements `PropertyAccessors`'s properties changed callback.

@@ -431,2 +430,3 @@ *

_initializeProtoProperties(props: object|null): void;
_registerHost(): void;

@@ -600,2 +600,3 @@ /**

_propagatePropertyChanges(changedProps: object|null, oldProps: object|null, hasPaths: boolean): void;
_runEffectsForTemplate(templateInfo: any, changedProps: any, oldProps: any, hasPaths: any): void;

@@ -739,3 +740,3 @@ /**

*/
splice(path: string|Array<string|number>, start: number, deleteCount?: number, ...items: any[]): any[]|null;
splice(path: string|Array<string|number>, start: number, deleteCount?: number, ...items: any[]): any[];

@@ -850,5 +851,4 @@ /**

/**
* Equivalent to static `bindTemplate` API but can be called on
* an instance to add effects at runtime. See that method for
* full API docs.
* Equivalent to static `bindTemplate` API but can be called on an instance
* to add effects at runtime. See that method for full API docs.
*

@@ -862,10 +862,10 @@ * This method may be called on the prototype (for prototypical template

* @param template Template containing binding
* bindings
* bindings
* @param instanceBinding When false (default), performs
* "prototypical" binding of the template and overwrites any previously
* bound template for the class. When true (as passed from
* `_stampTemplate`), the template info is instanced and linked into
* the list of bound templates.
* "prototypical" binding of the template and overwrites any previously
* bound template for the class. When true (as passed from
* `_stampTemplate`), the template info is instanced and linked into the
* list of bound templates.
* @returns Template metadata object; for `runtimeBinding`,
* this is an instance of the prototypical template info
* this is an instance of the prototypical template info
*/

@@ -872,0 +872,0 @@ _bindTemplate(template: HTMLTemplateElement, instanceBinding?: boolean): TemplateInfo;

@@ -236,5 +236,8 @@ /**

* @param template Template to stamp
* @param templateInfo Optional template info associated
* with the template to be stamped; if omitted the template will be
* automatically parsed.
* @returns Cloned template content
*/
_stampTemplate(template: HTMLTemplateElement): StampedTemplate;
_stampTemplate(template: HTMLTemplateElement, templateInfo?: TemplateInfo|null): StampedTemplate;

@@ -241,0 +244,0 @@ /**

@@ -122,5 +122,7 @@ /**

// push configuration references at configure time
function applyTemplateContent(inst, node, nodeInfo) {
function applyTemplateInfo(inst, node, nodeInfo, parentTemplateInfo) {
if (nodeInfo.templateInfo) {
// Give the node an instance of this templateInfo and set its parent
node._templateInfo = nodeInfo.templateInfo;
node._parentTemplateInfo = parentTemplateInfo;
}

@@ -155,5 +157,2 @@ }

* @summary Element class mixin that provides basic template parsing and stamping
* @template T
* @param {function(new:T)} superClass Class to apply mixin to.
* @return {function(new:T)} superClass with mixin applied.
*/

@@ -257,2 +256,3 @@ export const TemplateStamp = dedupingMixin(

templateInfo.nodeInfoList = [];
templateInfo.nestedTemplate = Boolean(outerTemplateInfo);
templateInfo.stripWhiteSpace =

@@ -311,3 +311,7 @@ (outerTemplateInfo && outerTemplateInfo.stripWhiteSpace) ||

}
return noted;
// Checking `nodeInfo.noted` allows a child node of this node (who gets
// access to `parentInfo`) to cause the parent to be noted, which
// otherwise has no return path via `_parseTemplateChildNodes` (used by
// some optimizations)
return noted || nodeInfo.noted;
}

@@ -491,6 +495,9 @@

* @param {!HTMLTemplateElement} template Template to stamp
* @param {TemplateInfo=} templateInfo Optional template info associated
* with the template to be stamped; if omitted the template will be
* automatically parsed.
* @return {!StampedTemplate} Cloned template content
* @override
*/
_stampTemplate(template) {
_stampTemplate(template, templateInfo) {
// Polyfill support: bootstrap the template if it has not already been

@@ -501,3 +508,6 @@ if (template && !template.content &&

}
let templateInfo = this.constructor._parseTemplate(template);
// Accepting the `templateInfo` via an argument allows for creating
// instances of the `templateInfo` by the caller, useful for adding
// instance-time information to the prototypical data
templateInfo = templateInfo || this.constructor._parseTemplate(template);
let nodeInfo = templateInfo.nodeInfoList;

@@ -513,3 +523,3 @@ let content = templateInfo.content || template.content;

applyIdToMap(this, dom.$, node, info);
applyTemplateContent(this, node, info);
applyTemplateInfo(this, node, info, templateInfo);
applyEventListener(this, node, info);

@@ -516,0 +526,0 @@ }

@@ -30,2 +30,3 @@ /**

let microtaskNodeContent = 0;
let microtaskScheduled = false;
let microtaskNode = document.createTextNode('');

@@ -35,2 +36,3 @@ new window.MutationObserver(microtaskFlush).observe(microtaskNode, {characterData: true});

function microtaskFlush() {
microtaskScheduled = false;
const len = microtaskCallbacks.length;

@@ -186,3 +188,6 @@ for (let i = 0; i < len; i++) {

run(callback) {
microtaskNode.textContent = microtaskNodeContent++;
if (!microtaskScheduled) {
microtaskScheduled = true;
microtaskNode.textContent = microtaskNodeContent++;
}
microtaskCallbacks.push(callback);

@@ -189,0 +194,0 @@ return microtaskCurrHandle++;

@@ -55,9 +55,9 @@ /**

map.set(base, extended);
// copy inherited mixin set from the extended class, or the base class
// NOTE: we avoid use of Set here because some browser (IE11)
// cannot extend a base Set via the constructor.
let mixinSet = Object.create(/** @type {!MixinFunction} */(extended).__mixinSet || baseSet || null);
mixinSet[mixinDedupeId] = true;
/** @type {!MixinFunction} */(extended).__mixinSet = mixinSet;
}
// copy inherited mixin set from the extended class, or the base class
// NOTE: we avoid use of Set here because some browser (IE11)
// cannot extend a base Set via the constructor.
let mixinSet = Object.create(/** @type {!MixinFunction} */(extended).__mixinSet || baseSet || null);
mixinSet[mixinDedupeId] = true;
/** @type {!MixinFunction} */(extended).__mixinSet = mixinSet;
return extended;

@@ -64,0 +64,0 @@ }

@@ -35,2 +35,12 @@ /**

export {getSanitizeDOMValue};
/**
* Gets sanitizeDOMValue, for environments that don't well support `export let`.
*
* @returns sanitizeDOMValue
*/
declare function getSanitizeDOMValue(): ((p0: any, p1: string, p2: string, p3: Node|null) => any)|undefined;
export {setPassiveTouchGestures};

@@ -69,2 +79,10 @@

export {setLegacyWarnings};
/**
* Sets `legacyWarnings` globally for all elements to migration warnings.
*/
declare function setLegacyWarnings(useLegacyWarnings: boolean): void;
export {setSyncInitialRender};

@@ -79,2 +97,20 @@

export {setLegacyUndefined};
/**
* Sets `legacyUndefined` globally for all elements to enable legacy
* multi-property behavior for undefined values.
*/
declare function setLegacyUndefined(useLegacyUndefined: boolean): void;
export {setOrderedComputed};
/**
* Sets `orderedComputed` globally for all elements to enable ordered computed
* property computation.
*/
declare function setOrderedComputed(useOrderedComputed: boolean): void;
export {setCancelSyntheticClickEvents};

@@ -87,1 +123,43 @@

declare function setCancelSyntheticClickEvents(useCancelSyntheticClickEvents: boolean): void;
export {setRemoveNestedTemplates};
/**
* Sets `removeNestedTemplates` globally, to eliminate nested templates
* inside `dom-if` and `dom-repeat` as part of template parsing.
*/
declare function setRemoveNestedTemplates(useRemoveNestedTemplates: boolean): void;
export {setFastDomIf};
/**
* Sets `fastDomIf` globally, to put `dom-if` in a performance-optimized mode.
*/
declare function setFastDomIf(useFastDomIf: boolean): void;
export {setSuppressTemplateNotifications};
/**
* Sets `suppressTemplateNotifications` globally, to disable `dom-change` and
* `rendered-item-count` events from `dom-if` and `dom-repeat`.
*/
declare function setSuppressTemplateNotifications(suppress: boolean): void;
export {setLegacyNoObservedAttributes};
/**
* Sets `legacyNoObservedAttributes` globally, to disable `observedAttributes`.
*/
declare function setLegacyNoObservedAttributes(noObservedAttributes: boolean): void;
export {setUseAdoptedStyleSheetsWithBuiltCSS};
/**
* Sets `useAdoptedStyleSheetsWithBuiltCSS` globally.
*/
declare function setUseAdoptedStyleSheetsWithBuiltCSS(value: boolean): void;

@@ -11,9 +11,23 @@ /**

import './boot.js';
import { pathFromUrl } from './resolve-url.js';
export const useShadow = !(window.ShadyDOM);
export const useShadow = !(window.ShadyDOM) || !(window.ShadyDOM.inUse);
export const useNativeCSSProperties = Boolean(!window.ShadyCSS || window.ShadyCSS.nativeCss);
export const useNativeCustomElements = !(window.customElements.polyfillWrapFlushCallback);
export const supportsAdoptingStyleSheets = useShadow &&
('adoptedStyleSheets' in Document.prototype) &&
('replaceSync' in CSSStyleSheet.prototype) &&
// Since spec may change, feature detect exact API we need
(() => {
try {
const sheet = new CSSStyleSheet();
sheet.replaceSync('');
const host = document.createElement('div');
host.attachShadow({mode: 'open'});
host.shadowRoot.adoptedStyleSheets = [sheet];
return (host.shadowRoot.adoptedStyleSheets[0] === sheet);
} catch(e) {
return false;
}
})();
/**

@@ -27,3 +41,4 @@ * Globally settable property that is automatically assigned to

*/
export let rootPath = pathFromUrl(document.baseURI || window.location.href);
export let rootPath = window.Polymer && window.Polymer.rootPath ||
pathFromUrl(document.baseURI || window.location.href);

@@ -54,5 +69,6 @@ /**

*
* @type {(function(*,string,string,Node):*)|undefined}
* @type {(function(*,string,string,?Node):*)|undefined}
*/
export let sanitizeDOMValue = window.Polymer && window.Polymer.sanitizeDOMValue || undefined;
export let sanitizeDOMValue =
window.Polymer && window.Polymer.sanitizeDOMValue || undefined;

@@ -63,3 +79,3 @@ /**

*
* @param {(function(*,string,string,Node):*)|undefined} newSanitizeDOMValue the global sanitizeDOMValue callback
* @param {(function(*,string,string,?Node):*)|undefined} newSanitizeDOMValue the global sanitizeDOMValue callback
* @return {void}

@@ -72,2 +88,11 @@ */

/**
* Gets sanitizeDOMValue, for environments that don't well support `export let`.
*
* @return {(function(*,string,string,?Node):*)|undefined} sanitizeDOMValue
*/
export const getSanitizeDOMValue = function() {
return sanitizeDOMValue;
};
/**
* Globally settable property to make Polymer Gestures use passive TouchEvent listeners when recognizing gestures.

@@ -78,3 +103,4 @@ * When set to `true`, gestures made from touch will not be able to prevent scrolling, allowing for smoother

*/
export let passiveTouchGestures = false;
export let passiveTouchGestures =
window.Polymer && window.Polymer.setPassiveTouchGestures || false;

@@ -97,3 +123,4 @@ /**

*/
export let strictTemplatePolicy = false;
export let strictTemplatePolicy =
window.Polymer && window.Polymer.strictTemplatePolicy || false;

@@ -117,3 +144,4 @@ /**

*/
export let allowTemplateFromDomModule = false;
export let allowTemplateFromDomModule =
window.Polymer && window.Polymer.allowTemplateFromDomModule || false;

@@ -138,3 +166,4 @@ /**

*/
export let legacyOptimizations = false;
export let legacyOptimizations =
window.Polymer && window.Polymer.legacyOptimizations || false;

@@ -154,6 +183,23 @@ /**

/**
* Setting to add warnings useful when migrating from Polymer 1.x to 2.x.
*/
export let legacyWarnings =
window.Polymer && window.Polymer.legacyWarnings || false;
/**
* Sets `legacyWarnings` globally for all elements to migration warnings.
*
* @param {boolean} useLegacyWarnings enable or disable warnings
* @return {void}
*/
export const setLegacyWarnings = function(useLegacyWarnings) {
legacyWarnings = useLegacyWarnings;
};
/**
* Setting to perform initial rendering synchronously when running under ShadyDOM.
* This matches the behavior of Polymer 1.
*/
export let syncInitialRender = false;
export let syncInitialRender =
window.Polymer && window.Polymer.syncInitialRender || false;

@@ -173,2 +219,40 @@ /**

/**
* Setting to retain the legacy Polymer 1 behavior for multi-property
* observers around undefined values. Observers and computed property methods
* are not called until no argument is undefined.
*/
export let legacyUndefined =
window.Polymer && window.Polymer.legacyUndefined || false;
/**
* Sets `legacyUndefined` globally for all elements to enable legacy
* multi-property behavior for undefined values.
*
* @param {boolean} useLegacyUndefined enable or disable legacy
* multi-property behavior for undefined.
* @return {void}
*/
export const setLegacyUndefined = function(useLegacyUndefined) {
legacyUndefined = useLegacyUndefined;
};
/**
* Setting to ensure computed properties are computed in order to ensure
* re-computation never occurs in a given turn.
*/
export let orderedComputed =
window.Polymer && window.Polymer.orderedComputed || false;
/**
* Sets `orderedComputed` globally for all elements to enable ordered computed
* property computation.
*
* @param {boolean} useOrderedComputed enable or disable ordered computed effects
* @return {void}
*/
export const setOrderedComputed = function(useOrderedComputed) {
orderedComputed = useOrderedComputed;
};
/**
* Setting to cancel synthetic click events fired by older mobile browsers. Modern browsers

@@ -190,1 +274,98 @@ * no longer fire synthetic click events, and the cancellation behavior can interfere

};
/**
* 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 =
window.Polymer && window.Polymer.removeNestedTemplates || false;
/**
* Sets `removeNestedTemplates` globally, to eliminate nested templates
* inside `dom-if` and `dom-repeat` as part of template parsing.
*
* @param {boolean} useRemoveNestedTemplates enable or disable removing nested
* templates during parsing
* @return {void}
*/
export const setRemoveNestedTemplates = function(useRemoveNestedTemplates) {
removeNestedTemplates = useRemoveNestedTemplates;
};
/**
* 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 = window.Polymer && window.Polymer.fastDomIf || false;
/**
* 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;
};
/**
* Setting to disable `dom-change` and `rendered-item-count` events from
* `dom-if` and `dom-repeat`. Users can opt back into `dom-change` events by
* setting the `notify-dom-change` attribute (`notifyDomChange: true` property)
* to `dom-if`/`don-repeat` instances.
*/
export let suppressTemplateNotifications =
window.Polymer && window.Polymer.suppressTemplateNotifications || false;
/**
* Sets `suppressTemplateNotifications` globally, to disable `dom-change` and
* `rendered-item-count` events from `dom-if` and `dom-repeat`.
*
* @param {boolean} suppress enable or disable `suppressTemplateNotifications`
* @return {void}
*/
export const setSuppressTemplateNotifications = function(suppress) {
suppressTemplateNotifications = suppress;
};
/**
* Setting to disable use of dynamic attributes. This is an optimization
* to avoid setting `observedAttributes`. Instead attributes are read
* once at create time and set/removeAttribute are patched.
*/
export let legacyNoObservedAttributes =
window.Polymer && window.Polymer.legacyNoObservedAttributes || false;
/**
* Sets `legacyNoObservedAttributes` globally, to disable `observedAttributes`.
*
* @param {boolean} noObservedAttributes enable or disable `legacyNoObservedAttributes`
* @return {void}
*/
export const setLegacyNoObservedAttributes = function(noObservedAttributes) {
legacyNoObservedAttributes = noObservedAttributes;
};
/**
* Setting to enable use of `adoptedStyleSheets` for sharing style sheets
* between component instances' shadow roots, if the app uses built Shady CSS
* styles.
*/
export let useAdoptedStyleSheetsWithBuiltCSS =
window.Polymer && window.Polymer.useAdoptedStyleSheetsWithBuiltCSS || false;
/**
* Sets `useAdoptedStyleSheetsWithBuiltCSS` globally.
*
* @param {boolean} value enable or disable `useAdoptedStyleSheetsWithBuiltCSS`
* @return {void}
*/
export const setUseAdoptedStyleSheetsWithBuiltCSS = function(value) {
useAdoptedStyleSheetsWithBuiltCSS = value;
};

@@ -19,2 +19,6 @@ /**

export {showHideChildren};
declare function showHideChildren(): void;
declare class TemplateInstanceBase extends

@@ -190,3 +194,3 @@ PropertyEffects(

*/
declare function modelForElement(template: HTMLTemplateElement|null, node?: Node|null): TemplateInstanceBase|null;
declare function modelForElement(template: HTMLElement|null, node?: Node|null): TemplateInstanceBase|null;

@@ -193,0 +197,0 @@ export {TemplateInstanceBase};

@@ -52,3 +52,3 @@ /**

import { MutableData } from '../mixins/mutable-data.js';
import { strictTemplatePolicy } from './settings.js';
import { strictTemplatePolicy, legacyWarnings } from './settings.js';
import { wrap } from './wrap.js';

@@ -106,7 +106,46 @@

*/
const templateInstanceBase = PropertyEffects(
// This cast shouldn't be neccessary, but Closure doesn't understand that
// "class {}" is a constructor function.
/** @type {function(new:Object)} */(class {}));
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);
}
}
}
/**

@@ -217,41 +256,3 @@ * @polymer

_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);
}

@@ -331,5 +332,5 @@ /**

const MutableTemplateInstanceBase = MutableData(
// This cast shouldn't be necessary, but Closure doesn't seem to understand
// this constructor.
/** @type {function(new:TemplateInstanceBase)} */(TemplateInstanceBase));
// This cast shouldn't be neccessary, but Closure doesn't understand that
// TemplateInstanceBase is a constructor function.
/** @type {function(new:TemplateInstanceBase)} */ (TemplateInstanceBase));

@@ -379,19 +380,47 @@ function findMethodHost(template) {

* properties that the host binds to the template using the `_host_` prefix.
*
*
* @suppress {missingProperties} class.prototype is not defined for some reason
*/
function addPropagateEffects(template, templateInfo, options) {
function addPropagateEffects(target, templateInfo, options, methodHost) {
let userForwardHostProp = options.forwardHostProp;
if (userForwardHostProp && templateInfo.hasHostProps) {
// 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) {
/**
* @constructor
* @extends {DataTemplate}
*/
let templatizedBase = options.mutableData ? MutableDataTemplate : DataTemplate;
/** @private */
klass = templateInfo.templatizeTemplateClass =
class TemplatizedTemplate extends templatizedBase {};
if (isTemplate) {
/**
* @constructor
* @extends {DataTemplate}
*/
let templatizedBase =
options.mutableData ? MutableDataTemplate : DataTemplate;
// NOTE: due to https://github.com/google/closure-compiler/issues/2928,
// combining the next two lines into one assignment causes a spurious
// type error.
/** @private */
class TemplatizedTemplate extends templatizedBase {}
klass = templateInfo.templatizeTemplateClass = TemplatizedTemplate;
} else {
/**
* @constructor
* @extends {PolymerElement}
*/
const templatizedBase = target.constructor;
// Create a cached subclass of the base custom element class onto which
// to put the template-specific propagate effects
// NOTE: due to https://github.com/google/closure-compiler/issues/2928,
// combining the next two lines into one assignment causes a spurious
// type error.
/** @private */
class TemplatizedTemplateExtension extends templatizedBase {}
klass = templateInfo.templatizeTemplateClass =
TemplatizedTemplateExtension;
}
// Add template - >instances effects

@@ -406,16 +435,36 @@ // and host <- template effects

}
if (legacyWarnings && methodHost) {
warnOnUndeclaredProperties(templateInfo, options, methodHost);
}
}
upgradeTemplate(template, klass);
// 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);
}
// Clear any pending data for performance
template.__dataTemp = {};
template.__dataPending = null;
template.__dataOld = null;
template._enableProperties();
if (isTemplate) {
upgradeTemplate(target, klass);
// Clear any pending data for performance
target.__dataTemp = {};
target.__dataPending = null;
target.__dataOld = null;
target._enableProperties();
} else {
// Swizzle the cached subclass prototype onto the custom element
Object.setPrototypeOf(target, klass.prototype);
// Check for any pre-bound instance host properties, and do the
// instance property delete/assign dance for those (directly into data;
// not need to go through accessor since they are pulled at instance time)
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;
}
}
}
}

@@ -574,4 +623,5 @@ }

}
const methodHost = findMethodHost(template);
// Host property forwarding must be installed onto template instance
addPropagateEffects(template, templateInfo, options);
addPropagateEffects(template, templateInfo, options, methodHost);
// Subclass base class and add reference for this specific template

@@ -581,3 +631,3 @@ /** @private */

/** @override */
klass.prototype._methodHost = findMethodHost(template);
klass.prototype._methodHost = methodHost;
/** @override */

@@ -593,2 +643,23 @@ klass.prototype.__dataHost = /** @type {!DataTemplate} */ (template);

function warnOnUndeclaredProperties(templateInfo, options, methodHost) {
const declaredProps = methodHost.constructor._properties;
const {propertyEffects} = templateInfo;
const {instanceProps} = options;
for (let prop in propertyEffects) {
// Ensure properties with template effects are declared on the outermost
// host (`methodHost`), unless they are instance props or static functions
if (!declaredProps[prop] && !(instanceProps && instanceProps[prop])) {
const effects = propertyEffects[prop];
for (let i=0; i<effects.length; i++) {
const {part} = effects[i].info;
if (!(part.signature && part.signature.static)) {
console.warn(`Property '${prop}' used in template but not ` +
`declared in 'properties'; attribute will not be observed.`);
break;
}
}
}
}
}
/**

@@ -608,4 +679,6 @@ * Returns the template "model" associated with a given element, which

*
* @param {HTMLTemplateElement} template The model will be returned for
* elements stamped from this template
* @param {HTMLElement} template The model will be returned for
* elements stamped from this template (accepts either an HTMLTemplateElement)
* or a `<dom-if>`/`<dom-repeat>` element when using `removeNestedTemplates`
* optimization.
* @param {Node=} node Node for which to return a template model.

@@ -621,3 +694,3 @@ * @return {TemplateInstanceBase} Template instance representing the

// 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

@@ -624,0 +697,0 @@ // from its __dataHost

{
"name": "@polymer/polymer",
"version": "3.3.1",
"version": "3.4.0",
"description": "The Polymer library makes it easy to create your own web components. Give your element some markup and properties, and then use it on a site. Polymer provides features like dynamic templates and data binding to reduce the amount of boilerplate you need to write",

@@ -5,0 +5,0 @@ "main": "polymer-element.js",

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc