diff --git a/lib/mixins/element-mixin.html b/lib/mixins/element-mixin.html index ae63319115..eb41b3df47 100644 --- a/lib/mixins/element-mixin.html +++ b/lib/mixins/element-mixin.html @@ -11,7 +11,6 @@ - @@ -100,8 +99,6 @@ */ const polymerElementBase = Polymer.PropertiesMixin(Polymer.PropertyEffects(base)); - let caseMap = Polymer.CaseMap; - /** * Returns a list of properties with default values. * This list is created as an optimization since it is a subset of @@ -113,20 +110,20 @@ * that have default values * @private */ - function propertyDefaultsForClass(klass) { + function propertyDefaults(klass) { if (!klass.hasOwnProperty( - JSCompiler_renameProperty('__classPropertyDefaults', klass))) { - klass.__classPropertyDefaults = null; + JSCompiler_renameProperty('__propertyDefaults', klass))) { + klass.__propertyDefaults = null; let props = klass._properties; for (let p in props) { let info = props[p]; if ('value' in info) { - klass.__classPropertyDefaults = klass.__classPropertyDefaults || {}; - klass.__classPropertyDefaults[p] = info; + klass.__propertyDefaults = klass.__propertyDefaults || {}; + klass.__propertyDefaults[p] = info; } } } - return klass.__classPropertyDefaults; + return klass.__propertyDefaults; } /** @@ -135,7 +132,7 @@ * @return {Array} Array containing own observers for the given class * @protected */ - function ownObserversForClass(klass) { + function ownObservers(klass) { if (!klass.hasOwnProperty( JSCompiler_renameProperty('__ownObservers', klass))) { klass.__ownObservers = @@ -250,7 +247,7 @@ JSCompiler_renameProperty('is', this)) && this.is) { Polymer.telemetry.register(this.prototype); } - const observers = ownObserversForClass(this); + const observers = ownObservers(this); if (observers) { this.createObservers(observers, this._properties); } @@ -400,7 +397,7 @@ this.rootPath = Polymer.rootPath; this.importPath = importPath; // apply property defaults... - let p$ = propertyDefaultsForClass(this.constructor); + let p$ = propertyDefaults(this.constructor); if (!p$) { return; } @@ -564,7 +561,7 @@ */ attributeChangedCallback(name, old, value) { if (old !== value) { - let property = this._attributeForProperty(name); + let property = this._propertyNameForAttribute(name); if (!this._hasReadOnlyEffect(property)) { super.attributeChangedCallback(name, old, value); } diff --git a/lib/mixins/properties-changed.html b/lib/mixins/properties-changed.html index f44c23a7fd..b9a49b6154 100644 --- a/lib/mixins/properties-changed.html +++ b/lib/mixins/properties-changed.html @@ -359,7 +359,7 @@ */ _attributeToProperty(attribute, value, type) { if (!this.__serializing) { - const property = this._propertyForAttribute(attribute); + const property = this._propertyNameForAttribute(attribute); this[property] = this._deserializeValue(value, type || this._typeForProperty(property)); } @@ -378,7 +378,7 @@ this.__serializing = true; value = (arguments.length < 3) ? this[property] : value; this._valueToNodeAttribute(/** @type {!HTMLElement} */(this), value, - attribute || this._attributeForProperty(property)); + attribute || this._attributeNameForProperty(property)); this.__serializing = false; } @@ -403,6 +403,17 @@ } } + /** + * Converts a typed JavaScript value to a string. + * + * This method is called by Polymer when setting JS property values to + * HTML attributes. Users may override this method on Polymer element + * prototypes to provide serialization for custom types. + * + * @param {*} value Property value to serialize. + * @return {string | undefined} String serialized from the provided + * property value. + */ _serializeValue(value) { switch (typeof value) { case 'boolean': @@ -429,6 +440,8 @@ switch (type) { case Boolean: return (value !== null); + case String: + return value; default: return typeof type == 'function' ? type(value) : value; } @@ -442,7 +455,7 @@ * * @protected */ - _propertyForAttribute(attribute) { + _propertyNameForAttribute(attribute) { return attribute; } @@ -454,7 +467,7 @@ * * @protected */ - _attributeForProperty(property) { + _attributeNameForProperty(property) { return property.toLowerCase(); } diff --git a/lib/mixins/properties-mixin.html b/lib/mixins/properties-mixin.html index 155be989e8..a20325926a 100644 --- a/lib/mixins/properties-mixin.html +++ b/lib/mixins/properties-mixin.html @@ -86,7 +86,7 @@ * @param {PropertiesClassConstructor} ctor PropertiesClass constructor * @return {Object} Memoized properties object */ - function ownPropertiesForClass(ctor) { + function ownProperties(ctor) { if (!ctor.hasOwnProperty( JSCompiler_renameProperty('__ownProperties', ctor))) { const props = ctor.properties; @@ -96,23 +96,18 @@ } /** - * Returns a memoized version attribute info for the - * given class. + * Returns map of properties for attributes for the given class. * * @param {PropertiesClassConstructor} ctor PropertiesClass constructor - * @return {Object} Memoized attribute info object + * @param {string} nane Name of attribute + * @return {string} Name of property. */ - function attributeInfoForClass(ctor) { + function propertyNameForAttributeMap(ctor) { if (!ctor.hasOwnProperty( - JSCompiler_renameProperty('__attributeInfo', ctor))) { - const proto = ctor.prototype; - const attrInfo = ctor.__attributeInfo = {}; - const props = ctor._properties; - for (let prop in props) { - attrInfo[proto._attributeForProperty(prop)] = prop; - } + JSCompiler_renameProperty('__propertyNameForAttributeMap', ctor))) { + ctor.__propertyNameForAttributeMap = {}; } - return ctor.__attributeInfo; + return ctor.__propertyNameForAttributeMap; } /** @@ -124,10 +119,6 @@ */ class PropertiesClass extends base { - static get BooleanAttribute() { - return BooleanAttribute; - } - /** * Implements standard custom elements getter to observes the attributes * listed in `properties`. @@ -135,7 +126,7 @@ static get observedAttributes() { const props = this._properties; return props ? Object.keys(props).map(p => { - return this.prototype._attributeForProperty(p); + return this.prototype._attributeNameForProperty(p); }) : []; } @@ -144,9 +135,8 @@ * 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. - * @param {string} name Name of the element */ - static finalize() { // eslint-disable-line no-unused-vars + static finalize() { if (!this.hasOwnProperty(JSCompiler_renameProperty('__finalized', this))) { const superCtor = superForClass(this); if (superCtor) { @@ -165,7 +155,7 @@ * @protected */ static _finalizeClass() { - const props = ownPropertiesForClass(this); + const props = ownProperties(this); if (props) { this.createProperties(props); } @@ -184,19 +174,22 @@ JSCompiler_renameProperty('__properties', this))) { const superCtor = superForClass(this); this.__properties = Object.assign({}, - superCtor && superCtor._properties, ownPropertiesForClass(this)); + superCtor && superCtor._properties, ownProperties(this)); } return this.__properties; } - _propertyForAttribute(name) { - return attributeInfoForClass(this.constructor)[name] || - super._propertyForAttribute(name); - } - - _attributeForProperty(name) { - const info = this.constructor._properties[name]; - return info && info.attribute || super._attributeForProperty(name); + /** + * Overrides PropertiesChanged implementation to provide caching. + * @param {string} name Name of property + * @return {string} Name of attribute + */ + _propertyNameForAttribute(name) { + const cache = propertyNameForAttributeMap(this.constructor); + if (!cache[name]) { + cache[name] = super._propertyNameForAttribute(name); + } + return cache[name]; } /** @@ -209,7 +202,7 @@ */ _typeForProperty(name) { const info = this.constructor._properties[name]; - return info.type || info; + return info && info.type; } /** @@ -218,7 +211,7 @@ * @override */ _initializeProperties() { - this.constructor.finalize(this.localName); + this.constructor.finalize(); super._initializeProperties(); } diff --git a/lib/mixins/property-accessors.html b/lib/mixins/property-accessors.html index 9682e3222c..d5532d7f9b 100644 --- a/lib/mixins/property-accessors.html +++ b/lib/mixins/property-accessors.html @@ -125,12 +125,6 @@ } } - constructor() { - super(); - /** @type {number} */ - this.__dataCounter = 0; - } - /** * Returns a property name that corresponds to the given attribute. * By default, converts dash to camel case, e.g. `foo-bar` to `fooBar`. @@ -139,7 +133,7 @@ * * @protected */ - _propertyForAttribute(attribute) { + _propertyNameForAttribute(attribute) { return caseMap.dashToCamelCase(attribute); } @@ -151,7 +145,7 @@ * * @protected */ - _attributeForProperty(property) { + _attributeNameForProperty(property) { return caseMap.camelToDashCase(property); } @@ -290,7 +284,7 @@ * for the values to take effect. * @protected */ - _definePropertyAccessor(property, readOnly) { + _definePropertyAccessor(property, readOnly) { saveAccessorValue(this, property); super._definePropertyAccessor(property, readOnly); } @@ -316,17 +310,6 @@ return Boolean(this.__dataPending && (prop in this.__dataPending)); } - /** - * Overrides `PropertiesChanged` implementation. - * - * @protected - */ - _flushProperties() { - this.__dataCounter++; - super._flushProperties(); - this.__dataCounter--; - } - } return PropertyAccessors; diff --git a/lib/mixins/property-effects.html b/lib/mixins/property-effects.html index 02e8442630..842114e7a5 100644 --- a/lib/mixins/property-effects.html +++ b/lib/mixins/property-effects.html @@ -1112,6 +1112,8 @@ constructor() { super(); + /** @type {number} */ + this.__dataCounter = 0; /** @type {boolean} */ this.__dataClientsReady; /** @type {Array} */ @@ -1505,6 +1507,17 @@ } } + /** + * Overrides superclass implementation. + * + * @protected + */ + _flushProperties() { + this.__dataCounter++; + super._flushProperties(); + this.__dataCounter--; + } + /** * Flushes any clients previously enqueued via `_enqueueClient`, causing * their `_flushProperties` method to run. @@ -2051,7 +2064,7 @@ * @protected */ _createReflectedProperty(property) { - let attr = this._attributeForProperty(property); + let attr = this._attributeNameForProperty(property); if (attr[0] === '-') { console.warn('Property ' + property + ' cannot be reflected to attribute ' + attr + ' because "-" is not a valid starting attribute name. Use a lowercase first letter for the property instead.'); diff --git a/test/unit/polymer.element.html b/test/unit/polymer.element.html index caefabed91..d8f6ccf8c8 100644 --- a/test/unit/polymer.element.html +++ b/test/unit/polymer.element.html @@ -40,12 +40,7 @@ computed: '_compute(computedPropDep)' }, accessor: String, - noStomp: String, - customAttr: { - type: String, - attribute: 'foo', - reflectToAttribute: true - } + noStomp: String }; } @@ -414,20 +409,15 @@

Sub template

test('attributes', function() { const fixtureEl = fixture('my-element-attr'); assert.equal(fixtureEl.prop, 'attr'); - assert.equal(fixtureEl.customAttr, 'foo'); - assert.equal(fixtureEl._callAttributeChangedCallback, 3); + assert.equal(fixtureEl._callAttributeChangedCallback, 1); assert.isTrue(fixtureEl.hasAttribute('tabindex')); }); test('reflecting attributes', function() { const fixtureEl = fixture('my-element-attr'); fixtureEl.prop = 'propValue'; - // without reflect effect fixtureEl._propertyToAttribute('prop'); assert.equal(fixtureEl.getAttribute('prop'), 'propValue'); - // with reflect effect - fixtureEl.customAttr = 'customAttrValue'; - assert.equal(fixtureEl.getAttribute('foo'), 'customAttrValue'); }); }); diff --git a/test/unit/polymer.properties-element.html b/test/unit/polymer.properties-element.html index f5a952039e..8702759f4d 100644 --- a/test/unit/polymer.properties-element.html +++ b/test/unit/polymer.properties-element.html @@ -25,11 +25,7 @@ static get properties() { return { prop: String, - noStomp: String, - customAttr: { - type: String, - attribute: 'foo' - } + noStomp: String }; } @@ -248,8 +244,7 @@ test('attributes', function() { const fixtureEl = fixture('my-element-attr'); assert.equal(fixtureEl.prop, 'attr'); - assert.equal(fixtureEl.customAttr, 'foo'); - assert.equal(fixtureEl._callAttributeChangedCallback, 2); + assert.equal(fixtureEl._callAttributeChangedCallback, 1); }); test('reflecting attributes', function() { @@ -257,9 +252,6 @@ fixtureEl.prop = 'propValue'; fixtureEl._propertyToAttribute('prop'); assert.equal(fixtureEl.getAttribute('prop'), 'propValue'); - fixtureEl.customAttr = 'customAttrValue'; - fixtureEl._propertyToAttribute('customAttr'); - assert.equal(fixtureEl.getAttribute('foo'), 'customAttrValue'); }); });