Skip to content

Commit c30ac10

Browse files
committed
Apply effect value from compound parts.
1 parent 1026498 commit c30ac10

File tree

6 files changed

+159
-17
lines changed

6 files changed

+159
-17
lines changed

src/lib/annotations/annotations.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@
156156
var annote = {
157157
bindings: [{
158158
kind: 'text',
159-
parts: parts
159+
name: 'textContent',
160+
parts: parts,
161+
isCompound: parts.length !== 1
160162
}]
161163
};
162164
list.push(annote);

src/lib/bind/effects.html

+6-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
!effect.parts[0].negate;
2121
},
2222

23+
_compoundInitializationEffect: function(source, value, effect) {
24+
this._applyEffectValue(effect);
25+
},
26+
2327
_annotationEffect: function(source, value, effect) {
2428
if (source != effect.value) {
2529
value = this._get(effect.value);
@@ -30,7 +34,7 @@
3034
// are used, since the target element may not dirty check (e.g. <input>)
3135
if (!effect.customEvent ||
3236
this._nodes[effect.index][effect.name] !== calc) {
33-
return this._applyEffectValue(calc, effect);
37+
return this._applyEffectValue(effect, calc);
3438
}
3539
},
3640

@@ -95,7 +99,7 @@
9599
if (effect.negate) {
96100
computedvalue = !computedvalue;
97101
}
98-
this._applyEffectValue(computedvalue, effect);
102+
this._applyEffectValue(effect, computedvalue);
99103
}
100104
} else {
101105
computedHost._warn(computedHost._logf('_annotatedComputationEffect',

src/standard/annotations.html

+21
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@
221221
// push configuration references at configure time
222222
_configureAnnotationReferences: function() {
223223
this._configureTemplateContent();
224+
this._configureCompoundBindings();
224225
},
225226

226227
// nested template contents have been stored prototypically to avoid
@@ -236,6 +237,26 @@
236237
}, this);
237238
},
238239

240+
// Compound bindings utilize private storage on the node to store
241+
// the current state of each value that will be concatenated to generate
242+
// the final property/attribute/text value
243+
// Here we initialize the private storage array on the node with any
244+
// literal parts that won't change (could get fancy and use WeakMap)
245+
_configureCompoundBindings: function() {
246+
this._notes.forEach(function(note, i) {
247+
var node = this._nodes[i];
248+
note.bindings.forEach(function(binding) {
249+
if (binding.isCompound) {
250+
var storage = node.__compoundStorage__ ||
251+
(node.__compoundStorage__ = {});
252+
storage[binding.name] = binding.parts.map(function(part) {
253+
return part.literal;
254+
});
255+
}
256+
});
257+
}, this);
258+
},
259+
239260
// construct `$` map (from id annotations)
240261
_marshalIdNodes: function() {
241262
this.$ = {};

src/standard/effectBuilder.html

+15-4
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@
150150
});
151151
}
152152
}
153+
// We need to ensure compound bindings with literals push the literals
154+
// through regardless of whether annotation dependencies initialized
155+
// this is done with a special compoundInitialization effect which simply
156+
// kicks _applyEffectValue to push the literals through
157+
if (note.isCompound) {
158+
note.index = index;
159+
this._addPropertyEffect('__static__', 'compoundInitialization', note);
160+
}
153161
},
154162

155163
_addAnnotatedComputationEffect: function(note, part, index) {
@@ -262,11 +270,14 @@
262270
Polymer.Bind.setupBindListeners(this);
263271
},
264272

265-
_applyEffectValue: function(value, info) {
273+
_applyEffectValue: function(info, value) {
266274
var node = this._nodes[info.index];
267-
// TODO(sorvell): ideally, the info object is normalized for easy
268-
// lookup here.
269-
var property = info.name || 'textContent';
275+
var property = info.name;
276+
if (info.isCompound) {
277+
var storage = node.__compoundStorage__[property];
278+
storage[info.compoundIndex] = value;
279+
value = storage.join('');
280+
}
270281
// special processing for 'class' and 'className'; 'class' handled
271282
// when attr is serialized.
272283
if (info.kind == 'attribute') {

test/unit/bind-elements.html

+11
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,21 @@
2424
computed-from-tricky-literals2='{{computeFromTrickyLiterals(3,"tricky\,&#39;zot&#39;" )}}'
2525
computed-from-no-args="{{computeFromNoArgs( )}}"
2626
no-computed="{{foobared(noInlineComputed)}}"
27+
compound1="{{cpnd1}}{{ cpnd2 }}{{cpnd3.prop}}{{ computeCompound(cpnd4, cpnd5, 'literal')}}"
28+
compound2="literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literal')}} literal4"
29+
compoundAttr1$="{{cpnd1}}{{ cpnd2 }}{{cpnd3.prop}}{{ computeCompound(cpnd4, cpnd5, 'literal')}}"
30+
compoundAttr2$="literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literal')}} literal4"
2731
>
2832
Test
2933
</div>
3034
<span id="boundText">{{text}}</span>
3135
<span idtest id="{{boundId}}"></span>
3236
<s id="computedContent">{{computeFromTrickyLiterals(3, 'tricky\,\'zot\'')}}</s>
3337
<input id="boundInput" value="{{text::input}}">
38+
<div id="compound1">{{cpnd1}}{{cpnd2}}{{cpnd3.prop}}{{computeCompound(cpnd4, cpnd5, 'literal')}}</div>
39+
<div id="compound2">
40+
literal1 {{cpnd1}} literal2 {{cpnd2}}{{cpnd3.prop}} literal3 {{computeCompound(cpnd4, cpnd5, 'literal')}} literal4
41+
</div>
3442
</template>
3543
<script>
3644
Polymer({
@@ -237,6 +245,9 @@
237245
},
238246
computeNegativeNumber: function (num) {
239247
return num;
248+
},
249+
computeCompound: function(a, b, c) {
250+
return '' + c + b + a;
240251
}
241252
});
242253
</script>

test/unit/bind.html

+103-10
Original file line numberDiff line numberDiff line change
@@ -688,22 +688,115 @@
688688

689689
});
690690

691-
</script>
691+
suite('binding corner cases', function() {
692692

693-
<script>
694-
suite('binding corner cases', function() {
693+
// IE can create adjacent text nodes that split bindings; this test
694+
// ensures the code that addresses this is functional
695+
test('text binding after entity', function() {
696+
var el = document.createElement('x-entity-and-binding');
697+
assert.equal(el.$.binding.textContent, 'binding');
698+
});
695699

696-
// IE can create adjacent text nodes that split bindings; this test
697-
// ensures the code that addresses this is functional
698-
test('text binding after entity', function() {
699-
var el = document.createElement('x-entity-and-binding');
700-
assert.equal(el.$.binding.textContent, 'binding');
701-
});
700+
});
702701

702+
suite('compound binding / string interpolation', function() {
703+
704+
test('compound adjacent property bindings', function() {
705+
var el = document.createElement('x-basic');
706+
assert.equal(el.$.boundChild.compound1, '');
707+
el.cpnd2 = 'cpnd2';
708+
assert.equal(el.$.boundChild.compound1, 'cpnd2');
709+
el.cpnd1 = 'cpnd1';
710+
el.cpnd3 = {prop: 'cpnd3'};
711+
assert.equal(el.$.boundChild.compound1, 'cpnd1cpnd2cpnd3');
712+
el.cpnd4 = 'cpnd4';
713+
assert.equal(el.$.boundChild.compound1, 'cpnd1cpnd2cpnd3');
714+
el.cpnd5 = 'cpnd5';
715+
assert.equal(el.$.boundChild.compound1, 'cpnd1cpnd2cpnd3literalcpnd5cpnd4');
716+
});
717+
718+
test('compound property bindings with literals', function() {
719+
var el = document.createElement('x-basic');
720+
assert.equal(el.$.boundChild.compound2, 'literal1 literal2 literal3 literal4');
721+
el.cpnd1 = 'cpnd1';
722+
el.cpnd2 = 'cpnd2';
723+
el.cpnd3 = {prop: 'cpnd3'};
724+
el.cpnd4 = 'cpnd4';
725+
el.cpnd5 = 'cpnd5';
726+
assert.equal(el.$.boundChild.compound2, 'literal1 cpnd1 literal2 cpnd2cpnd3 literal3 literalcpnd5cpnd4 literal4');
727+
el.cpnd1 = null;
728+
el.cpnd2 = undefined;
729+
el.cpnd3 = {};
730+
el.cpnd4 = '';
731+
el.cpnd5 = '';
732+
assert.equal(el.$.boundChild.compound2, 'literal1 literal2 literal3 literal literal4');
733+
});
734+
735+
test('compound adjacent property bindings', function() {
736+
var el = document.createElement('x-basic');
737+
assert.equal(el.$.boundChild.getAttribute('compoundAttr1'), '');
738+
el.cpnd2 = 'cpnd2';
739+
assert.equal(el.$.boundChild.getAttribute('compoundAttr1'), 'cpnd2');
740+
el.cpnd1 = 'cpnd1';
741+
el.cpnd3 = {prop: 'cpnd3'};
742+
assert.equal(el.$.boundChild.getAttribute('compoundAttr1'), 'cpnd1cpnd2cpnd3');
743+
el.cpnd4 = 'cpnd4';
744+
assert.equal(el.$.boundChild.getAttribute('compoundAttr1'), 'cpnd1cpnd2cpnd3');
745+
el.cpnd5 = 'cpnd5';
746+
assert.equal(el.$.boundChild.getAttribute('compoundAttr1'), 'cpnd1cpnd2cpnd3literalcpnd5cpnd4');
747+
});
748+
749+
test('compound property bindings with literals', function() {
750+
var el = document.createElement('x-basic');
751+
assert.equal(el.$.boundChild.getAttribute('compoundAttr2'), 'literal1 literal2 literal3 literal4');
752+
el.cpnd1 = 'cpnd1';
753+
el.cpnd2 = 'cpnd2';
754+
el.cpnd3 = {prop: 'cpnd3'};
755+
el.cpnd4 = 'cpnd4';
756+
el.cpnd5 = 'cpnd5';
757+
assert.equal(el.$.boundChild.getAttribute('compoundAttr2'), 'literal1 cpnd1 literal2 cpnd2cpnd3 literal3 literalcpnd5cpnd4 literal4');
758+
el.cpnd1 = null;
759+
el.cpnd2 = undefined;
760+
el.cpnd3 = {};
761+
el.cpnd4 = '';
762+
el.cpnd5 = '';
763+
assert.equal(el.$.boundChild.getAttribute('compoundAttr2'), 'literal1 literal2 literal3 literal literal4');
764+
});
765+
766+
test('compound adjacent textNode bindings', function() {
767+
var el = document.createElement('x-basic');
768+
assert.equal(el.$.compound1.textContent, '');
769+
el.cpnd2 = 'cpnd2';
770+
assert.equal(el.$.compound1.textContent, 'cpnd2');
771+
el.cpnd1 = 'cpnd1';
772+
el.cpnd3 = {prop: 'cpnd3'};
773+
assert.equal(el.$.compound1.textContent, 'cpnd1cpnd2cpnd3');
774+
el.cpnd4 = 'cpnd4';
775+
assert.equal(el.$.compound1.textContent, 'cpnd1cpnd2cpnd3');
776+
el.cpnd5 = 'cpnd5';
777+
assert.equal(el.$.compound1.textContent, 'cpnd1cpnd2cpnd3literalcpnd5cpnd4');
778+
});
779+
780+
test('compound textNode bindings with literals', function() {
781+
var el = document.createElement('x-basic');
782+
assert.equal(el.$.compound2.textContent.trim(), 'literal1 literal2 literal3 literal4');
783+
el.cpnd1 = 'cpnd1';
784+
el.cpnd2 = 'cpnd2';
785+
el.cpnd3 = {prop: 'cpnd3'};
786+
el.cpnd4 = 'cpnd4';
787+
el.cpnd5 = 'cpnd5';
788+
assert.equal(el.$.compound2.textContent.trim(), 'literal1 cpnd1 literal2 cpnd2cpnd3 literal3 literalcpnd5cpnd4 literal4');
789+
el.cpnd1 = null;
790+
el.cpnd2 = undefined;
791+
el.cpnd3 = {};
792+
el.cpnd4 = '';
793+
el.cpnd5 = '';
794+
assert.equal(el.$.compound2.textContent.trim(), 'literal1 literal2 literal3 literal literal4');
703795
});
704-
</script>
705796

797+
});
706798

799+
</script>
707800

708801
</body>
709802
</html>

0 commit comments

Comments
 (0)