Skip to content

Commit f50e329

Browse files
Merge pull request #704 from bigopon/fix-patching-array
fix(ArrayObservation): ensure patch applied only once
1 parent 9b103d9 commit f50e329

File tree

2 files changed

+111
-96
lines changed

2 files changed

+111
-96
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
"binding",
88
"databinding"
99
],
10+
"scripts": {
11+
"test": "karma start"
12+
},
1013
"homepage": "http://aurelia.io",
1114
"bugs": {
1215
"url": "https://github.com/aurelia/binding/issues"

src/array-observation.js

Lines changed: 108 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,121 @@
11
/* eslint-disable no-extend-native */
22
import {ModifyCollectionObserver} from './collection-observation';
3+
import * as LogManager from 'aurelia-logging';
34

4-
let pop = Array.prototype.pop;
5-
let push = Array.prototype.push;
6-
let reverse = Array.prototype.reverse;
7-
let shift = Array.prototype.shift;
8-
let sort = Array.prototype.sort;
9-
let splice = Array.prototype.splice;
10-
let unshift = Array.prototype.unshift;
5+
const arrayProto = Array.prototype;
6+
const pop = arrayProto.pop;
7+
const push = arrayProto.push;
8+
const reverse = arrayProto.reverse;
9+
const shift = arrayProto.shift;
10+
const sort = arrayProto.sort;
11+
const splice = arrayProto.splice;
12+
const unshift = arrayProto.unshift;
1113

12-
Array.prototype.pop = function() {
13-
let notEmpty = this.length > 0;
14-
let methodCallResult = pop.apply(this, arguments);
15-
if (notEmpty && this.__array_observer__ !== undefined) {
16-
this.__array_observer__.addChangeRecord({
17-
type: 'delete',
18-
object: this,
19-
name: this.length,
20-
oldValue: methodCallResult
21-
});
22-
}
23-
return methodCallResult;
24-
};
14+
if (arrayProto.__au_patched__) {
15+
LogManager
16+
.getLogger('array-observation')
17+
.warn('Detected 2nd attempt of patching array from Aurelia binding.'
18+
+ ' This is probably caused by dependency mismatch between core modules and a 3rd party plugin.'
19+
+ ' Please see https://github.com/aurelia/cli/pull/906 if you are using webpack.'
20+
);
21+
} else {
22+
arrayProto.__au_patched__ = 1;
23+
arrayProto.pop = function() {
24+
let notEmpty = this.length > 0;
25+
let methodCallResult = pop.apply(this, arguments);
26+
if (notEmpty && this.__array_observer__ !== undefined) {
27+
this.__array_observer__.addChangeRecord({
28+
type: 'delete',
29+
object: this,
30+
name: this.length,
31+
oldValue: methodCallResult
32+
});
33+
}
34+
return methodCallResult;
35+
};
2536

26-
Array.prototype.push = function() {
27-
let methodCallResult = push.apply(this, arguments);
28-
if (this.__array_observer__ !== undefined) {
29-
this.__array_observer__.addChangeRecord({
30-
type: 'splice',
31-
object: this,
32-
index: this.length - arguments.length,
33-
removed: [],
34-
addedCount: arguments.length
35-
});
36-
}
37-
return methodCallResult;
38-
};
37+
arrayProto.push = function() {
38+
let methodCallResult = push.apply(this, arguments);
39+
if (this.__array_observer__ !== undefined) {
40+
this.__array_observer__.addChangeRecord({
41+
type: 'splice',
42+
object: this,
43+
index: this.length - arguments.length,
44+
removed: [],
45+
addedCount: arguments.length
46+
});
47+
}
48+
return methodCallResult;
49+
};
3950

40-
Array.prototype.reverse = function() {
41-
let oldArray;
42-
if (this.__array_observer__ !== undefined) {
43-
this.__array_observer__.flushChangeRecords();
44-
oldArray = this.slice();
45-
}
46-
let methodCallResult = reverse.apply(this, arguments);
47-
if (this.__array_observer__ !== undefined) {
48-
this.__array_observer__.reset(oldArray);
49-
}
50-
return methodCallResult;
51-
};
51+
arrayProto.reverse = function() {
52+
let oldArray;
53+
if (this.__array_observer__ !== undefined) {
54+
this.__array_observer__.flushChangeRecords();
55+
oldArray = this.slice();
56+
}
57+
let methodCallResult = reverse.apply(this, arguments);
58+
if (this.__array_observer__ !== undefined) {
59+
this.__array_observer__.reset(oldArray);
60+
}
61+
return methodCallResult;
62+
};
5263

53-
Array.prototype.shift = function() {
54-
let notEmpty = this.length > 0;
55-
let methodCallResult = shift.apply(this, arguments);
56-
if (notEmpty && this.__array_observer__ !== undefined) {
57-
this.__array_observer__.addChangeRecord({
58-
type: 'delete',
59-
object: this,
60-
name: 0,
61-
oldValue: methodCallResult
62-
});
63-
}
64-
return methodCallResult;
65-
};
64+
arrayProto.shift = function() {
65+
let notEmpty = this.length > 0;
66+
let methodCallResult = shift.apply(this, arguments);
67+
if (notEmpty && this.__array_observer__ !== undefined) {
68+
this.__array_observer__.addChangeRecord({
69+
type: 'delete',
70+
object: this,
71+
name: 0,
72+
oldValue: methodCallResult
73+
});
74+
}
75+
return methodCallResult;
76+
};
6677

67-
Array.prototype.sort = function() {
68-
let oldArray;
69-
if (this.__array_observer__ !== undefined) {
70-
this.__array_observer__.flushChangeRecords();
71-
oldArray = this.slice();
72-
}
73-
let methodCallResult = sort.apply(this, arguments);
74-
if (this.__array_observer__ !== undefined) {
75-
this.__array_observer__.reset(oldArray);
76-
}
77-
return methodCallResult;
78-
};
78+
arrayProto.sort = function() {
79+
let oldArray;
80+
if (this.__array_observer__ !== undefined) {
81+
this.__array_observer__.flushChangeRecords();
82+
oldArray = this.slice();
83+
}
84+
let methodCallResult = sort.apply(this, arguments);
85+
if (this.__array_observer__ !== undefined) {
86+
this.__array_observer__.reset(oldArray);
87+
}
88+
return methodCallResult;
89+
};
7990

80-
Array.prototype.splice = function() {
81-
let methodCallResult = splice.apply(this, arguments);
82-
if (this.__array_observer__ !== undefined) {
83-
this.__array_observer__.addChangeRecord({
84-
type: 'splice',
85-
object: this,
86-
index: +arguments[0],
87-
removed: methodCallResult,
88-
addedCount: arguments.length > 2 ? arguments.length - 2 : 0
89-
});
90-
}
91-
return methodCallResult;
92-
};
91+
arrayProto.splice = function() {
92+
let methodCallResult = splice.apply(this, arguments);
93+
if (this.__array_observer__ !== undefined) {
94+
this.__array_observer__.addChangeRecord({
95+
type: 'splice',
96+
object: this,
97+
index: +arguments[0],
98+
removed: methodCallResult,
99+
addedCount: arguments.length > 2 ? arguments.length - 2 : 0
100+
});
101+
}
102+
return methodCallResult;
103+
};
93104

94-
Array.prototype.unshift = function() {
95-
let methodCallResult = unshift.apply(this, arguments);
96-
if (this.__array_observer__ !== undefined) {
97-
this.__array_observer__.addChangeRecord({
98-
type: 'splice',
99-
object: this,
100-
index: 0,
101-
removed: [],
102-
addedCount: arguments.length
103-
});
104-
}
105-
return methodCallResult;
106-
};
105+
arrayProto.unshift = function() {
106+
let methodCallResult = unshift.apply(this, arguments);
107+
if (this.__array_observer__ !== undefined) {
108+
this.__array_observer__.addChangeRecord({
109+
type: 'splice',
110+
object: this,
111+
index: 0,
112+
removed: [],
113+
addedCount: arguments.length
114+
});
115+
}
116+
return methodCallResult;
117+
};
118+
}
107119

108120
export function getArrayObserver(taskQueue, array) {
109121
return ModifyArrayObserver.for(taskQueue, array);

0 commit comments

Comments
 (0)