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

(WIP)(core): add scoped zone.js support #1126

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion karma-base.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
module.exports = function(config) {
config.set({
basePath: '',
client: {errorpolicy: config.errorpolicy},
client: {errorpolicy: config.errorpolicy, entryPoint: config.entryPoint},
files: [
'node_modules/systemjs/dist/system-polyfills.js', 'node_modules/systemjs/dist/system.src.js',
'node_modules/whatwg-fetch/fetch.js',
Expand Down
5 changes: 5 additions & 0 deletions karma-build-outside-jasmine.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

module.exports = function (config) {
require('./karma-build-jasmine.conf.js')(config);
config.files.push('build/test/browser-outside-zone-setup.js');
};
54 changes: 27 additions & 27 deletions lib/browser/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,29 @@ Zone.__load_patch('util', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
api.bindArguments = bindArguments;
});

Zone.__load_patch('timers', (global: any) => {
Zone.__load_patch('timers', (global: any, _: ZoneType, api: _ZonePrivate) => {
const set = 'set';
const clear = 'clear';
patchTimer(global, set, clear, 'Timeout');
patchTimer(global, set, clear, 'Interval');
patchTimer(global, set, clear, 'Immediate');
patchTimer(global, set, clear, 'Timeout', api);
patchTimer(global, set, clear, 'Interval', api);
patchTimer(global, set, clear, 'Immediate', api);
});

Zone.__load_patch('requestAnimationFrame', (global: any) => {
patchTimer(global, 'request', 'cancel', 'AnimationFrame');
patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame');
patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame');
Zone.__load_patch('requestAnimationFrame', (global: any, _: ZoneType, api: _ZonePrivate) => {
patchTimer(global, 'request', 'cancel', 'AnimationFrame', api);
patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame', api);
patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame', api);
});

Zone.__load_patch('blocking', (global: any, Zone: ZoneType) => {
Zone.__load_patch('blocking', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
const blockingMethods = ['alert', 'prompt', 'confirm'];
for (let i = 0; i < blockingMethods.length; i++) {
const name = blockingMethods[i];
patchMethod(global, name, (delegate, symbol, name) => {
return function(s: any, args: any[]) {
return Zone.current.run(delegate, global, args, name);
};
});
}, api);
}
});

Expand All @@ -63,33 +63,33 @@ Zone.__load_patch('EventTarget', (global: any, Zone: ZoneType, api: _ZonePrivate
// patch XMLHttpRequestEventTarget's addEventListener/removeEventListener
const XMLHttpRequestEventTarget = (global as any)['XMLHttpRequestEventTarget'];
if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) {
api.patchEventTarget(global, [XMLHttpRequestEventTarget.prototype]);
api.patchEventTarget(global, [XMLHttpRequestEventTarget.prototype], api);
}
patchClass('MutationObserver');
patchClass('WebKitMutationObserver');
patchClass('IntersectionObserver');
patchClass('FileReader');
patchClass('MutationObserver', api);
patchClass('WebKitMutationObserver', api);
patchClass('IntersectionObserver', api);
patchClass('FileReader', api);
});

Zone.__load_patch('on_property', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
propertyDescriptorPatch(api, global);
propertyPatch();
registerElementPatch(global);
propertyPatch(api);
registerElementPatch(global, api);
});

Zone.__load_patch('canvas', (global: any) => {
Zone.__load_patch('canvas', (global: any, _: ZoneType, api: _ZonePrivate) => {
const HTMLCanvasElement = global['HTMLCanvasElement'];
if (typeof HTMLCanvasElement !== 'undefined' && HTMLCanvasElement.prototype &&
HTMLCanvasElement.prototype.toBlob) {
patchMacroTask(HTMLCanvasElement.prototype, 'toBlob', (self: any, args: any[]) => {
return {name: 'HTMLCanvasElement.toBlob', target: self, cbIdx: 0, args: args};
});
}, api);
}
});

Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
Zone.__load_patch('XHR', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
// Treat XMLHttpRequest as a macrotask.
patchXHR(global);
patchXHR(global, api);

const XHR_TASK = zoneSymbol('xhrTask');
const XHR_SYNC = zoneSymbol('xhrSync');
Expand All @@ -105,7 +105,7 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
aborted: boolean;
}

function patchXHR(window: any) {
function patchXHR(window: any, api: _ZonePrivate) {
const XMLHttpRequestPrototype: any = XMLHttpRequest.prototype;

function findPendingTask(target: any) {
Expand Down Expand Up @@ -201,7 +201,7 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
self[XHR_SYNC] = args[2] == false;
self[XHR_URL] = args[1];
return openNative!.apply(self, args);
});
}, api);

const XMLHTTPREQUEST_SOURCE = 'XMLHttpRequest.send';
const fetchTaskAborting = zoneSymbol('fetchTaskAborting');
Expand Down Expand Up @@ -230,7 +230,7 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
task.invoke();
}
}
});
}, api);

const abortNative =
patchMethod(XMLHttpRequestPrototype, 'abort', () => function(self: any, args: any[]) {
Expand All @@ -251,14 +251,14 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
// Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no
// task
// to cancel. Do nothing.
});
}, api);
}
});

Zone.__load_patch('geolocation', (global: any) => {
Zone.__load_patch('geolocation', (global: any, _: ZoneType, api: _ZonePrivate) => {
/// GEO_LOCATION
if (global['navigator'] && global['navigator'].geolocation) {
patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']);
patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition'], api);
}
});

Expand Down
11 changes: 10 additions & 1 deletion lib/browser/define-property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ const _getOwnPropertyDescriptor = (Object as any)[zoneSymbol('getOwnPropertyDesc
const _create = Object.create;
const unconfigurablesKey = zoneSymbol('unconfigurables');

export function propertyPatch() {
export function propertyPatch(api: _ZonePrivate) {
Object.defineProperty = function(obj: any, prop: string, desc: any) {
if (api.getCurrentScope() === 'outside') {
return _defineProperty(obj, prop, desc);
}
if (isUnconfigurable(obj, prop)) {
throw new TypeError('Cannot assign to read only property \'' + prop + '\' of ' + obj);
}
Expand All @@ -38,6 +41,9 @@ export function propertyPatch() {
};

Object.create = <any>function(obj: any, proto: any) {
if (api.getCurrentScope() === 'outside') {
return _create(obj, proto);
}
if (typeof proto === 'object' && !Object.isFrozen(proto)) {
Object.keys(proto).forEach(function(prop) {
proto[prop] = rewriteDescriptor(obj, prop, proto[prop]);
Expand All @@ -48,6 +54,9 @@ export function propertyPatch() {

Object.getOwnPropertyDescriptor = function(obj, prop) {
const desc = _getOwnPropertyDescriptor(obj, prop);
if (api.getCurrentScope() === 'outside') {
return desc;
}
if (desc && isUnconfigurable(obj, prop)) {
desc.configurable = false;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/browser/event-target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export function eventTargetPatch(_global: any, api: _ZonePrivate) {
}
// vh is validateHandler to check event handler
// is valid or not(for security check)
patchEventTarget(_global, apiTypes, {vh: checkIEAndCrossContext});
patchEventTarget(_global, apiTypes, api, {vh: checkIEAndCrossContext});
api.patchEventTarget = patchEventTarget;

return true;
Expand Down
56 changes: 31 additions & 25 deletions lib/browser/property-descriptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ const documentEventNames = [
'afterscriptexecute', 'beforescriptexecute', 'DOMContentLoaded', 'fullscreenchange',
'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange', 'fullscreenerror',
'mozfullscreenerror', 'webkitfullscreenerror', 'msfullscreenerror', 'readystatechange',
'visibilitychange'
'visibilitychange', 'freeze', 'resume'
];
const windowEventNames = [
'absolutedeviceorientation',
Expand Down Expand Up @@ -255,14 +255,15 @@ function filterProperties(
}

export function patchFilteredProperties(
target: any, onProperties: string[], ignoreProperties: IgnoreProperty[], prototype?: any) {
target: any, onProperties: string[], ignoreProperties: IgnoreProperty[], api: _ZonePrivate,
prototype?: any) {
// check whether target is available, sometimes target will be undefined
// because different browser or some 3rd party plugin.
if (!target) {
return;
}
const filteredProperties: string[] = filterProperties(target, onProperties, ignoreProperties);
patchOnProperties(target, filteredProperties, prototype);
patchOnProperties(target, filteredProperties, api, prototype);
}

export function propertyDescriptorPatch(api: _ZonePrivate, _global: any) {
Expand All @@ -282,56 +283,61 @@ export function propertyDescriptorPatch(api: _ZonePrivate, _global: any) {
// so we need to pass WindowPrototype to check onProp exist or not
patchFilteredProperties(
internalWindow, eventNames.concat(['messageerror']),
ignoreProperties ? ignoreProperties.concat(ignoreErrorProperties) : ignoreProperties,
ignoreProperties ? ignoreProperties.concat(ignoreErrorProperties) : ignoreProperties, api,
ObjectGetPrototypeOf(internalWindow));
patchFilteredProperties(Document.prototype, eventNames, ignoreProperties);
patchFilteredProperties(Document.prototype, eventNames, ignoreProperties, api);

if (typeof internalWindow['SVGElement'] !== 'undefined') {
patchFilteredProperties(
internalWindow['SVGElement'].prototype, eventNames, ignoreProperties);
internalWindow['SVGElement'].prototype, eventNames, ignoreProperties, api);
}
patchFilteredProperties(Element.prototype, eventNames, ignoreProperties);
patchFilteredProperties(HTMLElement.prototype, eventNames, ignoreProperties);
patchFilteredProperties(HTMLMediaElement.prototype, mediaElementEventNames, ignoreProperties);
patchFilteredProperties(Element.prototype, eventNames, ignoreProperties, api);
patchFilteredProperties(HTMLElement.prototype, eventNames, ignoreProperties, api);
patchFilteredProperties(
HTMLMediaElement.prototype, mediaElementEventNames, ignoreProperties, api);
patchFilteredProperties(
HTMLFrameSetElement.prototype, windowEventNames.concat(frameSetEventNames),
ignoreProperties);
ignoreProperties, api);
patchFilteredProperties(
HTMLBodyElement.prototype, windowEventNames.concat(frameSetEventNames), ignoreProperties);
patchFilteredProperties(HTMLFrameElement.prototype, frameEventNames, ignoreProperties);
patchFilteredProperties(HTMLIFrameElement.prototype, frameEventNames, ignoreProperties);
HTMLBodyElement.prototype, windowEventNames.concat(frameSetEventNames), ignoreProperties,
api);
patchFilteredProperties(HTMLFrameElement.prototype, frameEventNames, ignoreProperties, api);
patchFilteredProperties(HTMLIFrameElement.prototype, frameEventNames, ignoreProperties, api);

const HTMLMarqueeElement = internalWindow['HTMLMarqueeElement'];
if (HTMLMarqueeElement) {
patchFilteredProperties(HTMLMarqueeElement.prototype, marqueeEventNames, ignoreProperties);
patchFilteredProperties(
HTMLMarqueeElement.prototype, marqueeEventNames, ignoreProperties, api);
}
const Worker = internalWindow['Worker'];
if (Worker) {
patchFilteredProperties(Worker.prototype, workerEventNames, ignoreProperties);
patchFilteredProperties(Worker.prototype, workerEventNames, ignoreProperties, api);
}
}
patchFilteredProperties(XMLHttpRequest.prototype, XMLHttpRequestEventNames, ignoreProperties);
patchFilteredProperties(
XMLHttpRequest.prototype, XMLHttpRequestEventNames, ignoreProperties, api);
const XMLHttpRequestEventTarget = _global['XMLHttpRequestEventTarget'];
if (XMLHttpRequestEventTarget) {
patchFilteredProperties(
XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype,
XMLHttpRequestEventNames, ignoreProperties);
XMLHttpRequestEventNames, ignoreProperties, api);
}
if (typeof IDBIndex !== 'undefined') {
patchFilteredProperties(IDBIndex.prototype, IDBIndexEventNames, ignoreProperties);
patchFilteredProperties(IDBRequest.prototype, IDBIndexEventNames, ignoreProperties);
patchFilteredProperties(IDBOpenDBRequest.prototype, IDBIndexEventNames, ignoreProperties);
patchFilteredProperties(IDBDatabase.prototype, IDBIndexEventNames, ignoreProperties);
patchFilteredProperties(IDBTransaction.prototype, IDBIndexEventNames, ignoreProperties);
patchFilteredProperties(IDBCursor.prototype, IDBIndexEventNames, ignoreProperties);
patchFilteredProperties(IDBIndex.prototype, IDBIndexEventNames, ignoreProperties, api);
patchFilteredProperties(IDBRequest.prototype, IDBIndexEventNames, ignoreProperties, api);
patchFilteredProperties(
IDBOpenDBRequest.prototype, IDBIndexEventNames, ignoreProperties, api);
patchFilteredProperties(IDBDatabase.prototype, IDBIndexEventNames, ignoreProperties, api);
patchFilteredProperties(IDBTransaction.prototype, IDBIndexEventNames, ignoreProperties, api);
patchFilteredProperties(IDBCursor.prototype, IDBIndexEventNames, ignoreProperties, api);
}
if (supportsWebSocket) {
patchFilteredProperties(WebSocket.prototype, websocketEventNames, ignoreProperties);
patchFilteredProperties(WebSocket.prototype, websocketEventNames, ignoreProperties, api);
}
} else {
// Safari, Android browsers (Jelly Bean)
patchViaCapturingAllTheEvents();
patchClass('XMLHttpRequest');
patchClass('XMLHttpRequest', api);
if (supportsWebSocket) {
webSocketPatch.apply(api, _global);
}
Expand Down
5 changes: 4 additions & 1 deletion lib/browser/register-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {attachOriginToPatched, isBrowser, isMix, ObjectGetOwnPropertyDescriptor,

import {_redefineProperty} from './define-property';

export function registerElementPatch(_global: any) {
export function registerElementPatch(_global: any, api: _ZonePrivate) {
if ((!isBrowser && !isMix) || !('registerElement' in (<any>_global).document)) {
return;
}
Expand All @@ -20,6 +20,9 @@ export function registerElementPatch(_global: any) {
['createdCallback', 'attachedCallback', 'detachedCallback', 'attributeChangedCallback'];

(<any>document).registerElement = function(name: any, opts: any) {
if (api.getCurrentScope() === 'outside') {
return _registerElement.call(document, name, opts);
}
if (opts && opts.prototype) {
callbacks.forEach(function(callback) {
const source = 'Document.registerElement::' + callback;
Expand Down
4 changes: 2 additions & 2 deletions lib/browser/shadydom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ Zone.__load_patch('shadydom', (global: any, Zone: ZoneType, api: _ZonePrivate) =
if (windowPrototype && windowPrototype.hasOwnProperty('addEventListener')) {
(windowPrototype as any)[Zone.__symbol__('addEventListener')] = null;
(windowPrototype as any)[Zone.__symbol__('removeEventListener')] = null;
api.patchEventTarget(global, [windowPrototype]);
api.patchEventTarget(global, [windowPrototype], api);
}
if (Node.prototype.hasOwnProperty('addEventListener')) {
(Node.prototype as any)[Zone.__symbol__('addEventListener')] = null;
(Node.prototype as any)[Zone.__symbol__('removeEventListener')] = null;
api.patchEventTarget(global, [Node.prototype]);
api.patchEventTarget(global, [Node.prototype], api);
}
});
6 changes: 3 additions & 3 deletions lib/browser/webapis-media-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Zone.__load_patch('mediaQuery', (global: any, Zone: ZoneType, api: _ZonePrivate)
} else {
return delegate.apply(self, args);
}
});
}, api);
}

function patchRemoveListener(proto: any) {
Expand All @@ -32,7 +32,7 @@ Zone.__load_patch('mediaQuery', (global: any, Zone: ZoneType, api: _ZonePrivate)
} else {
return delegate.apply(self, args);
}
});
}, api);
}

if (global['MediaQueryList']) {
Expand Down Expand Up @@ -60,6 +60,6 @@ Zone.__load_patch('mediaQuery', (global: any, Zone: ZoneType, api: _ZonePrivate)
}
}
return mql;
});
}, api);
}
});
2 changes: 1 addition & 1 deletion lib/browser/webapis-notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ Zone.__load_patch('notification', (global: any, Zone: ZoneType, api: _ZonePrivat
if (!desc || !desc.configurable) {
return;
}
api.patchOnProperties(Notification.prototype, null);
api.patchOnProperties(Notification.prototype, null, api);
});
8 changes: 4 additions & 4 deletions lib/browser/webapis-resize-observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Zone.__load_patch('ResizeObserver', (global: any, Zone: any, api: _ZonePrivate)
};
}
return args.length > 0 ? new ResizeObserver(args[0]) : new ResizeObserver();
});
}, api);

api.patchMethod(
ResizeObserver.prototype, 'observe', (delegate: Function) => (self: any, args: any[]) => {
Expand All @@ -58,7 +58,7 @@ Zone.__load_patch('ResizeObserver', (global: any, Zone: any, api: _ZonePrivate)
targets.push(target);
target[resizeObserverSymbol] = Zone.current;
return delegate.apply(self, args);
});
}, api);

api.patchMethod(
ResizeObserver.prototype, 'unobserve', (delegate: Function) => (self: any, args: any[]) => {
Expand All @@ -77,7 +77,7 @@ Zone.__load_patch('ResizeObserver', (global: any, Zone: any, api: _ZonePrivate)
}
target[resizeObserverSymbol] = undefined;
return delegate.apply(self, args);
});
}, api);

api.patchMethod(
ResizeObserver.prototype, 'disconnect', (delegate: Function) => (self: any, args: any[]) => {
Expand All @@ -89,5 +89,5 @@ Zone.__load_patch('ResizeObserver', (global: any, Zone: any, api: _ZonePrivate)
self[resizeObserverSymbol] = undefined;
}
return delegate.apply(self, args);
});
}, api);
});
Loading