Skip to content

Commit e6d558e

Browse files
committed
Use stronger check for PropertyEffects clients. Fixes #5017
1 parent 0e564ae commit e6d558e

11 files changed

Lines changed: 140 additions & 30 deletions

lib/mixins/property-effects.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@
567567
// e.g.: foo="{{obj.sub}}", path: 'obj.sub.prop', set 'foo.prop'=obj.sub.prop
568568
if (hasPaths && part.source && (path.length > part.source.length) &&
569569
(binding.kind == 'property') && !binding.isCompound &&
570+
node.__isPropertyEffectsClient &&
570571
node.__dataHasAccessor && node.__dataHasAccessor[binding.target]) {
571572
let value = props[path];
572573
path = Polymer.Path.translate(part.source, binding.target, path);
@@ -603,7 +604,8 @@
603604
} else {
604605
// Property binding
605606
let prop = binding.target;
606-
if (node.__dataHasAccessor && node.__dataHasAccessor[prop]) {
607+
if (node.__isPropertyEffectsClient &&
608+
node.__dataHasAccessor && node.__dataHasAccessor[prop]) {
607609
if (!node[TYPES.READ_ONLY] || !node[TYPES.READ_ONLY][prop]) {
608610
if (node._setPendingProperty(prop, value)) {
609611
inst._enqueueClient(node);
@@ -1131,6 +1133,9 @@
11311133

11321134
constructor() {
11331135
super();
1136+
/** @type {boolean} */
1137+
// Used to identify users of this mixin, ala instanceof
1138+
this.__isPropertyEffectsClient = true;
11341139
/** @type {number} */
11351140
// NOTE: used to track re-entrant calls to `_flushProperties`
11361141
// path changes dirty check against `__dataTemp` only during one "turn"

test/unit/path-effects-elements.html

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,32 @@
77
Code distributed by Google as part of the polymer project is also
88
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
99
-->
10+
11+
<link rel="import" href="../../lib/mixins/properties-mixin.html">
12+
13+
<script>
14+
class XPropertiesElement extends Polymer.PropertiesMixin(HTMLElement) {
15+
static get properties() {
16+
return {
17+
obj: Object
18+
};
19+
}
20+
constructor() {
21+
super();
22+
this.resetObservers();
23+
}
24+
// Allow re-set objects to show in _propertiesChanged
25+
_shouldPropertyChange(property, value, old) {
26+
return (typeof value == 'object') ||
27+
super._shouldPropertyChange(property, value, old);
28+
}
29+
resetObservers() {
30+
this._propertiesChanged = sinon.spy();
31+
}
32+
}
33+
customElements.define('x-pe', XPropertiesElement);
34+
</script>
35+
1036
<script>
1137
Polymer({
1238
is: 'x-basic',
@@ -103,6 +129,7 @@
103129
<x-compose id="compose" obj="{{nested.obj}}"></x-compose>
104130
<x-forward id="forward" obj="{{nested.obj}}"></x-forward>
105131
<div id="boundChild" computed-from-paths="{{computeFromPaths(a, nested.b, nested.obj.c)}}" array-length="{{data.length}}"></div>
132+
<x-pe id="pe" obj="[[nested.obj]]"></x-pe>
106133
</template>
107134
<script>
108135
Polymer({
@@ -161,6 +188,7 @@
161188
if (this.$) {
162189
this.$.compose.resetObservers();
163190
this.$.forward.resetObservers();
191+
this.$.pe.resetObservers();
164192
}
165193
},
166194
computeFromPaths: function(a, b, c) {

test/unit/path-effects.html

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
document.body.removeChild(el);
5050
});
5151

52-
function verifyObserverOutput(nestingLevel, nested) {
52+
async function verifyObserverOutput(nestingLevel, nested) {
5353
assert.equal(el.computed, '[' + nested.obj.value + ']');
5454
assert.equal(el.nestedChanged.callCount, nestingLevel == 0 ? 1 : 0);
5555
if (nestingLevel == 0) {
@@ -92,6 +92,7 @@
9292
assert.equal(el.$.compose.$.basic2.getAttribute('attrvalue'), '42');
9393
assert.equal(el.$.forward.$.compose.$.basic1.getAttribute('attrvalue'), '42');
9494
assert.equal(el.$.forward.$.compose.$.basic2.getAttribute('attrvalue'), '42');
95+
assert.equal(el.$.pe.obj, nested.obj);
9596
switch (nestingLevel) {
9697
case 0:
9798
assert.equal(el.nestedSubpathChanged.firstCall.args[0].path, 'nested');
@@ -104,6 +105,9 @@
104105
assert.equal(el.$.forward.objSubpathChanged.firstCall.args[0].value, nested.obj);
105106
assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].path, 'obj');
106107
assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].value, nested.obj);
108+
await Promise.resolve(); // x-pe uses async PropertiesChanged
109+
assert.equal(el.$.pe._propertiesChanged.callCount, 1);
110+
assert.equal(el.$.pe._propertiesChanged.firstCall.args[1].obj, nested.obj);
107111
break;
108112
case 1:
109113
assert.equal(el.nestedSubpathChanged.firstCall.args[0].path, 'nested.obj');
@@ -116,6 +120,9 @@
116120
assert.equal(el.$.forward.objSubpathChanged.firstCall.args[0].value, nested.obj);
117121
assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].path, 'obj');
118122
assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].value, nested.obj);
123+
await Promise.resolve(); // x-pe uses async PropertiesChanged
124+
assert.equal(el.$.pe._propertiesChanged.callCount, 1);
125+
assert.equal(el.$.pe._propertiesChanged.firstCall.args[1].obj, nested.obj);
119126
break;
120127
case 2:
121128
assert.equal(el.nestedSubpathChanged.firstCall.args[0].path, 'nested.obj.value');
@@ -128,22 +135,27 @@
128135
assert.equal(el.$.forward.objSubpathChanged.firstCall.args[0].value, 42);
129136
assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].path, 'obj.value');
130137
assert.equal(el.$.forward.$.compose.objSubpathChanged.firstCall.args[0].value, 42);
138+
await Promise.resolve(); // x-pe uses async PropertiesChanged
139+
// Note the PropertiesMixin element only sees a deep set to 'nested.obj.value'
140+
// because it overrides _shouldPropertyChange to allow object re-sets through
141+
assert.equal(el.$.pe._propertiesChanged.callCount, 1);
142+
assert.equal(el.$.pe._propertiesChanged.firstCall.args[1].obj, nested.obj);
131143
break;
132144
}
133145
}
134146

135-
test('downward data flow', function() {
147+
test('downward data flow', async function() {
136148
// Do the thing
137149
el.nested = {
138150
obj: {
139151
value: 42
140152
}
141153
};
142154
// Verify
143-
verifyObserverOutput(0, el.nested);
155+
await verifyObserverOutput(0, el.nested);
144156
});
145157

146-
test('notification from basic element property change', function() {
158+
test('notification from basic element property change', async function() {
147159
// Setup
148160
el.nested = {
149161
obj: {
@@ -154,10 +166,10 @@
154166
// Do the thing
155167
el.$.basic.notifyingValue = 42;
156168
// Verify
157-
verifyObserverOutput(2, el.nested);
169+
await verifyObserverOutput(2, el.nested);
158170
});
159171

160-
test('notification from composed element property change', function() {
172+
test('notification from composed element property change', async function() {
161173
// Setup
162174
el.nested = {
163175
obj: {
@@ -168,10 +180,10 @@
168180
// Do the thing
169181
el.$.compose.$.basic1.notifyingValue = 42;
170182
// Verify
171-
verifyObserverOutput(2, el.nested);
183+
await verifyObserverOutput(2, el.nested);
172184
});
173185

174-
test('notification from forward\'s composed element property change', function() {
186+
test('notification from forward\'s composed element property change', async function() {
175187
// Setup
176188
el.nested = {
177189
obj: {
@@ -182,10 +194,10 @@
182194
// Do the thing
183195
el.$.forward.$.compose.$.basic1.notifyingValue = 42;
184196
// Verify
185-
verifyObserverOutput(2, el.nested);
197+
await verifyObserverOutput(2, el.nested);
186198
});
187199

188-
test('notification from set in top element', function() {
200+
test('notification from set in top element', async function() {
189201
// Setup
190202
el.nested = {
191203
obj: {
@@ -196,10 +208,10 @@
196208
// Do the thing
197209
el.set('nested.obj.value', 42);
198210
// Verify
199-
verifyObserverOutput(2, el.nested);
211+
await verifyObserverOutput(2, el.nested);
200212
});
201213

202-
test('notification from set in composed element', function() {
214+
test('notification from set in composed element', async function() {
203215
// Setup
204216
el.nested = {
205217
obj: {
@@ -210,10 +222,10 @@
210222
// Do the thing
211223
el.$.compose.set('obj.value', 42);
212224
// Verify
213-
verifyObserverOutput(2, el.nested);
225+
await verifyObserverOutput(2, el.nested);
214226
});
215227

216-
test('notification from set in forward element', function() {
228+
test('notification from set in forward element', async function() {
217229
// Setup
218230
el.nested = {
219231
obj: {
@@ -224,10 +236,10 @@
224236
// Do the thing
225237
el.$.forward.set('obj.value', 42);
226238
// Verify
227-
verifyObserverOutput(2, el.nested);
239+
await verifyObserverOutput(2, el.nested);
228240
});
229241

230-
test('notification from set in forward\'s composed element', function() {
242+
test('notification from set in forward\'s composed element', async function() {
231243
// Setup
232244
el.nested = {
233245
obj: {
@@ -238,10 +250,10 @@
238250
// Do the thing
239251
el.$.forward.$.compose.set('obj.value', 42);
240252
// Verify
241-
verifyObserverOutput(2, el.nested);
253+
await verifyObserverOutput(2, el.nested);
242254
});
243255

244-
test('notification from object change in compose element', function() {
256+
test('notification from object change in compose element', async function() {
245257
// Setup
246258
el.nested = {
247259
obj: {
@@ -254,10 +266,10 @@
254266
value: 42
255267
};
256268
// Verify
257-
verifyObserverOutput(1, el.nested);
269+
await verifyObserverOutput(1, el.nested);
258270
});
259271

260-
test('notification from object change in forward element', function() {
272+
test('notification from object change in forward element', async function() {
261273
// Setup
262274
el.nested = {
263275
obj: {
@@ -270,10 +282,10 @@
270282
value: 42
271283
};
272284
// Verify
273-
verifyObserverOutput(1, el.nested);
285+
await verifyObserverOutput(1, el.nested);
274286
});
275287

276-
test('notification from object change in forward\'s compose element', function() {
288+
test('notification from object change in forward\'s compose element', async function() {
277289
// Setup
278290
el.nested = {
279291
obj: {
@@ -287,7 +299,7 @@
287299
value: 42
288300
};
289301
// Verify
290-
verifyObserverOutput(1, el.nested);
302+
await verifyObserverOutput(1, el.nested);
291303
});
292304

293305
test('cached paths get invalidated by object sets', function() {

types/externs/closure-types.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* DO NOT EDIT
3+
*
4+
* This file was automatically generated by
5+
* https://github.com/Polymer/gen-typescript-declarations
6+
*
7+
* To modify these typings, edit the source file(s):
8+
* externs/closure-types.js
9+
*/
10+

types/externs/polymer-externs.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* DO NOT EDIT
3+
*
4+
* This file was automatically generated by
5+
* https://github.com/Polymer/gen-typescript-declarations
6+
*
7+
* To modify these typings, edit the source file(s):
8+
* externs/polymer-externs.js
9+
*/
10+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* DO NOT EDIT
3+
*
4+
* This file was automatically generated by
5+
* https://github.com/Polymer/gen-typescript-declarations
6+
*
7+
* To modify these typings, edit the source file(s):
8+
* externs/polymer-internal-shared-types.js
9+
*/
10+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* DO NOT EDIT
3+
*
4+
* This file was automatically generated by
5+
* https://github.com/Polymer/gen-typescript-declarations
6+
*
7+
* To modify these typings, edit the source file(s):
8+
* externs/webcomponents-externs.js
9+
*/
10+

types/gulpfile.d.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* DO NOT EDIT
3+
*
4+
* This file was automatically generated by
5+
* https://github.com/Polymer/gen-typescript-declarations
6+
*
7+
* To modify these typings, edit the source file(s):
8+
* gulpfile.js
9+
*/
10+
11+
declare class BackfillStream {
12+
_transform(file: any, enc: any, cb: any): any;
13+
_flush(cb: any): any;
14+
}
15+
16+
declare class AddClosureTypeImport {
17+
_transform(file: any, enc: any, cb: any): any;
18+
}

types/lib/legacy/mutable-data-behavior.d.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,6 @@ declare namespace Polymer {
6666
_shouldPropertyChange(property: string, value: any, old: any): boolean;
6767
}
6868

69-
const MutableDataBehavior: object;
70-
7169
/**
7270
* Legacy element behavior to add the optional ability to skip strict
7371
* dirty-checking for objects and arrays (always consider them to be
@@ -130,6 +128,4 @@ declare namespace Polymer {
130128
*/
131129
_shouldPropertyChange(property: string, value: any, old: any): boolean;
132130
}
133-
134-
const OptionalMutableDataBehavior: object;
135131
}

types/lib/legacy/templatizer-behavior.d.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,4 @@ declare namespace Polymer {
111111
*/
112112
modelForElement(el: HTMLElement|null): TemplateInstanceBase|null;
113113
}
114-
115-
const Templatizer: object;
116114
}

0 commit comments

Comments
 (0)