Files
polymer/lib/mixins/element-mixin.js

746 lines
28 KiB
JavaScript
Raw Normal View History

2018-04-13 16:40:26 -07:00
/**
@license
2017-03-03 16:54:36 -08:00
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
2018-04-13 16:40:26 -07:00
*/
import '../utils/boot.js';
import { rootPath as rootPath$0 } from '../utils/settings.js';
import { dedupingMixin } from '../utils/mixin.js';
import { stylesFromTemplate, stylesFromModuleImports } from '../utils/style-gather.js';
import { pathFromUrl, resolveCss, resolveUrl as resolveUrl$0 } from '../utils/resolve-url.js';
import { DomModule } from '../elements/dom-module.js';
import { PropertyEffects } from './property-effects.js';
import { PropertiesMixin } from './properties-mixin.js';
/**
* Element class mixin that provides the core API for Polymer's meta-programming
* features including template stamping, data-binding, attribute deserialization,
* and property change observation.
*
* Subclassers may provide the following static getters to return metadata
* used to configure Polymer's features for the class:
*
* - `static get is()`: When the template is provided via a `dom-module`,
* users should return the `dom-module` id from a static `is` getter. If
* no template is needed or the template is provided directly via the
* `template` getter, there is no need to define `is` for the element.
*
* - `static get template()`: Users may provide the template directly (as
* opposed to via `dom-module`) by implementing a static `template` getter.
* The getter must return an `HTMLTemplateElement`.
2018-04-13 16:40:26 -07:00
*
* - `static get properties()`: Should return an object describing
* property-related metadata used by Polymer features (key: property name
* value: object containing property metadata). Valid keys in per-property
* metadata include:
* - `type` (String|Number|Object|Array|...): Used by
* `attributeChangedCallback` to determine how string-based attributes
* are deserialized to JavaScript property values.
* - `notify` (boolean): Causes a change in the property to fire a
* non-bubbling event called `<property>-changed`. Elements that have
* enabled two-way binding to the property use this event to observe changes.
* - `readOnly` (boolean): Creates a getter for the property, but no setter.
* To set a read-only property, use the private setter method
* `_setProperty(property, value)`.
* - `observer` (string): Observer method name that will be called when
* the property changes. The arguments of the method are
* `(value, previousValue)`.
* - `computed` (string): String describing method and dependent properties
* for computing the value of this property (e.g. `'computeFoo(bar, zot)'`).
* Computed properties are read-only by default and can only be changed
* via the return value of the computing method.
*
* - `static get observers()`: Array of strings describing multi-property
* observer methods and their dependent properties (e.g.
* `'observeABC(a, b, c)'`).
*
* The base class provides default implementations for the following standard
* custom element lifecycle callbacks; users may override these, but should
* call the super method to ensure
* - `constructor`: Run when the element is created or upgraded
* - `connectedCallback`: Run each time the element is connected to the
* document
* - `disconnectedCallback`: Run each time the element is disconnected from
* the document
* - `attributeChangedCallback`: Run each time an attribute in
* `observedAttributes` is set or removed (note: this element's default
* `observedAttributes` implementation will automatically return an array
* of dash-cased attributes based on `properties`)
*
* @mixinFunction
* @polymer
* @appliesMixin PropertyEffects
* @appliesMixin PropertiesMixin
* @property rootPath {string} Set to the value of `rootPath`,
2018-04-13 16:40:26 -07:00
* which defaults to the main document path
* @property importPath {string} Set to the value of the class's static
* `importPath` property, which defaults to the path of this element's
* `dom-module` (when `is` is used), but can be overridden for other
* import strategies.
* @summary Element class mixin that provides the core API for Polymer's
* meta-programming features.
*/
export const ElementMixin = dedupingMixin(base => {
2018-04-13 16:40:26 -07:00
/**
* @constructor
* @extends {base}
* @implements {Polymer_PropertyEffects}
* @implements {Polymer_PropertiesMixin}
*/
const polymerElementBase = PropertiesMixin(PropertyEffects(base));
2018-04-13 16:40:26 -07:00
/**
* Returns a list of properties with default values.
* This list is created as an optimization since it is a subset of
* the list returned from `_properties`.
* This list is used in `_initializeProperties` to set property defaults.
*
* @param {PolymerElementConstructor} constructor Element class
* @return {PolymerElementProperties} Flattened properties for this class
* that have default values
* @private
*/
function propertyDefaults(constructor) {
if (!constructor.hasOwnProperty(
JSCompiler_renameProperty('__propertyDefaults', constructor))) {
constructor.__propertyDefaults = null;
let props = constructor._properties;
for (let p in props) {
let info = props[p];
if ('value' in info) {
constructor.__propertyDefaults = constructor.__propertyDefaults || {};
constructor.__propertyDefaults[p] = info;
}
}
}
return constructor.__propertyDefaults;
}
/**
* Returns a memoized version of the the `observers` array.
* @param {PolymerElementConstructor} constructor Element class
* @return {Array} Array containing own observers for the given class
* @protected
*/
function ownObservers(constructor) {
if (!constructor.hasOwnProperty(
JSCompiler_renameProperty('__ownObservers', constructor))) {
constructor.__ownObservers =
constructor.hasOwnProperty(JSCompiler_renameProperty('observers', constructor)) ?
/** @type {PolymerElementConstructor} */ (constructor).observers : null;
}
return constructor.__ownObservers;
}
/**
2018-04-13 16:40:26 -07:00
* Creates effects for a property.
*
* Note, once a property has been set to
* `readOnly`, `computed`, `reflectToAttribute`, or `notify`
* these values may not be changed. For example, a subclass cannot
* alter these settings. However, additional `observers` may be added
* by subclasses.
*
* The info object should may contain property metadata as follows:
*
2018-04-13 16:40:26 -07:00
* * `type`: {function} type to which an attribute matching the property
* is deserialized. Note the property is camel-cased from a dash-cased
* attribute. For example, 'foo-bar' attribute is deserialized to a
* property named 'fooBar'.
2017-02-28 16:19:24 -08:00
*
2018-04-13 16:40:26 -07:00
* * `readOnly`: {boolean} creates a readOnly property and
* makes a private setter for the private of the form '_setFoo' for a
* property 'foo',
2017-02-28 16:19:24 -08:00
*
2018-04-13 16:40:26 -07:00
* * `computed`: {string} creates a computed property. A computed property
* also automatically is set to `readOnly: true`. The value is calculated
* by running a method and arguments parsed from the given string. For
* example 'compute(foo)' will compute a given property when the
* 'foo' property changes by executing the 'compute' method. This method
* must return the computed value.
2017-02-28 16:19:24 -08:00
*
2018-04-13 16:40:26 -07:00
* * `reflectToAttribute`: {boolean} If true, the property value is reflected
* to an attribute of the same name. Note, the attribute is dash-cased
* so a property named 'fooBar' is reflected as 'foo-bar'.
2017-02-28 16:19:24 -08:00
*
2018-04-13 16:40:26 -07:00
* * `notify`: {boolean} sends a non-bubbling notification event when
* the property changes. For example, a property named 'foo' sends an
* event named 'foo-changed' with `event.detail` set to the value of
* the property.
2017-02-28 16:19:24 -08:00
*
2018-04-13 16:40:26 -07:00
* * observer: {string} name of a method that runs when the property
* changes. The arguments of the method are (value, previousValue).
2017-02-28 16:19:24 -08:00
*
2018-04-13 16:40:26 -07:00
* Note: Users may want control over modifying property
* effects via subclassing. For example, a user might want to make a
* reflectToAttribute property not do so in a subclass. We've chosen to
* disable this because it leads to additional complication.
* For example, a readOnly effect generates a special setter. If a subclass
* disables the effect, the setter would fail unexpectedly.
* Based on feedback, we may want to try to make effects more malleable
* and/or provide an advanced api for manipulating them.
* Also consider adding warnings when an effect cannot be changed.
*
* @param {!PolymerElement} proto Element class prototype to add accessors
* and effects to
* @param {string} name Name of the property.
* @param {Object} info Info object from which to create property effects.
* Supported keys:
* @param {Object} allProps Flattened map of all properties defined in this
* element (including inherited properties)
* @return {void}
* @private
*/
function createPropertyFromConfig(proto, name, info, allProps) {
// computed forces readOnly...
if (info.computed) {
info.readOnly = true;
}
// Note, since all computed properties are readOnly, this prevents
// adding additional computed property effects (which leads to a confusing
// setup where multiple triggers for setting a property)
// While we do have `hasComputedEffect` this is set on the property's
// dependencies rather than itself.
if (info.computed && !proto._hasReadOnlyEffect(name)) {
proto._createComputedProperty(name, info.computed, allProps);
}
if (info.readOnly && !proto._hasReadOnlyEffect(name)) {
proto._createReadOnlyProperty(name, !info.computed);
}
if (info.reflectToAttribute && !proto._hasReflectEffect(name)) {
proto._createReflectedProperty(name);
}
if (info.notify && !proto._hasNotifyEffect(name)) {
proto._createNotifyingProperty(name);
}
// always add observer
if (info.observer) {
proto._createPropertyObserver(name, info.observer, allProps[info.observer]);
}
// always create the mapping from attribute back to property for deserialization.
proto._addPropertyToAttributeMap(name);
}
/**
* Process all style elements in the element template. Styles with the
* `include` attribute are processed such that any styles in
* the associated "style modules" are included in the element template.
* @param {PolymerElementConstructor} klass Element class
* @param {!HTMLTemplateElement} template Template to process
* @param {string} is Name of element
* @param {string} baseURI Base URI for element
* @private
*/
function processElementStyles(klass, template, is, baseURI) {
const templateStyles = template.content.querySelectorAll('style');
const stylesWithImports = stylesFromTemplate(template);
// insert styles from <link rel="import" type="css"> at the top of the template
const linkedStyles = stylesFromModuleImports(is);
const firstTemplateChild = template.content.firstElementChild;
for (let idx = 0; idx < linkedStyles.length; idx++) {
let s = linkedStyles[idx];
s.textContent = klass._processStyleText(s.textContent, baseURI);
template.content.insertBefore(s, firstTemplateChild);
}
// keep track of the last "concrete" style in the template we have encountered
let templateStyleIndex = 0;
// ensure all gathered styles are actually in this template.
for (let i = 0; i < stylesWithImports.length; i++) {
let s = stylesWithImports[i];
let templateStyle = templateStyles[templateStyleIndex];
// if the style is not in this template, it's been "included" and
// we put a clone of it in the template before the style that included it
if (templateStyle !== s) {
s = s.cloneNode(true);
templateStyle.parentNode.insertBefore(s, templateStyle);
} else {
templateStyleIndex++;
}
s.textContent = klass._processStyleText(s.textContent, baseURI);
}
if (window.ShadyCSS) {
window.ShadyCSS.prepareTemplate(template, is);
}
}
/**
* @polymer
2018-04-13 16:40:26 -07:00
* @mixinClass
* @unrestricted
* @implements {Polymer_ElementMixin}
*/
2018-04-13 16:40:26 -07:00
class PolymerElement extends polymerElementBase {
2017-03-29 15:52:01 -07:00
/**
2018-04-13 16:40:26 -07:00
* Override of PropertiesMixin _finalizeClass to create observers and
* find the template.
* @return {void}
* @protected
* @override
* @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do
2017-03-29 15:52:01 -07:00
*/
2018-04-13 16:40:26 -07:00
static _finalizeClass() {
super._finalizeClass();
if (this.hasOwnProperty(
JSCompiler_renameProperty('is', this)) && this.is) {
register(this.prototype);
}
const observers = ownObservers(this);
if (observers) {
this.createObservers(observers, this._properties);
}
// note: create "working" template that is finalized at instance time
let template = /** @type {PolymerElementConstructor} */ (this).template;
if (template) {
if (typeof template === 'string') {
console.error('template getter must return HTMLTemplateElement');
template = null;
2018-04-13 16:40:26 -07:00
} else {
template = template.cloneNode(true);
}
}
this.prototype._template = template;
}
/**
2018-04-13 16:40:26 -07:00
* Override of PropertiesChanged createProperties to create accessors
* and property effects for all of the properties.
* @return {void}
* @protected
* @override
*/
2018-04-13 16:40:26 -07:00
static createProperties(props) {
for (let p in props) {
createPropertyFromConfig(this.prototype, p, props[p], props);
}
}
/**
2018-04-13 16:40:26 -07:00
* Creates observers for the given `observers` array.
* Leverages `PropertyEffects` to create observers.
* @param {Object} observers Array of observer descriptors for
* this class
* @param {Object} dynamicFns Object containing keys for any properties
* that are functions and should trigger the effect when the function
* reference is changed
* @return {void}
* @protected
*/
2018-04-13 16:40:26 -07:00
static createObservers(observers, dynamicFns) {
const proto = this.prototype;
for (let i=0; i < observers.length; i++) {
proto._createMethodObserver(observers[i], dynamicFns);
}
}
/**
2018-04-13 16:40:26 -07:00
* Returns the template that will be stamped into this element's shadow root.
*
2018-04-13 16:40:26 -07:00
* 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`.
*
2018-04-13 16:40:26 -07:00
* Users may override this getter to return an arbitrary template
* (in which case the `is` getter is unnecessary). The template returned
* must be an `HTMLTemplateElement`.
*
2018-04-13 16:40:26 -07:00
* Note that when subclassing, if the super class overrode the default
* implementation and the subclass would like to provide an alternate
* template via a `dom-module`, it should override this getter and
* return `DomModule.import(this.is, 'template')`.
*
2018-04-13 16:40:26 -07:00
* If a subclass would like to modify the super class template, it should
* clone it rather than modify it in place. If the getter does expensive
* work such as cloning/modifying a template, it should memoize the
* template for maximum performance:
*
2018-04-13 16:40:26 -07:00
* let memoizedTemplate;
* class MySubClass extends MySuperClass {
* static get template() {
* if (!memoizedTemplate) {
* memoizedTemplate = super.template.cloneNode(true);
* let subContent = document.createElement('div');
* subContent.textContent = 'This came from MySubClass';
* memoizedTemplate.content.appendChild(subContent);
* }
* return memoizedTemplate;
* }
* }
*
2018-04-13 16:40:26 -07:00
* @return {HTMLTemplateElement|string} Template to be stamped
*/
2018-04-13 16:40:26 -07:00
static get template() {
if (!this.hasOwnProperty(JSCompiler_renameProperty('_template', this))) {
this._template = DomModule && DomModule.import(
/** @type {PolymerElementConstructor}*/ (this).is, 'template') ||
// note: implemented so a subclass can retrieve the super
// template; call the super impl this way so that `this` points
// to the superclass.
Object.getPrototypeOf(/** @type {PolymerElementConstructor}*/ (this).prototype).constructor.template;
}
2018-04-13 16:40:26 -07:00
return this._template;
}
2016-08-15 09:38:20 -07:00
/**
2018-04-13 16:40:26 -07:00
* Path matching the url from which the element was imported.
*
* This path is used to resolve url's in template style cssText.
* The `importPath` property is also set on element instances and can be
* used to create bindings relative to the import path.
*
* For elements defined in ES modules, users should implement
2018-04-13 16:40:26 -07:00
* `static get importMeta() { return import.meta; }`, and the default
* implementation of `importPath` will return `import.meta.url`'s path.
* For elements defined in HTML imports, this getter will return the path
* to the document containing a `dom-module` element matching this
* element's static `is` property.
*
* Note, this path should contain a trailing `/`.
*
* @return {string} The import path for this element class
* @suppress {missingProperties}
*/
2018-04-13 16:40:26 -07:00
static get importPath() {
if (!this.hasOwnProperty(JSCompiler_renameProperty('_importPath', this))) {
const meta = this.importMeta;
if (meta) {
this._importPath = pathFromUrl(meta.url);
} else {
2018-04-13 16:40:26 -07:00
const module = DomModule && DomModule.import(/** @type {PolymerElementConstructor} */ (this).is);
this._importPath = (module && module.assetpath) ||
2018-04-13 16:40:26 -07:00
Object.getPrototypeOf(/** @type {PolymerElementConstructor}*/ (this).prototype).constructor.importPath;
}
}
2018-04-13 16:40:26 -07:00
return this._importPath;
}
constructor() {
super();
/** @type {HTMLTemplateElement} */
this._template;
/** @type {string} */
this._importPath;
/** @type {string} */
this.rootPath;
/** @type {string} */
this.importPath;
/** @type {StampedTemplate | HTMLElement | ShadowRoot} */
this.root;
/** @type {!Object<string, !Element>} */
this.$;
}
/**
* Overrides the default `PropertyAccessors` to ensure class
2018-04-13 16:40:26 -07:00
* metaprogramming related to property accessors and effects has
* completed (calls `finalize`).
*
* It also initializes any property defaults provided via `value` in
* `properties` metadata.
*
* @return {void}
* @override
* @suppress {invalidCasts}
*/
2018-04-13 16:40:26 -07:00
_initializeProperties() {
instanceCount++;
this.constructor.finalize();
// note: finalize template when we have access to `localName` to
// avoid dependence on `is` for polyfilling styling.
this.constructor._finalizeTemplate(/** @type {!HTMLElement} */(this).localName);
super._initializeProperties();
// set path defaults
this.rootPath = rootPath$0;
this.importPath = this.constructor.importPath;
// apply property defaults...
let p$ = propertyDefaults(this.constructor);
if (!p$) {
return;
}
2018-04-13 16:40:26 -07:00
for (let p in p$) {
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)) {
let value = typeof info.value == 'function' ?
info.value.call(this) :
info.value;
// Set via `_setProperty` if there is an accessor, to enable
// initializing readOnly property defaults
if (this._hasAccessor(p)) {
this._setPendingProperty(p, value, true);
} else {
2018-04-13 16:40:26 -07:00
this[p] = value;
}
}
}
2018-04-13 16:40:26 -07:00
}
2018-04-13 16:40:26 -07:00
/**
* Gather style text for a style element in the template.
*
* @param {string} cssText Text containing styling to process
* @param {string} baseURI Base URI to rebase CSS paths against
* @return {string} The processed CSS text
* @protected
*/
static _processStyleText(cssText, baseURI) {
return resolveCss(cssText, baseURI);
}
2018-04-13 16:40:26 -07:00
/**
* Configures an element `proto` to function with a given `template`.
* The element name `is` and extends `ext` must be specified for ShadyCSS
* style scoping.
*
* @param {string} is Tag name (or type extension name) for this element
* @return {void}
* @protected
*/
static _finalizeTemplate(is) {
/** @const {HTMLTemplateElement} */
const template = this.prototype._template;
if (template && !template.__polymerFinalized) {
template.__polymerFinalized = true;
const importPath = this.importPath;
const baseURI = importPath ? resolveUrl$0(importPath) : '';
// e.g. support `include="module-name"`, and ShadyCSS
processElementStyles(this, template, is, baseURI);
this.prototype._bindTemplate(template);
}
2018-04-13 16:40:26 -07:00
}
2018-04-13 16:40:26 -07:00
/**
* Provides a default implementation of the standard Custom Elements
* `connectedCallback`.
*
* The default implementation enables the property effects system and
* flushes any pending properties, and updates shimmed CSS properties
* when using the ShadyCSS scoping/custom properties polyfill.
*
* @suppress {missingProperties, invalidCasts} Super may or may not implement the callback
* @return {void}
*/
connectedCallback() {
if (window.ShadyCSS && this._template) {
window.ShadyCSS.styleElement(/** @type {!HTMLElement} */(this));
}
2018-04-13 16:40:26 -07:00
super.connectedCallback();
}
2018-04-13 16:40:26 -07:00
/**
* Stamps the element template.
*
* @return {void}
* @override
*/
ready() {
if (this._template) {
this.root = this._stampTemplate(this._template);
this.$ = this.root.$;
}
2018-04-13 16:40:26 -07:00
super.ready();
}
2018-04-13 16:40:26 -07:00
/**
* Implements `PropertyEffects`'s `_readyClients` call. Attaches
* element dom by calling `_attachDom` with the dom stamped from the
* element's template via `_stampTemplate`. Note that this allows
* client dom to be attached to the element prior to any observers
* running.
*
* @return {void}
* @override
*/
_readyClients() {
if (this._template) {
this.root = this._attachDom(/** @type {StampedTemplate} */(this.root));
}
2018-04-13 16:40:26 -07:00
// The super._readyClients here sets the clients initialized flag.
// We must wait to do this until after client dom is created/attached
// so that this flag can be checked to prevent notifications fired
// during this process from being handled before clients are ready.
super._readyClients();
}
2018-04-13 16:40:26 -07:00
/**
* Attaches an element's stamped dom to itself. By default,
* this method creates a `shadowRoot` and adds the dom to it.
* However, this method may be overridden to allow an element
* to put its dom in another location.
*
* @throws {Error}
* @suppress {missingReturn}
* @param {StampedTemplate} dom to attach to the element.
* @return {ShadowRoot} node to which the dom has been attached.
*/
_attachDom(dom) {
if (this.attachShadow) {
if (dom) {
if (!this.shadowRoot) {
this.attachShadow({mode: 'open'});
}
2018-04-13 16:40:26 -07:00
this.shadowRoot.appendChild(dom);
return this.shadowRoot;
}
2018-04-13 16:40:26 -07:00
return null;
} else {
throw new Error('ShadowDOM not available. ' +
// TODO(sorvell): move to compile-time conditional when supported
'PolymerElement can create dom as children instead of in ' +
2018-04-13 16:40:26 -07:00
'ShadowDOM by setting `this.root = this;\` before \`ready\`.');
}
}
2017-02-28 17:07:32 -08:00
/**
2018-04-13 16:40:26 -07:00
* When using the ShadyCSS scoping and custom property shim, causes all
* shimmed styles in this element (and its subtree) to be updated
* based on current custom property values.
*
* The optional parameter overrides inline custom property styles with an
* object of properties where the keys are CSS properties, and the values
* are strings.
*
* Example: `this.updateStyles({'--color': 'blue'})`
*
* These properties are retained unless a value of `null` is set.
*
* Note: This function does not support updating CSS mixins.
* You can not dynamically change the value of an `@apply`.
*
* @param {Object=} properties Bag of custom property key/values to
* apply to this element.
* @return {void}
* @suppress {invalidCasts}
2017-02-28 17:07:32 -08:00
*/
2018-04-13 16:40:26 -07:00
updateStyles(properties) {
if (window.ShadyCSS) {
window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */(this), properties);
}
}
2017-02-28 17:07:32 -08:00
/**
2018-04-13 16:40:26 -07:00
* Rewrites a given URL relative to a base URL. The base URL defaults to
* the original location of the document containing the `dom-module` for
* this element. This method will return the same URL before and after
* bundling.
*
* Note that this function performs no resolution for URLs that start
* with `/` (absolute URLs) or `#` (hash identifiers). For general purpose
* URL resolution, use `window.URL`.
*
* @param {string} url URL to resolve.
* @param {string=} base Optional base URL to resolve against, defaults
* to the element's `importPath`
* @return {string} Rewritten URL relative to base
2017-02-28 17:07:32 -08:00
*/
2018-04-13 16:40:26 -07:00
resolveUrl(url, base) {
if (!base && this.importPath) {
base = resolveUrl$0(this.importPath);
}
return resolveUrl$0(url, base);
}
2018-04-13 16:40:26 -07:00
/**
* Overrides `PropertyAccessors` to add map of dynamic functions on
* template info, for consumption by `PropertyEffects` template binding
* code. This map determines which method templates should have accessors
* created for them.
*
* @override
* @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do
*/
static _parseTemplateContent(template, templateInfo, nodeInfo) {
templateInfo.dynamicFns = templateInfo.dynamicFns || this._properties;
return super._parseTemplateContent(template, templateInfo, nodeInfo);
}
2018-04-13 16:40:26 -07:00
}
return PolymerElement;
});
/**
* Provides basic tracking of element definitions (registrations) and
* instance counts.
*
* @summary Provides basic tracking of element definitions (registrations) and
* instance counts.
*/
`TODO(modulizer): A namespace named Polymer.telemetry was
declared here. The surrounding comments should be reviewed,
and this string can then be deleted`;
/**
* Total number of Polymer element instances created.
* @type {number}
*/
export let instanceCount = 0;
/**
* Array of Polymer element classes that have been finalized.
* @type {Array<PolymerElement>}
2018-04-13 16:40:26 -07:00
*/
export const registrations = [];
/**
* @param {!PolymerElementConstructor} prototype Element prototype to log
* @this {this}
* @private
*/
function _regLog(prototype) {
2018-04-13 16:40:26 -07:00
console.log('[' + prototype.is + ']: registered');
}
/**
* Registers a class prototype for telemetry purposes.
* @param {HTMLElement} prototype Element prototype to register
* @this {this}
* @protected
*/
export function register(prototype) {
registrations.push(prototype);
undefined && _regLog(prototype);
}
/**
* Logs all elements registered with an `is` to the console.
* @public
* @this {this}
*/
export function dumpRegistrations() {
registrations.forEach(_regLog);
}
/**
* When using the ShadyCSS scoping and custom property shim, causes all
* shimmed `styles` (via `custom-style`) in the document (and its subtree)
* to be updated based on current custom property values.
*
* The optional parameter overrides inline custom property styles with an
* object of properties where the keys are CSS properties, and the values
* are strings.
*
* Example: `updateStyles({'--color': 'blue'})`
2018-04-13 16:40:26 -07:00
*
* These properties are retained unless a value of `null` is set.
*
* @param {Object=} props Bag of custom property key/values to
* apply to the document.
* @return {void}
*/
export const updateStyles = function(props) {
if (window.ShadyCSS) {
window.ShadyCSS.styleDocument(props);
}
};