Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit ad711b8

Browse files
committed
fix: support MutationObserver.disconnect
1 parent 93c1468 commit ad711b8

File tree

2 files changed

+136
-5
lines changed

2 files changed

+136
-5
lines changed

Diff for: test/patch/MutationObserver.spec.js

+76-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
'use strict';
22

33
describe('MutationObserver', function () {
4+
var elt;
5+
6+
beforeEach(function () {
7+
elt = document.createElement('div');
8+
});
9+
410
it('should work', function () {
511
if (!window.MutationObserver) {
612
console.log('WARNING: skipping MutationObserver test (missing this API)');
713
return;
814
}
915

1016
var flag = false,
11-
elt = document.createElement('div'),
1217
hasParent;
1318

1419
runs(function () {
@@ -33,6 +38,76 @@ describe('MutationObserver', function () {
3338
});
3439

3540
});
41+
42+
it('should dequeue upon disconnect', function () {
43+
if (!window.MutationObserver) {
44+
console.log('WARNING: skipping MutationObserver test (missing this API)');
45+
return;
46+
}
47+
48+
var flag = false,
49+
childZone = zone.fork({
50+
dequeueTask: function () {
51+
flag = true;
52+
}
53+
});
54+
55+
childZone.run(function () {
56+
var ob = new MutationObserver(function () {});
57+
ob.observe(elt, {
58+
childList: true
59+
});
60+
ob.disconnect();
61+
expect(flag).toBe(true);
62+
});
63+
});
64+
65+
it('should enqueue once upon observation', function () {
66+
if (!window.MutationObserver) {
67+
console.log('WARNING: skipping MutationObserver test (missing this API)');
68+
return;
69+
}
70+
71+
var count = 0,
72+
childZone = zone.fork({
73+
enqueueTask: function () {
74+
count += 1;
75+
}
76+
});
77+
78+
childZone.run(function () {
79+
var ob = new MutationObserver(function () {});
80+
expect(count).toBe(0);
81+
82+
ob.observe(elt, { childList: true });
83+
expect(count).toBe(1);
84+
85+
ob.observe(elt, { childList: true });
86+
expect(count).toBe(1);
87+
});
88+
});
89+
90+
it('should only dequeue upon disconnect if something is observed', function () {
91+
if (!window.MutationObserver) {
92+
console.log('WARNING: skipping MutationObserver test (missing this API)');
93+
return;
94+
}
95+
96+
var flag = false,
97+
elt = document.createElement('div'),
98+
childZone = zone.fork({
99+
dequeueTask: function () {
100+
flag = true;
101+
}
102+
});
103+
104+
childZone.run(function () {
105+
var ob = new MutationObserver(function () {});
106+
ob.disconnect();
107+
expect(flag).toBe(false);
108+
});
109+
110+
});
36111
});
37112

38113
describe('WebKitMutationObserver', function () {

Diff for: zone.js

+60-4
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ Zone.prototype = {
5757
return new Zone(this, locals);
5858
},
5959

60-
bind: function (fn) {
61-
this.enqueueTask(fn);
60+
bind: function (fn, skipEnqueue) {
61+
skipEnqueue || this.enqueueTask(fn);
6262
var zone = this.fork();
6363
return function zoneBoundFn() {
6464
return zone.run(fn, this, arguments);
@@ -364,8 +364,8 @@ Zone.patch = function patch () {
364364
'catch'
365365
]);
366366
}
367-
Zone.patchClass('MutationObserver');
368-
Zone.patchClass('WebKitMutationObserver');
367+
Zone.patchMutationObserverClass('MutationObserver');
368+
Zone.patchMutationObserverClass('WebKitMutationObserver');
369369
};
370370

371371
//
@@ -454,6 +454,62 @@ Zone.patchClass = function (className) {
454454
};
455455
};
456456

457+
// wrap some native API on `window`
458+
Zone.patchMutationObserverClass = function (className) {
459+
var OriginalClass = window[className];
460+
if (!OriginalClass) {
461+
return;
462+
}
463+
window[className] = function (fn) {
464+
this._o = new OriginalClass(zone.bind(fn, true));
465+
};
466+
467+
var instance = new OriginalClass(function () {});
468+
469+
window[className].prototype.disconnect = function () {
470+
var result = this._o.disconnect.apply(this._o, arguments);
471+
this._active && zone.dequeueTask();
472+
this._active = false;
473+
return result;
474+
};
475+
476+
window[className].prototype.observe = function () {
477+
if (!this._active) {
478+
zone.enqueueTask();
479+
}
480+
dump(this._active)
481+
this._active = true;
482+
return this._o.observe.apply(this._o, arguments);
483+
};
484+
485+
var prop;
486+
for (prop in instance) {
487+
(function (prop) {
488+
if (typeof window[className].prototype !== undefined) {
489+
return;
490+
}
491+
if (typeof instance[prop] === 'function') {
492+
window[className].prototype[prop] = function () {
493+
return this._o[prop].apply(this._o, arguments);
494+
};
495+
} else {
496+
Object.defineProperty(window[className].prototype, prop, {
497+
set: function (fn) {
498+
if (typeof fn === 'function') {
499+
this._o[prop] = zone.bind(fn);
500+
} else {
501+
this._o[prop] = fn;
502+
}
503+
},
504+
get: function () {
505+
return this._o[prop];
506+
}
507+
});
508+
}
509+
}(prop));
510+
}
511+
};
512+
457513
Zone.eventNames = 'copy cut paste abort blur focus canplay canplaythrough change click contextmenu dblclick drag dragend dragenter dragleave dragover dragstart drop durationchange emptied ended input invalid keydown keypress keyup load loadeddata loadedmetadata loadstart mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup pause play playing progress ratechange reset scroll seeked seeking select show stalled submit suspend timeupdate volumechange waiting mozfullscreenchange mozfullscreenerror mozpointerlockchange mozpointerlockerror error'.split(' ');
458514
Zone.onEventNames = Zone.eventNames.map(function (property) {
459515
return 'on' + property;

0 commit comments

Comments
 (0)