polymer-analyzer
Version:
Static analysis for Web Components
159 lines (145 loc) • 4.83 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>
/**
* Automatically extend using objects referenced in `behaviors` array.
*
* someBehaviorObject = {
* accessors: {
* value: {type: Number, observer: '_numberChanged'}
* },
* observers: [
* // ...
* ],
* ready: function() {
* // called before prototoype's ready
* },
* _numberChanged: function() {}
* };
*
* Polymer({
*
* behaviors: [
* someBehaviorObject
* ]
*
* ...
*
* });
*
* @class base feature: behaviors
*/
Polymer.Base._addFeature({
/**
* Array of objects to extend this prototype with.
*
* Each entry in the array may specify either a behavior object or array
* of behaviors.
*
* Each behavior object may define lifecycle callbacks, `properties`,
* `hostAttributes`, `observers` and `listeners`.
*
* Lifecycle callbacks will be called for each behavior in the order given
* in the `behaviors` array, followed by the callback on the prototype.
* Additionally, any non-lifecycle functions on the behavior object are
* mixed into the base prototype, such that same-named functions on the
* prototype take precedence, followed by later behaviors over earlier
* behaviors.
*/
behaviors: [],
_desugarBehaviors: function() {
if (this.behaviors.length) {
this.behaviors = this._desugarSomeBehaviors(this.behaviors);
}
},
_desugarSomeBehaviors: function(behaviors) {
var behaviorSet = [];
// iteration 1
behaviors = this._flattenBehaviorsList(behaviors);
// iteration 2
// traverse the behaviors in _reverse_ order (youngest first) because
// `_mixinBehavior` has _first property wins_ behavior, this is done
// to optimize # of calls to `_copyOwnProperty`
for (var i=behaviors.length-1; i>=0; i--) {
var b = behaviors[i];
if (behaviorSet.indexOf(b) === -1) {
this._mixinBehavior(b);
behaviorSet.unshift(b);
}
}
return behaviorSet;
},
_flattenBehaviorsList: function(behaviors) {
var flat = [];
for (var i=0; i < behaviors.length; i++) {
var b = behaviors[i];
if (b instanceof Array) {
flat = flat.concat(this._flattenBehaviorsList(b));
}
// filter out null entries so other iterators don't need to check
else if (b) {
flat.push(b);
} else {
this._warn(this._logf('_flattenBehaviorsList', 'behavior is null, check for missing or 404 import'));
}
}
return flat;
},
_mixinBehavior: function(b) {
var n$ = Object.getOwnPropertyNames(b);
var useAssignment = b._noAccessors;
for (var i=0, n; (i<n$.length) && (n=n$[i]); i++) {
if (!Polymer.Base._behaviorProperties[n] && !this.hasOwnProperty(n)) {
if (useAssignment) {
this[n] = b[n];
} else {
this.copyOwnProperty(n, b, this);
}
}
}
},
_prepBehaviors: function() {
this._prepFlattenedBehaviors(this.behaviors);
},
_prepFlattenedBehaviors: function(behaviors) {
// iteration 3
// `_prepBehavior` goes in natural order
// otherwise, it's a tricky detail for implementors of `_prepBehavior`
for (var i=0, l=behaviors.length; i<l; i++) {
this._prepBehavior(behaviors[i]);
}
// prep our prototype-as-behavior
this._prepBehavior(this);
},
_marshalBehaviors: function() {
for (var i=0; i < this.behaviors.length; i++) {
this._marshalBehavior(this.behaviors[i]);
}
this._marshalBehavior(this);
}
});
// special properties on behaviors are not mixed in and are instead
// either processed specially (e.g. listeners, properties) or available
// for calling via doBehavior (e.g. created, ready)
Polymer.Base._behaviorProperties = {
hostAttributes: true,
beforeRegister: true,
registered: true,
properties: true,
observers: true,
listeners: true,
created: true,
attached: true,
detached: true,
attributeChanged: true,
ready: true,
_noAccessors: true
}
</script>