Skip to content

Commit c91b9d1

Browse files
author
Steven Orvell
committed
Better attribute suppport
* Moves _propertyToAttribute to PropertiesChanged * PropertiesMixin supports `attribute` in the `properties` object to define an attribute name.
1 parent 5ae21a0 commit c91b9d1

File tree

3 files changed

+80
-57
lines changed

3 files changed

+80
-57
lines changed

lib/mixins/properties-changed.html

+40-3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
this.__dataPending = null;
118118
this.__dataOld = null;
119119
this.__dataInstanceProps = null;
120+
this.__serializing = false;
120121
this._initializeProperties();
121122
}
122123

@@ -356,9 +357,45 @@
356357
* returned from `_typeForProperty`
357358
*/
358359
_attributeToProperty(attribute, value, type) {
359-
const property = this._propertyForAttribute(attribute);
360-
this[property] = this._deserializeValue(value, type ||
361-
this._typeForProperty(property));
360+
if (!this.__serializing) {
361+
const property = this._propertyForAttribute(attribute);
362+
this[property] = this._deserializeValue(value, type ||
363+
this._typeForProperty(property));
364+
}
365+
}
366+
367+
/**
368+
* Serializes a property to its associated attribute.
369+
*
370+
* @suppress {invalidCasts} Closure can't figure out `this` is an element.
371+
*
372+
* @param {string} property Property name to reflect.
373+
* @param {string=} attribute Attribute name to reflect to.
374+
* @param {*=} value Property value to refect.
375+
*/
376+
_propertyToAttribute(property, attribute, value) {
377+
this.__serializing = true;
378+
value = (arguments.length < 3) ? this[property] : value;
379+
this._valueToNodeAttribute(/** @type {!HTMLElement} */(this), value,
380+
attribute || this._attributeForProperty(property));
381+
this.__serializing = false;
382+
}
383+
384+
/**
385+
* Sets a typed value to an HTML attribute on a node.
386+
*
387+
* If the value is `undefined`, the attribute will be removed.
388+
*
389+
* @param {Element} node Element to set attribute to.
390+
* @param {*} value Value to serialize.
391+
* @param {string} attribute Attribute name to serialize to.
392+
*/
393+
_valueToNodeAttribute(node, value, attribute) {
394+
if (!value && value !== '' && value !== 0) {
395+
node.removeAttribute(attribute);
396+
} else {
397+
node.setAttribute(attribute, value);
398+
}
362399
}
363400

364401
/**

lib/mixins/properties-mixin.html

+36-8
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
*/
4343
const base = Polymer.PropertiesChanged(superClass);
4444

45+
function BooleanAttribute(value) {
46+
return value !== null;
47+
}
48+
4549
/**
4650
* @polymer
4751
* @mixinClass
@@ -51,21 +55,33 @@
5155
*/
5256
class Properties extends base {
5357

58+
static get BooleanAttribute() {
59+
return BooleanAttribute;
60+
}
61+
5462
/**
5563
* Implements standard custom elements getter to observes the attributes
5664
* listed in `properties`.
5765
*/
5866
static get observedAttributes() {
59-
const props = this.properties;
67+
this._ensurePropertyInfo();
68+
const props = this.prototype.__propertyInfo;
6069
return props ? Object.keys(props).map(p => {
6170
return this.prototype._attributeForProperty(p);
6271
}) : [];
6372
}
6473

74+
_propertyForAttribute(name) {
75+
return this.__attributeInfo[name] || name;
76+
}
77+
78+
_attributeForProperty(name) {
79+
const info = this.__propertyInfo[name];
80+
return info && info.attribute || name.toLowerCase();
81+
}
82+
6583
static _ensureFinalized(name) {
66-
const proto = this.prototype;
67-
if (!proto.hasOwnProperty('__finalized')) {
68-
proto.__finalized = true;
84+
if (!this.prototype.hasOwnProperty('__finalized')) {
6985
this.finalize(name);
7086
}
7187
}
@@ -77,13 +93,25 @@
7793
* @param {string} name Name of the element
7894
*/
7995
static finalize(name) { // eslint-disable-line no-unused-vars
80-
const props = this.properties;
96+
this.prototype.__finalized = true;
97+
this._ensurePropertyInfo();
98+
const props = this.prototype.__propertyInfo;
8199
if (props) {
82-
this.prototype.__propertyInfo = props;
83100
this.createProperties(Object.keys(props));
84101
}
85102
}
86103

104+
static _ensurePropertyInfo() {
105+
let proto = this.prototype;
106+
if (!proto.hasOwnProperty('__propertyInfo')) {
107+
const props = this.prototype.__propertyInfo = this.properties;
108+
const attrInfo = this.prototype.__attributeInfo = {};
109+
for (let prop in props) {
110+
attrInfo[proto._attributeForProperty(prop)] = prop;
111+
}
112+
}
113+
}
114+
87115
/**
88116
* Overrides implementation in PropertiesChanged to immediately process
89117
* any pending changes to properties and ensure that
@@ -116,8 +144,8 @@
116144
* @protected
117145
*/
118146
_typeForProperty(name) {
119-
const props = this.__propertyInfo;
120-
return props && props[name];
147+
const info = this.__propertyInfo[name];
148+
return info.type || info;
121149
}
122150

123151
/**

lib/mixins/property-accessors.html

+4-46
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,6 @@
127127

128128
constructor() {
129129
super();
130-
/** @type {boolean} */
131-
this.__serializing;
132130
/** @type {number} */
133131
this.__dataCounter;
134132
}
@@ -209,44 +207,9 @@
209207
}
210208

211209
/**
212-
* Deserializes an attribute to its associated property.
213-
*
214-
* This method calls the `_deserializeValue` method to convert the string to
215-
* a typed value.
216-
*
217-
* @param {string} attribute Name of attribute to deserialize.
218-
* @param {?string} value of the attribute.
219-
* @param {*=} type type to deserialize to.
220-
*/
221-
_attributeToProperty(attribute, value, type) {
222-
// Don't deserialize back to property if currently reflecting
223-
if (!this.__serializing) {
224-
super._attributeToProperty(attribute, value, type);
225-
}
226-
}
227-
228-
/**
229-
* Serializes a property to its associated attribute.
230-
*
231-
* @suppress {invalidCasts} Closure can't figure out `this` is an element.
232-
*
233-
* @param {string} property Property name to reflect.
234-
* @param {string=} attribute Attribute name to reflect.
235-
* @param {*=} value Property value to refect.
236-
*/
237-
_propertyToAttribute(property, attribute, value) {
238-
this.__serializing = true;
239-
value = (arguments.length < 3) ? this[property] : value;
240-
this._valueToNodeAttribute(/** @type {!HTMLElement} */(this), value,
241-
attribute || this._attributeForProperty(property));
242-
this.__serializing = false;
243-
}
244-
245-
/**
246-
* Sets a typed value to an HTML attribute on a node.
247-
*
248-
* This method calls the `_serializeValue` method to convert the typed
249-
* value to a string. If the `_serializeValue` method returns `undefined`,
210+
* Overrides PropertiesChanged implementation to calls the
211+
* `_serializeValue` method to convert the typed value to a string.
212+
* If the `_serializeValue` method returns `undefined`,
250213
* the attribute will be removed (this is the default for boolean
251214
* type `false`).
252215
*
@@ -255,12 +218,7 @@
255218
* @param {string} attribute Attribute name to serialize to.
256219
*/
257220
_valueToNodeAttribute(node, value, attribute) {
258-
let str = this._serializeValue(value);
259-
if (str === undefined) {
260-
node.removeAttribute(attribute);
261-
} else {
262-
node.setAttribute(attribute, str);
263-
}
221+
super._valueToNodeAttribute(node, this._serializeValue(value), attribute);
264222
}
265223

266224
/**

0 commit comments

Comments
 (0)