Skip to content
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

iterate behavior mixins in reverse order as the hasOwnProperty chec… #1588

Merged
merged 3 commits into from
May 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions polymer-micro.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
_registerFeatures: function() {
// identity
this._prepIs();
// attributes
this._prepAttributes();
// shared behaviors
this._prepBehaviors();
// inheritance
Expand All @@ -31,18 +33,20 @@
this._prepConstructor();
},

_prepBehavior: function() {},
_prepBehavior: function(b) {
this._addHostAttributes(b.hostAttributes);
},

_marshalBehavior: function(b) {
},

_initFeatures: function() {
// install host attributes
this._marshalHostAttributes();
// setup debouncers
this._setupDebouncers();
// acquire behaviors
this._marshalBehaviors();
},

_marshalBehavior: function(b) {
// publish attributes to instance
this._installHostAttributes(b.hostAttributes);
}

});
Expand Down
10 changes: 7 additions & 3 deletions polymer-mini.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
_registerFeatures: function() {
// identity
this._prepIs();
// attributes
this._prepAttributes();
// shared behaviors
this._prepBehaviors();
// inheritance
Expand All @@ -36,7 +38,9 @@
this._prepShady();
},

_prepBehavior: function() {},
_prepBehavior: function(b) {
this._addHostAttributes(b.hostAttributes);
},

_initFeatures: function() {
// manage local dom
Expand All @@ -47,6 +51,8 @@
this._stampTemplate();
// host stack
this._popHost();
// install host attributes
this._marshalHostAttributes();
// setup debouncers
this._setupDebouncers();
// instance shared behaviors
Expand All @@ -56,8 +62,6 @@
},

_marshalBehavior: function(b) {
// publish attributes to instance
this._installHostAttributes(b.hostAttributes);
}

});
Expand Down
9 changes: 6 additions & 3 deletions polymer.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
_registerFeatures: function() {
// identity
this._prepIs();
// attributes
this._prepAttributes();
// inheritance
this._prepExtends();
// factory
Expand All @@ -51,8 +53,9 @@
},

_prepBehavior: function(b) {
this._addPropertyEffects(b.properties || b.accessors);
this._addPropertyEffects(b.properties);
this._addComplexObserverEffects(b.observers);
this._addHostAttributes(b.hostAttributes);
},

_initFeatures: function() {
Expand All @@ -70,6 +73,8 @@
this._popHost();
// concretize template references
this._marshalAnnotationReferences();
// install host attributes
this._marshalHostAttributes();
// setup debouncers
this._setupDebouncers();
// concretize effects on instance
Expand All @@ -83,8 +88,6 @@
},

_marshalBehavior: function(b) {
// publish attributes to instance
this._installHostAttributes(b.hostAttributes);
// establish listeners on instance
this._listenListeners(b.listeners);
}
Expand Down
17 changes: 11 additions & 6 deletions src/micro/attributes.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,29 +60,33 @@

Polymer.Base._addFeature({

_marshalAttributes: function() {
this._takeAttributes();
_prepAttributes: function() {
this._aggregatedAttributes = {};
},

_installHostAttributes: function(attributes) {
_addHostAttributes: function(attributes) {
if (attributes) {
this._applyAttributes(this, attributes);
this.mixin(this._aggregatedAttributes, attributes);
}
},

_marshalHostAttributes: function() {
this._applyAttributes(this, this._aggregatedAttributes);
},

/* apply attributes to node but avoid overriding existing values */
_applyAttributes: function(node, attr$) {
for (var n in attr$) {
// NOTE: never allow 'class' to be set in hostAttributes
// since shimming classes would make it work
// since shimming classes would make it work
// inconsisently under native SD
if (!this.hasAttribute(n) && (n !== 'class')) {
this.serializeValueToAttribute(attr$[n], n, this);
}
}
},

_takeAttributes: function() {
_marshalAttributes: function() {
this._takeAttributesToModel(this);
},

Expand All @@ -106,6 +110,7 @@
},

_serializing: false,

reflectPropertyToAttribute: function(name) {
this._serializing = true;
this.serializeValueToAttribute(this[name],
Expand Down
36 changes: 21 additions & 15 deletions src/micro/behaviors.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,43 +46,49 @@
if (this.behaviors.length) {
this.behaviors = this._flattenBehaviorsList(this.behaviors);
}
this._prepAllBehaviors();
this._prepAllBehaviors(this.behaviors);
},

_flattenBehaviorsList: function(behaviors) {
var flat = [];
behaviors.forEach(function(b) {
if (b instanceof Array) {
flat = flat.concat(this._flattenBehaviorsList(b));
} else {
}
// 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'));
}
}, this);
return flat;
},

_prepAllBehaviors: function() {
// filter so other iterators don't need null check
this.behaviors = this.behaviors.filter(function(b) {
if (b) {
this._mixinBehavior(b);
this._prepBehavior(b);
return true;
}
this._warn(this._logf('_prepAllBehaviors', 'behavior is null, check for missing or 404 import'));
}, this);
_prepAllBehaviors: function(behaviors) {
// 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--) {
this._mixinBehavior(behaviors[i]);
}
// we iterate a second time so that `_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);
},

_mixinBehavior: function(b) {
Object.getOwnPropertyNames(b).forEach(function(n) {
Object.getOwnPropertyNames(b).forEach(function(n) {
switch (n) {
case 'hostAttributes':
case 'registered':
case 'properties':
case 'observers':
case 'listeners':
case 'keyPresses':
case 'hostAttributes':
case 'created':
case 'attached':
case 'detached':
Expand Down
40 changes: 0 additions & 40 deletions src/micro/mixins.html

This file was deleted.

32 changes: 29 additions & 3 deletions test/unit/behaviors-elements.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,20 @@
value: false
},

overridablePropertyB: {
value: false
},

hasBehaviorA: {
value: true
}
},

_simpleProperty: 'A',

hostAttributes: {
behavior: 'A',
user: 'A'
},

listeners: {
Expand Down Expand Up @@ -76,10 +86,21 @@

hasBehaviorB: {
value: true
}
},

overridablePropertyB: {
value: true
},

},

hostAttributes: {
behavior: 'B',
user: 'B'
},

_simpleProperty: 'B',

_disabledChanged: function(disabled) {
this.__disabled = disabled
},
Expand Down Expand Up @@ -118,6 +139,7 @@

behaviors: [
Polymer.BehaviorA,
null,
Polymer.BehaviorB
],

Expand Down Expand Up @@ -158,7 +180,9 @@
value: true
}

}
},

_simpleProperty: 'C'

};

Expand All @@ -170,7 +194,9 @@
value: true
}

}
},

_simpleProperty: 'D'

};

Expand Down
22 changes: 16 additions & 6 deletions test/unit/behaviors.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@
var el;

setup(function() {
el = document.createElement('multi-behaviors');
var div = document.createElement('div');
div.innerHTML = '<multi-behaviors user="user"></multi-behaviors>';
el = div.firstElementChild;
document.body.appendChild(el);
});

Expand Down Expand Up @@ -103,14 +105,21 @@
assert.equal(typeof el._setHasOptionsB, 'function');
});

test('behavior overrides are last', function() {
assert.equal(el._toOverride, Polymer._toOverride, 'Behavior method was not overridden');
assert(el.overridableProperty, 'Behavior property was not overridden');
test('multi-behavior overrides ordering', function() {
assert.equal(el._toOverride, Polymer._toOverride, 'Behavior method was not overridden by prototype');
assert(el.overridableProperty, 'Behavior property was not overridden by prototype');
assert(el.overridablePropertyB, 'Behavior config-property was not overridden by sub-behavior');
});

test('hostAttributes ordering', function() {
assert.equal(el.attributes.behavior.value, 'B', 'Behavior hostAttribute not overridden by subclass');
assert.equal(el.attributes.user.value, 'user', 'Behavior hostAttribute overrode user attribute');
});

});


suite('nexted-behaviors element', function() {
suite('nested-behaviors element', function() {

var el;

Expand All @@ -123,11 +132,12 @@
document.body.removeChild(el);
});

test('properties from nested behaviors', function() {
test('nested-behavior overrides ordering', function() {
assert.ok(el.hasBehaviorA, "missing BehaviorA");
assert.ok(el.hasBehaviorB, "missing BehaviorB");
assert.ok(el.hasBehaviorC, "missing BehaviorC");
assert.ok(el.hasBehaviorD, "missing BehaviorD");
assert.equal(el._simpleProperty, 'D', 'Behavior simple property was not overridden by sub-behavior');
});

});
Expand Down