Skip to content

Commit efb8d71

Browse files
author
Steven Orvell
committed
Behaviors
* properly de-dup behaviors from superclasses * apply only "own" behaviors to class
1 parent 20c8bf1 commit efb8d71

2 files changed

Lines changed: 43 additions & 47 deletions

File tree

lib/legacy/class.html

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -62,34 +62,7 @@
6262
* @suppress {invalidCasts, checkTypes}
6363
*/
6464
function mixinBehaviors(behaviors, klass) {
65-
if (behaviors) {
66-
klass = applyBehaviors(behaviors, klass);
67-
}
68-
// provides behaviors functionality
69-
return GenerateClassFromInfo({}, klass);
70-
}
71-
72-
function applyBehaviors(behaviors, klass) {
73-
if (!behaviors) {
74-
klass = /** @type {HTMLElement} */(klass); // eslint-disable-line no-self-assign
75-
return klass;
76-
}
77-
// NOTE: ensure the behavior is extending a class with
78-
// legacy element api. This is necessary since behaviors expect to be able
79-
// to access 1.x legacy api.
80-
klass = class extends Polymer.LegacyElementMixin(klass) { };
81-
if (!Array.isArray(behaviors)) {
82-
behaviors = [behaviors];
83-
}
84-
let superBehaviors = klass.prototype.behaviors;
85-
// get flattened, deduped list of behaviors *not* already on super class
86-
behaviors = flattenBehaviors(behaviors, null, superBehaviors);
87-
if (superBehaviors) {
88-
behaviors = superBehaviors.concat(behaviors);
89-
}
90-
// Set behaviors on prototype
91-
klass.prototype.behaviors = behaviors;
92-
return klass;
65+
return GenerateClassFromInfo({}, Polymer.LegacyElementMixin(klass), behaviors);
9366
}
9467

9568
// NOTE:
@@ -124,20 +97,21 @@
12497
// (again same as 1.x)
12598
function copyBehaviorProperties(behaviors, klass) {
12699
const meta = {};
100+
const superMeta = klass.prototype.__behaviorMetaProps;
127101
if (behaviors) {
128102
klass.prototype.__behaviorMetaProps = meta;
129103
for (let i=0; i<behaviors.length; i++) {
130104
copyProperties(behaviors[i], klass.prototype);
131-
memoizeBehaviorMetaProps(meta, behaviors[i]);
105+
memoizeBehaviorMetaProps(meta, behaviors[i], superMeta);
132106
}
133107
}
134108
klass.prototype.__behaviorMetaProps = meta;
135109
}
136110

137-
function memoizeBehaviorMetaProps(meta, behavior) {
111+
function memoizeBehaviorMetaProps(meta, behavior, superMeta) {
138112
for (let p in memoizedProps) {
139113
if (behavior[p]) {
140-
meta[p] = meta[p] || [];
114+
meta[p] = meta[p] || (superMeta && superMeta[p] ? superMeta[p].slice() : []);
141115
meta[p].push(behavior[p]);
142116
}
143117
}
@@ -222,7 +196,7 @@
222196
* @suppress {checkTypes}
223197
* @private
224198
*/
225-
function GenerateClassFromInfo(info, Base) {
199+
function GenerateClassFromInfo(info, Base, behaviors) {
226200

227201
/** @private */
228202
class PolymerGenerated extends Base {
@@ -289,6 +263,7 @@
289263
/**
290264
* @return {void}
291265
*/
266+
// Called on element prototype
292267
_registered() {
293268
/* NOTE: `beforeRegister` is called here for bc, but the behavior
294269
is different than in 1.x. In 1.0, the method was called *after*
@@ -297,17 +272,20 @@
297272
in `beforeRegister` or `registered`. It is no longer possible to set
298273
`is` in `beforeRegister` as you could in 1.x.
299274
*/
300-
const proto = Object.getPrototypeOf(this);
301-
copyBehaviorProperties(proto.behaviors, proto.constructor);
275+
const proto = this;
276+
if (proto.hasOwnProperty('behaviors')) {
277+
copyBehaviorProperties(proto.behaviors, proto.constructor);
278+
}
279+
proto.__behaviorMetaProps = proto.__behaviorMetaProps || {};
302280
copyProperties(info, proto);
303281
// Note, previously these were interleaved.
304-
let list = this.__behaviorMetaProps.beforeRegister;
282+
let list = proto.__behaviorMetaProps.beforeRegister;
305283
if (list) {
306284
for (let i=0; i < list.length; i++) {
307285
list[i].call(proto);
308286
}
309287
}
310-
list = this.__behaviorMetaProps.registered;
288+
list = proto.__behaviorMetaProps.registered;
311289
if (list) {
312290
for (let i=0; i < list.length; i++) {
313291
list[i].call(proto);
@@ -431,7 +409,23 @@
431409
if (info.attributeChanged) {
432410
info.attributeChanged.call(this, name, old, value);
433411
}
434-
}
412+
}
413+
}
414+
415+
// apply behaviors
416+
if (behaviors) {
417+
// NOTE: ensure the behavior is extending a class with
418+
// legacy element api. This is necessary since behaviors expect to be able
419+
// to access 1.x legacy api.
420+
if (!Array.isArray(behaviors)) {
421+
behaviors = [behaviors];
422+
}
423+
let superBehaviors = PolymerGenerated.prototype.__allBehaviors;
424+
// get flattened, deduped list of behaviors *not* already on super class
425+
behaviors = flattenBehaviors(behaviors, null, superBehaviors);
426+
PolymerGenerated.prototype.__allBehaviors = superBehaviors ?
427+
superBehaviors.concat(behaviors) : behaviors;
428+
PolymerGenerated.prototype.behaviors = behaviors;
435429
}
436430

437431
PolymerGenerated.generatedFrom = info;
@@ -513,10 +507,7 @@
513507
}
514508
let klass = mixin ? mixin(Polymer.LegacyElementMixin(HTMLElement)) :
515509
Polymer.LegacyElementMixin(HTMLElement);
516-
if (info.behaviors) {
517-
klass = applyBehaviors(info.behaviors, klass);
518-
}
519-
klass = GenerateClassFromInfo(info, klass);
510+
klass = GenerateClassFromInfo(info, klass, info.behaviors);
520511
// decorate klass with registration info
521512
klass.is = info.is;
522513
return klass;

test/unit/mixin-behaviors.html

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,10 @@
256256
<script>
257257
HTMLImports.whenReady(function() {
258258
customElements.define('nested-behaviors',
259-
class extends Polymer.mixinBehaviors(
259+
class extends Polymer.mixinBehaviors([window.BehaviorD, window.LifeCycleBehavior1], Polymer.mixinBehaviors(
260260
[
261-
[window.BehaviorB, [window.BehaviorC, window.BehaviorB], window.BehaviorA],
262-
[window.BehaviorD]
263-
], Polymer.Element) {
261+
[window.BehaviorB, [window.BehaviorC, window.BehaviorB], window.BehaviorA, window.LifeCycleBehavior2],
262+
], Polymer.Element)) {
264263
});
265264
});
266265
</script>
@@ -356,7 +355,7 @@
356355

357356
<test-fixture id="nested">
358357
<template>
359-
<nested-behaviors></nested-behaviors>
358+
<nested-behaviors foo="foo"></nested-behaviors>
360359
</template>
361360
</test-fixture>
362361

@@ -552,7 +551,13 @@
552551
});
553552

554553
test('nested-behavior dedups', function() {
555-
assert.equal(el.behaviors.length, 4);
554+
assert.equal(el.behaviors.length, 2);
555+
});
556+
557+
test('nested-behavior lifecycle', function() {
558+
assert.equal(el._calledCreated, 2, 'created call count wrong');
559+
assert.equal(el._calledAttached, 2, 'attached call count wrong');
560+
assert.equal(el._calledAttributeChanged, 1, 'attributeChanged call count wrong');
556561
});
557562

558563
test('nested-behavior overrides ordering', function() {

0 commit comments

Comments
 (0)