2016-08-11 18:07:41 -07:00
|
|
|
<!--
|
|
|
|
|
@license
|
|
|
|
|
Copyright (c) 2014 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
|
|
|
|
|
-->
|
|
|
|
|
|
2017-02-17 19:18:07 -08:00
|
|
|
<link rel="import" href="../utils/boot.html">
|
|
|
|
|
<link rel="import" href="../utils/mixin.html">
|
|
|
|
|
<link rel="import" href="../utils/case-map.html">
|
|
|
|
|
<link rel="import" href="../utils/style-gather.html">
|
|
|
|
|
<link rel="import" href="../utils/resolve-url.html">
|
2017-02-14 10:25:44 -08:00
|
|
|
<link rel="import" href="../elements/dom-module.html">
|
|
|
|
|
<link rel="import" href="property-effects.html">
|
2016-08-11 18:07:41 -07:00
|
|
|
|
|
|
|
|
<script>
|
2017-02-21 23:23:40 -08:00
|
|
|
/**
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* @polymerMixin
|
|
|
|
|
* @mixes Polymer.PropertyEffects
|
|
|
|
|
* @memberof Polymer
|
|
|
|
|
*/
|
2017-02-17 19:01:20 -08:00
|
|
|
Polymer.ElementMixin = Polymer.dedupingMixin(function(base) {
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-21 23:23:40 -08:00
|
|
|
const polymerElementBase = Polymer.PropertyEffects(base);
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2016-09-01 12:44:48 -07:00
|
|
|
let caseMap = Polymer.CaseMap;
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
/**
|
2017-02-23 19:39:53 -08:00
|
|
|
* Returns the `properties` object specifically on `klass`. Use for:
|
2017-02-15 20:16:03 -08:00
|
|
|
* (1) super chain mixes togther to make `propertiesForClass` which is
|
|
|
|
|
* then used to make `observedAttributes`.
|
|
|
|
|
* (2) properties effects and observers are created from it at `finalize` time.
|
|
|
|
|
* @param {HTMLElement} klass
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2017-02-23 19:39:53 -08:00
|
|
|
function ownPropertiesForClass(klass) {
|
2017-02-15 20:16:03 -08:00
|
|
|
if (!klass.hasOwnProperty(
|
2017-02-23 19:39:53 -08:00
|
|
|
goog.reflect.objectProperty('__ownProperties', klass))) {
|
|
|
|
|
klass.__ownProperties =
|
|
|
|
|
klass.hasOwnProperty(goog.reflect.objectProperty('properties', klass)) ?
|
|
|
|
|
klass.properties : {};
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2017-02-23 19:39:53 -08:00
|
|
|
return klass.__ownProperties;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the `observers` array specifically on `klass`. Use for
|
|
|
|
|
* setting up observers.
|
|
|
|
|
* @param {HTMLElement} klass
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function ownObserversForClass(klass) {
|
|
|
|
|
if (!klass.hasOwnProperty(
|
|
|
|
|
goog.reflect.objectProperty('__ownObservers', klass))) {
|
|
|
|
|
klass.__ownObservers =
|
|
|
|
|
klass.hasOwnProperty(goog.reflect.objectProperty('observers', klass)) ?
|
|
|
|
|
klass.observers : [];
|
|
|
|
|
}
|
|
|
|
|
return klass.__ownObservers;
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Mixes `props` into `flattenedProps` but upgrades shorthand type
|
|
|
|
|
* syntax to { type: Type}.
|
|
|
|
|
* @param {Object} flattenedProps
|
|
|
|
|
* @param {Object} props
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2016-10-21 12:18:32 -07:00
|
|
|
function flattenProperties(flattenedProps, props) {
|
|
|
|
|
for (let p in props) {
|
|
|
|
|
let o = props[p];
|
|
|
|
|
if (typeof o == 'function') {
|
|
|
|
|
o = { type: o };
|
|
|
|
|
}
|
|
|
|
|
flattenedProps[p] = o;
|
|
|
|
|
}
|
|
|
|
|
return flattenedProps;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
/**
|
|
|
|
|
* Returns a flattened list of properties mixed together from the chain of all
|
|
|
|
|
* constructor's `config.properties`. This list is used to create
|
|
|
|
|
* (1) observedAttributes,
|
|
|
|
|
* (2) class property default values
|
|
|
|
|
* @param {HTMLElement} klass
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function propertiesForClass(klass) {
|
|
|
|
|
if (!klass.hasOwnProperty(
|
|
|
|
|
goog.reflect.objectProperty('__classProperties', klass))) {
|
|
|
|
|
klass.__classProperties =
|
2017-02-23 19:39:53 -08:00
|
|
|
flattenProperties({}, ownPropertiesForClass(klass));
|
2017-02-15 20:16:03 -08:00
|
|
|
let superCtor = Object.getPrototypeOf(klass.prototype).constructor;
|
|
|
|
|
if (superCtor.prototype instanceof PolymerElement) {
|
2017-02-17 19:01:20 -08:00
|
|
|
klass.__classProperties = Polymer.mixin(
|
2017-02-15 20:16:03 -08:00
|
|
|
Object.create(propertiesForClass(superCtor)),
|
|
|
|
|
klass.__classProperties);
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
|
|
|
|
return klass.__classProperties;
|
|
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08: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 `propertiesForClass`.
|
|
|
|
|
* This list is used in `_initializeProperties` to set property defaults.
|
|
|
|
|
* @param {HTMLElement} klass
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function propertyDefaultsForClass(klass) {
|
|
|
|
|
if (!klass.hasOwnProperty(
|
|
|
|
|
goog.reflect.objectProperty('__classPropertyDefaults', klass))) {
|
|
|
|
|
this.__classPropertyDefaults = null;
|
|
|
|
|
let props = propertiesForClass(klass);
|
|
|
|
|
for (let p in props) {
|
|
|
|
|
let info = props[p];
|
|
|
|
|
if ('value' in info) {
|
|
|
|
|
klass.__classPropertyDefaults = klass.__classPropertyDefaults || {};
|
|
|
|
|
klass.__classPropertyDefaults[p] = info;
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
|
|
|
|
return klass.__classPropertyDefaults;
|
|
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
/**
|
2017-02-16 17:04:22 -08:00
|
|
|
* Returns true if a `klass` has finalized. Called in `ElementClass.finalize()`
|
2017-02-15 20:16:03 -08:00
|
|
|
* @param {HTMLElement} klass
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function hasClassFinalized(klass) {
|
|
|
|
|
return klass.hasOwnProperty(goog.reflect.objectProperty('__finalized', klass));
|
|
|
|
|
}
|
2017-01-17 11:28:35 -08:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
/**
|
2017-02-16 17:04:22 -08:00
|
|
|
* Called by `ElementClass.finalize()`. Ensures this `klass` and
|
2017-02-15 20:16:03 -08:00
|
|
|
* *all superclasses* are finalized by traversing the prototype chain
|
2017-02-16 17:04:22 -08:00
|
|
|
* and calling `klass.finalize()`.
|
2017-02-15 20:16:03 -08:00
|
|
|
* @param {HTMLElement} klass
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function finalizeClassAndSuper(klass) {
|
|
|
|
|
let proto = klass.prototype;
|
|
|
|
|
let superCtor = Object.getPrototypeOf(proto).constructor;
|
|
|
|
|
if (superCtor.prototype instanceof PolymerElement) {
|
2017-02-16 17:04:22 -08:00
|
|
|
superCtor.finalize();
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2017-02-16 17:04:22 -08:00
|
|
|
finalizeClass(klass);
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2017-01-17 11:28:35 -08:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
/**
|
|
|
|
|
* Configures a `klass` based on a staic `klass.config` object and
|
|
|
|
|
* a `template`. This includes creating accessors and effects
|
|
|
|
|
* for properties in `config` and the `template` as well as preparing the
|
|
|
|
|
* `template` for stamping.
|
|
|
|
|
*/
|
|
|
|
|
function finalizeClass(klass) {
|
|
|
|
|
klass.__finalized = true;
|
|
|
|
|
let proto = klass.prototype;
|
|
|
|
|
if (klass.hasOwnProperty(
|
|
|
|
|
goog.reflect.objectProperty('is', klass)) && klass.is) {
|
|
|
|
|
Polymer.telemetry.register(proto);
|
|
|
|
|
}
|
2017-02-23 19:39:53 -08:00
|
|
|
let props = ownPropertiesForClass(klass);
|
|
|
|
|
if (props) {
|
|
|
|
|
finalizeProperties(proto, props);
|
|
|
|
|
}
|
|
|
|
|
let observers = ownObserversForClass(klass);
|
|
|
|
|
if (observers) {
|
|
|
|
|
finalizeObservers(proto, observers, props);
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2017-02-24 13:17:25 -08:00
|
|
|
// note: create "working" template that is finalized at instance time
|
2017-02-17 19:01:53 -08:00
|
|
|
let template = klass.template;
|
|
|
|
|
if (template) {
|
2017-02-24 13:17:25 -08:00
|
|
|
if (typeof template === 'string') {
|
|
|
|
|
let t = document.createElement('template');
|
|
|
|
|
t.innerHTML = template;
|
|
|
|
|
template = t;
|
|
|
|
|
} else {
|
|
|
|
|
template = template.cloneNode(true);
|
|
|
|
|
}
|
|
|
|
|
proto._template = template;
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
|
|
|
|
}
|
2017-01-17 11:28:35 -08:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
/**
|
2017-02-23 19:39:53 -08:00
|
|
|
* Configures a `proto` based on a `properties` object.
|
2017-02-15 20:16:03 -08:00
|
|
|
* Leverages `PropertyEffects` to create property accessors and effects
|
|
|
|
|
* supporting, observers, reflecting to attributes, change notification,
|
|
|
|
|
* computed properties, and read only properties.
|
|
|
|
|
* @param {HTMLElement} proto
|
2017-02-23 19:39:53 -08:00
|
|
|
* @param {Object} properties
|
2017-02-15 20:16:03 -08:00
|
|
|
* @private
|
|
|
|
|
*/
|
2017-02-23 19:39:53 -08:00
|
|
|
function finalizeProperties(proto, properties) {
|
|
|
|
|
for (let p in properties) {
|
|
|
|
|
createPropertyFromConfig(proto, p, properties[p], properties);
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2017-02-23 19:39:53 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configures a `proto` based on a `observers` array.
|
|
|
|
|
* Leverages `PropertyEffects` to create observers.
|
|
|
|
|
* @param {HTMLElement} proto
|
|
|
|
|
* @param {Array} observers
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function finalizeObservers(proto, observers, dynamicProperties) {
|
|
|
|
|
for (let i=0; i < observers.length; i++) {
|
|
|
|
|
proto._createMethodObserver(observers[i], dynamicProperties);
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08: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.
|
|
|
|
|
*
|
|
|
|
|
* @param {string} name Name of the property.
|
|
|
|
|
* @param {*=} info Info object from which to create property effects.
|
|
|
|
|
* Supported keys:
|
|
|
|
|
*
|
|
|
|
|
* * 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 dersialized to a
|
|
|
|
|
* property named 'fooBar'.
|
|
|
|
|
*
|
|
|
|
|
* * readOnly: {boolean} creates a readOnly property and
|
|
|
|
|
* makes a private setter for the private of the form '_setFoo' for a
|
|
|
|
|
* property 'foo',
|
|
|
|
|
*
|
|
|
|
|
* * 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.
|
|
|
|
|
*
|
|
|
|
|
* * reflectToAttriute: {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'.
|
|
|
|
|
*
|
|
|
|
|
* * 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.
|
|
|
|
|
*
|
|
|
|
|
* * observer: {string} name of a method that runs when the property
|
|
|
|
|
* changes. The arguments of the method are (value, previousValue).
|
|
|
|
|
*
|
|
|
|
|
* @param {HTMLElement} proto
|
|
|
|
|
* @param {string} name
|
|
|
|
|
* @param {object} info
|
2017-02-17 12:01:35 -08:00
|
|
|
* @param {object} props
|
2017-02-15 20:16:03 -08:00
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
/* 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.
|
|
|
|
|
*/
|
2017-02-17 12:01:35 -08:00
|
|
|
function createPropertyFromConfig(proto, name, info, allProps) {
|
2017-02-15 20:16:03 -08:00
|
|
|
// 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)) {
|
2017-02-17 12:01:35 -08:00
|
|
|
proto._createComputedProperty(name, info.computed, allProps);
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
|
|
|
|
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) {
|
2017-02-17 18:55:36 -08:00
|
|
|
proto._createPropertyObserver(name, info.observer, allProps[info.observer]);
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08: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 {HTMLElement} proto
|
|
|
|
|
* @param {HTMLTemplateElement} template
|
|
|
|
|
* @param {string} is
|
|
|
|
|
* @param {string} ext
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function finalizeTemplate(proto, template, is, ext) {
|
|
|
|
|
// support `include="module-name"`
|
2017-02-27 16:54:09 -08:00
|
|
|
let cssText = Polymer.StyleGather.cssFromTemplate(template) +
|
|
|
|
|
Polymer.StyleGather.cssFromModuleImports(is);
|
2017-02-15 20:16:03 -08:00
|
|
|
if (cssText) {
|
|
|
|
|
let style = document.createElement('style');
|
|
|
|
|
style.textContent = cssText;
|
|
|
|
|
template.content.insertBefore(style, template.content.firstChild);
|
|
|
|
|
}
|
2017-02-16 12:24:03 -08:00
|
|
|
if (window.ShadyCSS) {
|
|
|
|
|
window.ShadyCSS.prepareTemplate(template, is, ext);
|
|
|
|
|
}
|
2017-02-17 12:01:35 -08:00
|
|
|
proto._bindTemplate(template, propertiesForClass(proto.constructor));
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
/**
|
2017-02-21 23:23:40 -08:00
|
|
|
* @polymerMixinClass
|
2017-02-15 20:16:03 -08:00
|
|
|
* @unrestricted
|
|
|
|
|
*/
|
2017-02-21 23:23:40 -08:00
|
|
|
class PolymerElement extends polymerElementBase {
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
static get observedAttributes() {
|
|
|
|
|
if (!this.hasOwnProperty(goog.reflect.objectProperty('__observedAttributes', this))) {
|
|
|
|
|
let list = [];
|
|
|
|
|
let properties = propertiesForClass(this);
|
|
|
|
|
for (let prop in properties) {
|
|
|
|
|
list.push(Polymer.CaseMap.camelToDashCase(prop));
|
2016-08-22 18:52:55 -07:00
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
this.__observedAttributes = list;
|
2016-08-22 18:52:55 -07:00
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
return this.__observedAttributes;
|
|
|
|
|
}
|
2016-08-22 18:52:55 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
/**
|
|
|
|
|
* Called automatically when the first element instance is created to
|
|
|
|
|
* ensure that class finalization work has been completed.
|
|
|
|
|
* May be called by users to eagerly perform class finalization work
|
|
|
|
|
* prior to the creation of the first element instance.
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
2017-02-16 17:04:22 -08:00
|
|
|
static finalize() {
|
2017-02-15 20:16:03 -08:00
|
|
|
if (!hasClassFinalized(this)) {
|
|
|
|
|
finalizeClassAndSuper(this);
|
2016-08-15 09:38:20 -07:00
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2016-08-15 09:38:20 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
static get template() {
|
|
|
|
|
if (!this.hasOwnProperty(goog.reflect.objectProperty('_template', this))) {
|
2017-02-16 17:04:22 -08:00
|
|
|
this._template = Polymer.DomModule.import(this.is, 'template') ||
|
2017-02-15 20:16:03 -08:00
|
|
|
// 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(this.prototype).constructor.template;
|
2016-09-02 16:05:16 -07:00
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
return this._template;
|
|
|
|
|
}
|
2016-09-02 16:05:16 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
constructor() {
|
|
|
|
|
super();
|
|
|
|
|
Polymer.telemetry.instanceCount++;
|
2017-02-23 13:10:53 -08:00
|
|
|
// Stamp template
|
|
|
|
|
if (this._template) {
|
|
|
|
|
this.root = this._stampTemplate(this._template);
|
|
|
|
|
} else {
|
|
|
|
|
this.root = this;
|
|
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2016-09-19 19:21:54 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
_initializeProperties() {
|
2017-02-16 17:04:22 -08:00
|
|
|
this.constructor.finalize();
|
2017-02-24 13:17:25 -08:00
|
|
|
// note: finalize template when we have access to `localName` to
|
|
|
|
|
// avoid dependence on `is` for polyfilling styling.
|
|
|
|
|
if (this._template && !this._template.__polymerFinalized) {
|
|
|
|
|
this._template.__polymerFinalized = true;
|
|
|
|
|
finalizeTemplate(this.__proto__, this._template, this.localName);
|
|
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
super._initializeProperties();
|
|
|
|
|
// apply property defaults...
|
|
|
|
|
let p$ = propertyDefaultsForClass(this.constructor);
|
|
|
|
|
if (!p$) {
|
|
|
|
|
return;
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
for (let p in p$) {
|
|
|
|
|
let info = p$[p];
|
|
|
|
|
if (!this._isPropertyPending(p)) {
|
|
|
|
|
var value = typeof info.value == 'function' ?
|
|
|
|
|
info.value.call(this) :
|
|
|
|
|
info.value;
|
2017-02-23 13:10:53 -08:00
|
|
|
if (this._hasPropertyEffect(p)) {
|
2017-02-15 20:16:03 -08:00
|
|
|
this._setProperty(p, value)
|
|
|
|
|
} else {
|
|
|
|
|
this[p] = value;
|
|
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
connectedCallback() {
|
2017-02-16 12:24:03 -08:00
|
|
|
if (window.ShadyCSS) {
|
|
|
|
|
window.ShadyCSS.styleElement(this);
|
|
|
|
|
}
|
2017-02-23 13:10:53 -08:00
|
|
|
this._flushProperties();
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2016-09-12 18:26:08 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
disconnectedCallback() {}
|
|
|
|
|
|
|
|
|
|
ready() {
|
|
|
|
|
super.ready();
|
|
|
|
|
if (this._template) {
|
|
|
|
|
this.root = this._attachDom(this.root);
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
/**
|
|
|
|
|
* Attach 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.
|
|
|
|
|
*
|
|
|
|
|
* @method _attachDom
|
|
|
|
|
* @throws {Error}
|
|
|
|
|
* @suppress {missingReturn}
|
|
|
|
|
* @param {NodeList} dom to attach to the element.
|
|
|
|
|
* @return {Node} node to which the dom has been attached.
|
|
|
|
|
*/
|
|
|
|
|
_attachDom(dom) {
|
|
|
|
|
if (this.attachShadow) {
|
|
|
|
|
if (dom) {
|
|
|
|
|
if (!this.shadowRoot) {
|
|
|
|
|
this.attachShadow({mode: 'open'});
|
2016-12-06 11:03:50 -08:00
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
this.shadowRoot.appendChild(dom);
|
|
|
|
|
return this.shadowRoot;
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
} else {
|
2017-02-15 23:38:05 -08:00
|
|
|
throw new Error('ShadowDOM not available. ' +
|
|
|
|
|
// TODO(sorvell): move to compile-time conditional when supported
|
|
|
|
|
'Polymer.Element can create dom as children instead of in ' +
|
|
|
|
|
'ShadowDOM by setting `this.root = this;\` before \`ready\`.');
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
attributeChangedCallback(name, old, value) {
|
|
|
|
|
if (old !== value) {
|
|
|
|
|
let property = caseMap.dashToCamelCase(name);
|
|
|
|
|
let type = propertiesForClass(this.constructor)[property].type;
|
|
|
|
|
if (!this._hasReadOnlyEffect(property)) {
|
|
|
|
|
this._attributeToProperty(name, value, type);
|
2016-08-26 10:29:44 -07:00
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
/**
|
|
|
|
|
* Update styling for this element
|
|
|
|
|
*
|
|
|
|
|
* @param {Object=} properties
|
|
|
|
|
* Override styling 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.
|
|
|
|
|
*/
|
|
|
|
|
updateStyles(properties) {
|
2017-02-16 12:24:03 -08:00
|
|
|
if (window.ShadyCSS) {
|
|
|
|
|
window.ShadyCSS.styleSubtree(this, properties);
|
|
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
|
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
/**
|
|
|
|
|
* Rewrites a given URL relative to the original location of the document
|
|
|
|
|
* containing the `dom-module` for this element. This method will return
|
|
|
|
|
* the same URL before and after vulcanization.
|
|
|
|
|
*
|
|
|
|
|
* @method resolveUrl
|
|
|
|
|
* @param {string} url URL to resolve.
|
|
|
|
|
* @return {string} Rewritten URL relative to the import
|
|
|
|
|
*/
|
|
|
|
|
resolveUrl(url) {
|
|
|
|
|
const module = Polymer.DomModule.import(this.constructor.is);
|
|
|
|
|
const root = module ? module.assetpath : document.baseURI;
|
|
|
|
|
return Polymer.ResolveUrl.resolveUrl(url, root);
|
|
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
return PolymerElement;
|
|
|
|
|
});
|
2016-08-11 18:07:41 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
// telemetry
|
|
|
|
|
Polymer.telemetry = {
|
|
|
|
|
instanceCount: 0,
|
|
|
|
|
registrations: [],
|
|
|
|
|
_regLog: function(prototype) {
|
|
|
|
|
console.log('[' + prototype.is + ']: registered')
|
|
|
|
|
},
|
|
|
|
|
register: function(prototype) {
|
|
|
|
|
this.registrations.push(prototype);
|
|
|
|
|
Polymer.log && this._regLog(prototype);
|
|
|
|
|
},
|
|
|
|
|
dumpRegistrations: function() {
|
|
|
|
|
this.registrations.forEach(this._regLog);
|
|
|
|
|
}
|
|
|
|
|
};
|
2016-08-26 10:29:44 -07:00
|
|
|
|
2017-02-15 20:16:03 -08:00
|
|
|
Polymer.updateStyles = function(props) {
|
2017-02-16 12:24:03 -08:00
|
|
|
if (window.ShadyCSS) {
|
|
|
|
|
window.ShadyCSS.styleDocument(props);
|
|
|
|
|
}
|
2017-02-15 20:16:03 -08:00
|
|
|
};
|
2016-08-11 18:07:41 -07:00
|
|
|
</script>
|