diff --git a/packages/zone-js/dist/core.ts b/packages/zone-js/dist/core.ts index 65f2d74..a77841e 100644 --- a/packages/zone-js/dist/core.ts +++ b/packages/zone-js/dist/core.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -import { patchNativeScriptEventTarget } from './utils'; +import { patchClass, patchNativeScriptEventTarget } from './utils'; function isPropertyWritable(propertyDesc: any) { if (!propertyDesc) { @@ -49,3 +49,7 @@ Zone.__load_patch('nativescript_patchMethod', (global, Zone, api) => { Zone.__load_patch('nativescript_event_target_api', (g, z, api: any) => { api.patchNativeScriptEventTarget = patchNativeScriptEventTarget; }); + +Zone.__load_patch('nativescript_patch_class_api', (g, z, api) => { + api.patchClass = (className: string) => patchClass(className, api); +}); diff --git a/packages/zone-js/dist/index.ts b/packages/zone-js/dist/index.ts index 1a6ee78..330a1a5 100644 --- a/packages/zone-js/dist/index.ts +++ b/packages/zone-js/dist/index.ts @@ -1,4 +1,5 @@ import './core'; +import './nativescript-globals'; import './events'; import './xhr'; import './connectivity'; diff --git a/packages/zone-js/dist/nativescript-globals.ts b/packages/zone-js/dist/nativescript-globals.ts new file mode 100644 index 0000000..3d8144f --- /dev/null +++ b/packages/zone-js/dist/nativescript-globals.ts @@ -0,0 +1,12 @@ +// Zone.__load_patch('nativescript_MutationObserver', (global: any, Zone: ZoneType, api: _ZonePrivate) => { +// api.patchClass('MutationObserver'); +// api.patchClass('WebKitMutationObserver'); +// }); + +// Zone.__load_patch('nativescript_IntersectionObserver', (global: any, Zone: ZoneType, api: _ZonePrivate) => { +// api.patchClass('IntersectionObserver'); +// }); + +Zone.__load_patch('nativescript_FileReader', (global: any, Zone: ZoneType, api: _ZonePrivate) => { + api.patchClass('FileReader'); +}); diff --git a/packages/zone-js/dist/pre-zone-polyfills.ts b/packages/zone-js/dist/pre-zone-polyfills.ts index cf2a6e3..bced60b 100644 --- a/packages/zone-js/dist/pre-zone-polyfills.ts +++ b/packages/zone-js/dist/pre-zone-polyfills.ts @@ -1,3 +1,5 @@ -global['__Zone_disable_legacy'] = true; -global['__Zone_disable_EventTarget'] = true; -global['__Zone_disable_XHR'] = true; +export const disabledPatches = ['legacy', 'EventTarget', 'XHR', 'MutationObserver', 'IntersectionObserver', 'FileReader']; + +for (const patch of disabledPatches) { + global[`__Zone_disable_${patch}`] = true; +} diff --git a/packages/zone-js/dist/utils.ts b/packages/zone-js/dist/utils.ts index c5cef9c..f3b821a 100644 --- a/packages/zone-js/dist/utils.ts +++ b/packages/zone-js/dist/utils.ts @@ -331,3 +331,93 @@ export function patchNativeScriptEventTarget(global: any, api: _ZonePrivate, api return results; } + +const _global = global; + +const zoneSymbol = Zone.__symbol__; + +const originalInstanceKey = zoneSymbol('originalInstance'); + +function getAllPropertyNames(obj: unknown) { + const props = new Set(); + + do { + Object.getOwnPropertyNames(obj).forEach((prop) => { + props.add(prop); + }); + } while ((obj = Object.getPrototypeOf(obj)) && obj !== Object.prototype); + + return Array.from(props); +} + +// wrap some native API on `window` +export function patchClass(className: string, api: _ZonePrivate) { + const OriginalClass = _global[className]; + if (!OriginalClass) return; + // keep original class in global + _global[zoneSymbol(className)] = OriginalClass; + + _global[className] = function () { + const a = api.bindArguments(arguments, className); + switch (a.length) { + case 0: + this[originalInstanceKey] = new OriginalClass(); + break; + case 1: + this[originalInstanceKey] = new OriginalClass(a[0]); + break; + case 2: + this[originalInstanceKey] = new OriginalClass(a[0], a[1]); + break; + case 3: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2]); + break; + case 4: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2], a[3]); + break; + default: + throw new Error('Arg list too long.'); + } + }; + + // attach original delegate to patched function + api.attachOriginToPatched(_global[className], OriginalClass); + + const instance = new OriginalClass(function () {}); + + let prop; + for (prop of Object.getOwnPropertyNames(instance)) { + // https://bugs.webkit.org/show_bug.cgi?id=44721 + if (className === 'XMLHttpRequest' && prop === 'responseBlob') continue; + (function (prop) { + if (typeof instance[prop] === 'function') { + _global[className].prototype[prop] = function () { + return this[originalInstanceKey][prop].apply(this[originalInstanceKey], arguments); + }; + } else { + api.ObjectDefineProperty(_global[className].prototype, prop, { + set: function (fn) { + if (typeof fn === 'function') { + this[originalInstanceKey][prop] = api.wrapWithCurrentZone(fn, className + '.' + prop); + // keep callback in wrapped function so we can + // use it in Function.prototype.toString to return + // the native one. + api.attachOriginToPatched(this[originalInstanceKey][prop], fn); + } else { + this[originalInstanceKey][prop] = fn; + } + }, + get: function () { + return this[originalInstanceKey][prop]; + }, + }); + } + })(prop); + } + + for (prop in Object.getOwnPropertyNames(OriginalClass)) { + if (prop !== 'prototype' && OriginalClass.hasOwnProperty(prop)) { + _global[className][prop] = OriginalClass[prop]; + } + } +}