Skip to content

0.8 property config #1256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 5, 2015
197 changes: 104 additions & 93 deletions PRIMER.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,18 @@ You can always fallback to using the low-level methods if you wish (iow, you cou

By default, the default Polymer distribution include several features. Although `Polymer.Base` itself is tiny, if you examine `Polymer.Base` you will probably see several methods that have been plugged-in to that prototype by feature definitions. The next few sections will explain these features and why we include them in the default set. Keep in mind that it's entirely possible to construct custom feature sets, or even use a trivial, featureless form of `Polymer()`.

### Feature: _published_
### Feature: _property-config_

The first feature implements support for the `published` property. By placing a object-valued `published` property on your prototype, let's you define various aspects of your custom-elements public API.
The first feature implements support for the `properties` property. By placing a object-valued `properties` property on your prototype, let's you define various aspects of your custom-elements public API.

By itself, the `published` feature **doesn't do anything**. It only provides API for asking questions about these special properties (see [link to docs] for details).
By itself, the `properties` feature **doesn't do anything**. It only provides API for asking questions about these special properties (see [link to docs] for details).

```js
Polymer({

is: 'x-custom',

published: {
properties: {
user: String,
isHappy: Boolean,
count: {
Expand Down Expand Up @@ -128,7 +128,7 @@ Many custom elements want to support configuration using HTML attributes. Custom

Although it's relatively simple, having to write this code becomes annoying when working with multiple attributes or non-String types. It's also not very DRY.

Instead, Polymer's `attributes` feature handles this work for you (using the `published` feature data). If an attribute is set that matches a property listed in the `published` object, the value is captured into the matching property. Strings are automatically converted to the published type.
Instead, Polymer's `attributes` feature handles this work for you (using the `properties` feature data). If an attribute is set that matches a property listed in the `properties` object, the value is captured into the matching property. Strings are automatically converted to the specified type.

The type system includes support for Object values expressed as JSON, or Date objects expressed as any Date-parsable string representation. Boolean properties are mapped to Boolean attributes, in other words, if the attribute exists at all, its value is true, regardless of its string-value (and the value is only false if the attribute does not exist).

Expand All @@ -141,7 +141,7 @@ Here is the equivalent of the above code, taking advantage of the `attributes` f

is: 'x-custom',

published: {
properties: {
user: String
},

Expand Down
2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<x-doc-viewer flex sources='[
"src/features/standard/bind.html",
"src/features/standard/notify-path.html",
"src/features/micro/published.html",
"src/features/micro/property-config.html",
"src/features/standard/annotations.html",
"../x-elements/x-doc-viewer/x-doc-viewer.html"
]'></x-doc-viewer>
Expand Down
2 changes: 1 addition & 1 deletion explainer/samples.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

is: 'x-custom',

published: {
properties: {
user: String
},

Expand Down
2 changes: 1 addition & 1 deletion polymer-micro.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<link rel="import" href="src/features/micro/mixins.html">
<link rel="import" href="src/features/micro/extends.html">
<link rel="import" href="src/features/micro/constructor.html">
<link rel="import" href="src/features/micro/published.html">
<link rel="import" href="src/features/micro/property-config.html">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's name this properties.html

<link rel="import" href="src/features/micro/attributes.html">

<script>
Expand Down
159 changes: 159 additions & 0 deletions property-config.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<script>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete this file.


Polymer({

is: 'core-image',

properties: {

// Public properties

propertyName: { // Information about properties
type: String, // Type to use when deserializing attribute
notify: true, // Whether or not to send <propertyName>-changed event
readOnly: true, // Setter is no op, must use private _setPropertyName setter
value: 'foo', // Default value; may also be function that returns value
computed: 'computeFn(dep1, dep2)', // Function that computes this value based on dependencies
observer: 'propertyChanged' // Function to call upon changed
},

src: {
type: String,
value: '',
observer: 'srcChanged'
},

preventLoad: {
type: Boolean,
value: false
},

sizing: {
type: String,
value: null
},

position: {
type: String,
value: 'center'
},

preload: {
type: Boolean,
value: false
},

placeholder: {
type: String,
value: null
},

fade: {
type: Boolean,
value: false
},

loaded: {
type: Boolean,
notify: true,
readOnly: true,
value: false
},

loading: {
type: Boolean,
notify: true,
readOnly: true,
value: false
},

width: {
type: Number,
value: null,
observer: 'widthChanged'
},

height: {
type: Number,
value: null,
observer: 'heightChanged'
},

someObject: {
type: Object,
notify: true,
value: function() { return {}; }
},

// Private properties

imageClassName: {
computed: 'computeImageClassName(sizing)'
},

placeholderClassName: {
computed: 'computePlaceholderClassName(fade,loaded,preload)'
},

placeholderBackgroundUrl: {
computed: 'computePlaceholderBackgroundUrl(preload,placeholder)'
},

requiresPreload: {
computed: 'computeRequiresPreload(preload,loaded)'
},

canLoad: {
computed: 'computeCanLoad(preventLoad,src)'
}

},

observers: {
'sizing position': 'transformChanged',
'canLoad preload loaded': 'loadBehaviorChanged',
'src preload loaded': 'loadStateChanged',
'items.*': 'itemStuffChanged'
}

});

Polymer({

properties: {

propertyName: { // Information about properties
type: String, // Type to use when deserializing attribute
notify: true, // Whether or not to send <propertyName>-changed event
readOnly: true, // Setter is no op, must use private _setPropertyName setter

value: 'foo', // Default value; may also be function that returns value
// value: function(inputs) { return ... },
// noInitialObserver: true,
computed: 'computeFn(dep1, dep2)', // Function that computes this value based on dependencies
observer: 'propertyChanged' // Function to call upon changed
}

},

observers: {
'dep1 dep2': 'dependenciesChanged',
'object.path.*': 'pathChanged'
},

listeners: {
'click': 'clickHandler'
},

configure: function(inputs) {
return {
propertyName: 'default1',
propertyName2: 'default2'
};
}

});


</script>

32 changes: 18 additions & 14 deletions src/features/micro/attributes.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@
*
* Support for mapping attributes to properties.
*
* Properties that are `published` are mapped to attributes.
* Properties that are configured in `properties` with a type are mapped
* to attributes.
*
* A value set in a published attribute is deserialized into the specified
* A value set in an attribute is deserialized into the specified
* data-type and stored into the matching property.
*
* Example:
*
* published: {
* properties: {
* // values set to index attribute are converted to Number and propagated
* // to index property
* index: Number,
Expand Down Expand Up @@ -77,16 +78,20 @@
},

_takeAttributesToModel: function(model) {
for (var name in this.published) {
var type = this.getPublishedPropertyType(name);
if (type === Boolean || this.hasAttribute(name)) {
for (var name in this.properties) {
var type = this.getPropertyType(name);
if (type && this.hasAttribute(name)) {
this.setAttributeToProperty(model, name, type);
}
}
},

setAttributeToProperty: function(model, name, type) {
type = type || this.getPublishedPropertyType(name);
if (this._serializing) {
// Don't deserialize back to property if currently reflecting
return;
}
type = type || this.getPropertyType(name);
if (type) {
model[name] = this.deserialize(name, this.getAttribute(name), type);
}
Expand Down Expand Up @@ -154,19 +159,18 @@
}
},

_serializing: false,
reflectPropertyToAttribute: function(name) {
this._serializing = true;
this.serializeValueToAttribute(this[name], name);
this._serializing = false;
},

serializeValueToAttribute: function(value, attribute, node) {
node = node || this;
value = this.serialize(value);
attribute = this.camelToDashCase(attribute);
if (value !== undefined) {
node.setAttribute(attribute, value);
} else {
node.removeAttribute(attribute);
}
(node || this)[value === undefined ? 'removeAttribute' : 'setAttribute'](
this.camelToDashCase(attribute), value
);
},

// TODO(sjmiles): duplicate of function in Annotations library
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@
/**
* Define property metadata.
*
* published: {
* properties: {
* <property>: <Type || Object>,
* ...
* }
*
* Example:
*
* published: {
* properties: {
* // `foo` property can be assigned via attribute, will be deserialized to
* // the specified data-type. All `published` properties have this behavior.
* // the specified data-type. All `properties` properties have this behavior.
* foo: String,
*
* // `bar` property has additional behavior specifiers.
Expand All @@ -39,7 +39,7 @@
* }
* }
*
* By itself the published feature doesn't do anything but provide property
* By itself the properties feature doesn't do anything but provide property
* information. Other features use this information to control behavior.
*
* The `type` information is used by the `attributes` feature to convert
Expand All @@ -54,40 +54,44 @@
* `readOnly` properties have a getter, but no setter. To set a read-only
* property, use the private setter method `_set_<property>(value)`.
*
* @class base feature: published
* @class base feature: properties
*/

Base.addFeature({

published: {
properties: {
},

nob: Object.create(null),

getPublishInfo: function(property) {
var p = this.published[property];
getPropertyInfo: function(property) {
return this._getPropertyInfo(property, this.properties);
},

_getPropertyInfo: function(property, properties) {
var p = properties[property];
if (typeof(p) === 'function') {
p = this.published[property] = {
p = properties[property] = {
type: p
};
}
return p || Base.nob;
},

getPublishedPropertyType: function(property) {
return this.getPublishInfo(property).type;
getPropertyType: function(property) {
return this.getPropertyInfo(property).type;
},

isReadOnlyProperty: function(property) {
return this.getPublishInfo(property).readOnly;
return this.getPropertyInfo(property).readOnly;
},

isNotifyProperty: function(property) {
return this.getPublishInfo(property).notify;
return this.getPropertyInfo(property).notify;
},

isReflectedProperty: function(property) {
return this.getPublishInfo(property).reflect;
return this.getPropertyInfo(property).reflect;
}

});
Expand Down
Loading