231 lines
7.8 KiB
HTML
231 lines
7.8 KiB
HTML
<!--
|
|
@license
|
|
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
|
|
-->
|
|
|
|
<link rel="import" href="../utils/boot.html">
|
|
<link rel="import" href="../utils/mixin.html">
|
|
<link rel="import" href="../mixins/properties-changed.html">
|
|
|
|
<script>
|
|
(function() {
|
|
'use strict';
|
|
|
|
/**
|
|
* Creates a copy of `props` with each property normalized such that
|
|
* upgraded it is an object with at least a type property { type: Type}.
|
|
*
|
|
* @param {Object} props Properties to normalize
|
|
* @return {Object} Copy of input `props` with normalized properties that
|
|
* are in the form {type: Type}
|
|
* @private
|
|
*/
|
|
function normalizeProperties(props) {
|
|
const output = {};
|
|
for (let p in props) {
|
|
const o = props[p];
|
|
output[p] = (typeof o === 'function') ? {type: o} : o;
|
|
}
|
|
return output;
|
|
}
|
|
|
|
/**
|
|
* Mixin that provides a minimal starting point to using the PropertiesChanged
|
|
* mixin by providing a mechanism to declare properties in a static
|
|
* getter (e.g. static get properties() { return { foo: String } }). Changes
|
|
* are reported via the `_propertiesChanged` method.
|
|
*
|
|
* This mixin provides no specific support for rendering. Users are expected
|
|
* to create a ShadowRoot and put content into it and update it in whatever
|
|
* way makes sense. This can be done in reaction to properties changing by
|
|
* implementing `_propertiesChanged`.
|
|
*
|
|
* @mixinFunction
|
|
* @polymer
|
|
* @appliesMixin Polymer.PropertiesChanged
|
|
* @memberof Polymer
|
|
* @summary Mixin that provides a minimal starting point for using
|
|
* the PropertiesChanged mixin by providing a declarative `properties` object.
|
|
*/
|
|
Polymer.PropertiesMixin = Polymer.dedupingMixin(superClass => {
|
|
|
|
/**
|
|
* @constructor
|
|
* @extends {superClass}
|
|
* @implements {Polymer_PropertiesChanged}
|
|
*/
|
|
const base = Polymer.PropertiesChanged(superClass);
|
|
|
|
/**
|
|
* Returns the super class constructor for the given class, if it is an
|
|
* instance of the PropertiesMixin.
|
|
*
|
|
* @param {!PropertiesMixinConstructor} constructor PropertiesMixin constructor
|
|
* @return {PropertiesMixinConstructor} Super class constructor
|
|
*/
|
|
function superPropertiesClass(constructor) {
|
|
const superCtor = Object.getPrototypeOf(constructor);
|
|
|
|
// Note, the `PropertiesMixin` class below only refers to the class
|
|
// generated by this call to the mixin; the instanceof test only works
|
|
// because the mixin is deduped and guaranteed only to apply once, hence
|
|
// all constructors in a proto chain will see the same `PropertiesMixin`
|
|
return (superCtor.prototype instanceof PropertiesMixin) ?
|
|
/** @type {PropertiesMixinConstructor} */ (superCtor) : null;
|
|
}
|
|
|
|
/**
|
|
* Returns a memoized version of the `properties` object for the
|
|
* given class. Properties not in object format are converted to at
|
|
* least {type}.
|
|
*
|
|
* @param {PropertiesMixinConstructor} constructor PropertiesMixin constructor
|
|
* @return {Object} Memoized properties object
|
|
*/
|
|
function ownProperties(constructor) {
|
|
if (!constructor.hasOwnProperty(JSCompiler_renameProperty('__ownProperties', constructor))) {
|
|
let props = null;
|
|
|
|
if (constructor.hasOwnProperty(JSCompiler_renameProperty('properties', constructor)) && constructor.properties) {
|
|
props = normalizeProperties(constructor.properties);
|
|
}
|
|
|
|
constructor.__ownProperties = props;
|
|
}
|
|
return constructor.__ownProperties;
|
|
}
|
|
|
|
/**
|
|
* @polymer
|
|
* @mixinClass
|
|
* @extends {base}
|
|
* @implements {Polymer_PropertiesMixin}
|
|
* @unrestricted
|
|
*/
|
|
class PropertiesMixin extends base {
|
|
|
|
/**
|
|
* Implements standard custom elements getter to observes the attributes
|
|
* listed in `properties`.
|
|
* @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do
|
|
*/
|
|
static get observedAttributes() {
|
|
const props = this._properties;
|
|
return props ? Object.keys(props).map(p => this.attributeNameForProperty(p)) : [];
|
|
}
|
|
|
|
/**
|
|
* Finalizes an element definition, including ensuring any super classes
|
|
* are also finalized. This includes ensuring property
|
|
* accessors exist on the element prototype. This method calls
|
|
* `_finalizeClass` to finalize each constructor in the prototype chain.
|
|
* @return {void}
|
|
*/
|
|
static finalize() {
|
|
if (!this.hasOwnProperty(JSCompiler_renameProperty('__finalized', this))) {
|
|
const superCtor = superPropertiesClass(/** @type {PropertiesMixinConstructor} */(this));
|
|
if (superCtor) {
|
|
superCtor.finalize();
|
|
}
|
|
this.__finalized = true;
|
|
this._finalizeClass();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finalize an element class. This includes ensuring property
|
|
* accessors exist on the element prototype. This method is called by
|
|
* `finalize` and finalizes the class constructor.
|
|
*
|
|
* @protected
|
|
*/
|
|
static _finalizeClass() {
|
|
const props = ownProperties(/** @type {PropertiesMixinConstructor} */(this));
|
|
if (props) {
|
|
this.createProperties(props);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a memoized version of all properties, including those inherited
|
|
* from super classes. Properties not in object format are converted to
|
|
* at least {type}.
|
|
*
|
|
* @return {Object} Object containing properties for this class
|
|
* @protected
|
|
*/
|
|
static get _properties() {
|
|
if (!this.hasOwnProperty(
|
|
JSCompiler_renameProperty('__properties', this))) {
|
|
const superCtor = superPropertiesClass(/** @type {PropertiesMixinConstructor} */(this));
|
|
this.__properties = Object.assign({},
|
|
superCtor && superCtor._properties,
|
|
ownProperties(/** @type {PropertiesMixinConstructor} */(this)));
|
|
}
|
|
return this.__properties;
|
|
}
|
|
|
|
/**
|
|
* Overrides `PropertiesChanged` method to return type specified in the
|
|
* static `properties` object for the given property.
|
|
* @param {string} name Name of property
|
|
* @return {*} Type to which to deserialize attribute
|
|
*
|
|
* @protected
|
|
*/
|
|
static typeForProperty(name) {
|
|
const info = this._properties[name];
|
|
return info && info.type;
|
|
}
|
|
|
|
/**
|
|
* Overrides `PropertiesChanged` method and adds a call to
|
|
* `finalize` which lazily configures the element's property accessors.
|
|
* @override
|
|
* @return {void}
|
|
*/
|
|
_initializeProperties() {
|
|
this.constructor.finalize();
|
|
super._initializeProperties();
|
|
}
|
|
|
|
/**
|
|
* Called when the element is added to a document.
|
|
* Calls `_enableProperties` to turn on property system from
|
|
* `PropertiesChanged`.
|
|
* @suppress {missingProperties} Super may or may not implement the callback
|
|
* @return {void}
|
|
*/
|
|
connectedCallback() {
|
|
if (super.connectedCallback) {
|
|
super.connectedCallback();
|
|
}
|
|
this._enableProperties();
|
|
}
|
|
|
|
/**
|
|
* Called when the element is removed from a document
|
|
* @suppress {missingProperties} Super may or may not implement the callback
|
|
* @return {void}
|
|
*/
|
|
disconnectedCallback() {
|
|
if (super.disconnectedCallback) {
|
|
super.disconnectedCallback();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return PropertiesMixin;
|
|
|
|
});
|
|
|
|
})();
|
|
|
|
</script>
|