five-bells-visualization
Version:
Tool to visualize Five Bells payments
184 lines (160 loc) • 6.36 kB
HTML
<!--
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
-->
<script>
/*
Process inputs efficiently via a configure lifecycle callback.
Configure is called top-down, host before local dom. Users should
implement configure to supply a set of default values for the element by
returning an object containing the properties and values to set.
Configured values are not immediately set, instead they are set when
an element becomes ready, after its local dom is ready. This ensures
that any user change handlers are not called before ready time.
*/
/*
Implementation notes:
Configured values are collected into _config. At ready time, properties
are set to the values in _config. This ensures properties are set child
before host and change handlers are called only at ready time. The host
will reset a value already propagated to a child, but this is not
inefficient because of dirty checking at the set point.
Bind notification events are sent when properties are set at ready time
and thus received by the host before it is ready. Since notifications result
in property updates and this triggers side effects, handling notifications
is deferred until ready time.
In general, events can be heard before an element is ready. This may occur
when a user sends an event in a change handler or listens to a data event
directly (on-foo-changed).
*/
Polymer.Base._addFeature({
// storage for configuration
_setupConfigure: function(initialConfig) {
this._config = initialConfig || {};
this._handlers = [];
},
// static attributes are deserialized into _config
_takeAttributes: function() {
this._takeAttributesToModel(this._config);
},
// at configure time values are stored in _config
_configValue: function(name, value) {
this._config[name] = value;
},
// Override polymer-mini thunk
_beforeClientsReady: function() {
this._configure();
},
// configure: returns user supplied default property values
// combines with _config to create final property values
_configure: function() {
this._configureAnnotationReferences();
// get individual default values from property configs
var config = {};
this._configureProperties(this.properties, config);
// behave!
this.behaviors.forEach(function(b) {
this._configureProperties(b.properties, config);
}, this);
// get add'l default values from central configure
// combine defaults returned from configure with inputs in _config
this._mixinConfigure(config, this._config);
// this is the new _config, which are the final values to be applied
this._config = config;
// pass configuration data to bindings
this._distributeConfig(this._config);
},
_configureProperties: function(properties, config) {
for (i in properties) {
var c = properties[i];
if (c.value !== undefined) {
var value = c.value;
if (typeof value == 'function') {
// pass existing config values (this._config) to value function
value = value.call(this, this._config);
}
config[i] = value;
}
}
},
_mixinConfigure: function(a, b) {
for (var prop in b) {
if (!this.isReadOnlyProperty(prop)) {
a[prop] = b[prop];
}
}
},
// distribute config values to bound nodes.
_distributeConfig: function(config) {
var fx$ = this._propertyEffects;
if (fx$) {
for (var p in config) {
var fx = fx$[p];
if (fx) {
for (var i=0, l=fx.length, x; (i<l) && (x=fx[i]); i++) {
if (x.kind === 'annotation') {
var node = this._nodes[x.effect.index];
// seeding configuration only
if (node._configValue) {
var value = (p === x.effect.value) ? config[p] :
this.getPathValue(x.effect.value, config);
node._configValue(x.effect.name, value);
}
}
}
}
}
}
},
// Override polymer-mini thunk
_afterClientsReady: function() {
this._applyConfig(this._config);
this._flushHandlers();
},
// NOTE: values are already propagated to children via
// _distributeConfig so propagation triggered by effects here is
// redundant, but safe due to dirty checking
_applyConfig: function(config) {
for (var n in config) {
// Don't stomp on values that may have been set by other side effects
if (this[n] === undefined) {
// Call _propertySet for any properties with accessors, which will
// initialize read-only properties also
// TODO(kschaaf): consider passing fromAbove here to prevent
// unnecessary notify for: 1) possible perf, 2) debuggability
var effects = this._propertyEffects[n];
if (effects) {
this._propertySet(n, config[n], effects);
} else {
this[n] = config[n];
}
}
}
},
// NOTE: Notifications can be processed before ready since
// they are sent at *child* ready time. Since notifications cause side
// effects and side effects must not be processed before ready time,
// handling is queue/defered until then.
_notifyListener: function(fn, e) {
if (!this._clientsReadied) {
this._queueHandler([fn, e, e.target]);
} else {
return fn.call(this, e, e.target);
}
},
_queueHandler: function(args) {
this._handlers.push(args);
},
_flushHandlers: function() {
var h$ = this._handlers;
for (var i=0, l=h$.length, h; (i<l) && (h=h$[i]); i++) {
h[0].call(this, h[1], h[2]);
}
}
});
</script>