
committed by
Kara Erickson

parent
7b3bcc23af
commit
5eb7426216
52
packages/zone.js/lib/browser/api-util.ts
Normal file
52
packages/zone.js/lib/browser/api-util.ts
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {globalSources, patchEventPrototype, patchEventTarget, zoneSymbolEventNames} from '../common/events';
|
||||
import {ADD_EVENT_LISTENER_STR, ArraySlice, FALSE_STR, ObjectCreate, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, REMOVE_EVENT_LISTENER_STR, TRUE_STR, ZONE_SYMBOL_PREFIX, attachOriginToPatched, bindArguments, isBrowser, isIEOrEdge, isMix, isNode, patchClass, patchMacroTask, patchMethod, patchOnProperties, wrapWithCurrentZone} from '../common/utils';
|
||||
|
||||
import {patchCallbacks} from './browser-util';
|
||||
import {_redefineProperty} from './define-property';
|
||||
import {eventNames, filterProperties} from './property-descriptor';
|
||||
|
||||
Zone.__load_patch('util', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
api.patchOnProperties = patchOnProperties;
|
||||
api.patchMethod = patchMethod;
|
||||
api.bindArguments = bindArguments;
|
||||
api.patchMacroTask = patchMacroTask;
|
||||
// In earlier version of zone.js (<0.9.0), we use env name `__zone_symbol__BLACK_LISTED_EVENTS` to
|
||||
// define which events will not be patched by `Zone.js`.
|
||||
// In newer version (>=0.9.0), we change the env name to `__zone_symbol__UNPATCHED_EVENTS` to keep
|
||||
// the name consistent with angular repo.
|
||||
// The `__zone_symbol__BLACK_LISTED_EVENTS` is deprecated, but it is still be supported for
|
||||
// backwards compatibility.
|
||||
const SYMBOL_BLACK_LISTED_EVENTS = Zone.__symbol__('BLACK_LISTED_EVENTS');
|
||||
const SYMBOL_UNPATCHED_EVENTS = Zone.__symbol__('UNPATCHED_EVENTS');
|
||||
if (global[SYMBOL_UNPATCHED_EVENTS]) {
|
||||
global[SYMBOL_BLACK_LISTED_EVENTS] = global[SYMBOL_UNPATCHED_EVENTS];
|
||||
}
|
||||
if (global[SYMBOL_BLACK_LISTED_EVENTS]) {
|
||||
(Zone as any)[SYMBOL_BLACK_LISTED_EVENTS] = (Zone as any)[SYMBOL_UNPATCHED_EVENTS] =
|
||||
global[SYMBOL_BLACK_LISTED_EVENTS];
|
||||
}
|
||||
api.patchEventPrototype = patchEventPrototype;
|
||||
api.patchEventTarget = patchEventTarget;
|
||||
api.isIEOrEdge = isIEOrEdge;
|
||||
api.ObjectDefineProperty = ObjectDefineProperty;
|
||||
api.ObjectGetOwnPropertyDescriptor = ObjectGetOwnPropertyDescriptor;
|
||||
api.ObjectCreate = ObjectCreate;
|
||||
api.ArraySlice = ArraySlice;
|
||||
api.patchClass = patchClass;
|
||||
api.wrapWithCurrentZone = wrapWithCurrentZone;
|
||||
api.filterProperties = filterProperties;
|
||||
api.attachOriginToPatched = attachOriginToPatched;
|
||||
api._redefineProperty = _redefineProperty;
|
||||
api.patchCallbacks = patchCallbacks;
|
||||
api.getGlobalObjects = () =>
|
||||
({globalSources, zoneSymbolEventNames, eventNames, isBrowser, isMix, isNode, TRUE_STR,
|
||||
FALSE_STR, ZONE_SYMBOL_PREFIX, ADD_EVENT_LISTENER_STR, REMOVE_EVENT_LISTENER_STR});
|
||||
});
|
31
packages/zone.js/lib/browser/browser-legacy.ts
Normal file
31
packages/zone.js/lib/browser/browser-legacy.ts
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
/**
|
||||
* @fileoverview
|
||||
* @suppress {missingRequire}
|
||||
*/
|
||||
|
||||
import {eventTargetLegacyPatch} from './event-target-legacy';
|
||||
import {propertyDescriptorLegacyPatch} from './property-descriptor-legacy';
|
||||
import {registerElementPatch} from './register-element';
|
||||
|
||||
(function(_global: any) {
|
||||
_global[Zone.__symbol__('legacyPatch')] = function() {
|
||||
const Zone = _global['Zone'];
|
||||
Zone.__load_patch('registerElement', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
registerElementPatch(global, api);
|
||||
});
|
||||
|
||||
Zone.__load_patch('EventTargetLegacy', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
eventTargetLegacyPatch(global, api);
|
||||
propertyDescriptorLegacyPatch(api, global);
|
||||
});
|
||||
};
|
||||
})(typeof window !== 'undefined' ?
|
||||
window :
|
||||
typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {});
|
38
packages/zone.js/lib/browser/browser-util.ts
Normal file
38
packages/zone.js/lib/browser/browser-util.ts
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
export function patchCallbacks(
|
||||
api: _ZonePrivate, target: any, targetName: string, method: string, callbacks: string[]) {
|
||||
const symbol = Zone.__symbol__(method);
|
||||
if (target[symbol]) {
|
||||
return;
|
||||
}
|
||||
const nativeDelegate = target[symbol] = target[method];
|
||||
target[method] = function(name: any, opts: any, options?: any) {
|
||||
if (opts && opts.prototype) {
|
||||
callbacks.forEach(function(callback) {
|
||||
const source = `${targetName}.${method}::` + callback;
|
||||
const prototype = opts.prototype;
|
||||
if (prototype.hasOwnProperty(callback)) {
|
||||
const descriptor = api.ObjectGetOwnPropertyDescriptor(prototype, callback);
|
||||
if (descriptor && descriptor.value) {
|
||||
descriptor.value = api.wrapWithCurrentZone(descriptor.value, source);
|
||||
api._redefineProperty(opts.prototype, callback, descriptor);
|
||||
} else if (prototype[callback]) {
|
||||
prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source);
|
||||
}
|
||||
} else if (prototype[callback]) {
|
||||
prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return nativeDelegate.call(target, name, opts, options);
|
||||
};
|
||||
|
||||
api.attachOriginToPatched(target[method], nativeDelegate);
|
||||
}
|
280
packages/zone.js/lib/browser/browser.ts
Normal file
280
packages/zone.js/lib/browser/browser.ts
Normal file
@ -0,0 +1,280 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
/**
|
||||
* @fileoverview
|
||||
* @suppress {missingRequire}
|
||||
*/
|
||||
|
||||
import {findEventTasks} from '../common/events';
|
||||
import {patchTimer} from '../common/timers';
|
||||
import {ZONE_SYMBOL_ADD_EVENT_LISTENER, ZONE_SYMBOL_REMOVE_EVENT_LISTENER, patchClass, patchMethod, patchPrototype, scheduleMacroTaskWithCurrentZone, zoneSymbol} from '../common/utils';
|
||||
|
||||
import {patchCustomElements} from './custom-elements';
|
||||
import {propertyPatch} from './define-property';
|
||||
import {eventTargetPatch, patchEvent} from './event-target';
|
||||
import {propertyDescriptorPatch} from './property-descriptor';
|
||||
|
||||
Zone.__load_patch('legacy', (global: any) => {
|
||||
const legacyPatch = global[Zone.__symbol__('legacyPatch')];
|
||||
if (legacyPatch) {
|
||||
legacyPatch();
|
||||
}
|
||||
});
|
||||
|
||||
Zone.__load_patch('timers', (global: any) => {
|
||||
const set = 'set';
|
||||
const clear = 'clear';
|
||||
patchTimer(global, set, clear, 'Timeout');
|
||||
patchTimer(global, set, clear, 'Interval');
|
||||
patchTimer(global, set, clear, 'Immediate');
|
||||
});
|
||||
|
||||
Zone.__load_patch('requestAnimationFrame', (global: any) => {
|
||||
patchTimer(global, 'request', 'cancel', 'AnimationFrame');
|
||||
patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame');
|
||||
patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame');
|
||||
});
|
||||
|
||||
Zone.__load_patch('blocking', (global: any, Zone: ZoneType) => {
|
||||
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);
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Zone.__load_patch('EventTarget', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
patchEvent(global, api);
|
||||
eventTargetPatch(global, api);
|
||||
// patch XMLHttpRequestEventTarget's addEventListener/removeEventListener
|
||||
const XMLHttpRequestEventTarget = (global as any)['XMLHttpRequestEventTarget'];
|
||||
if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) {
|
||||
api.patchEventTarget(global, [XMLHttpRequestEventTarget.prototype]);
|
||||
}
|
||||
patchClass('MutationObserver');
|
||||
patchClass('WebKitMutationObserver');
|
||||
patchClass('IntersectionObserver');
|
||||
patchClass('FileReader');
|
||||
});
|
||||
|
||||
Zone.__load_patch('on_property', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
propertyDescriptorPatch(api, global);
|
||||
propertyPatch();
|
||||
});
|
||||
|
||||
Zone.__load_patch('customElements', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
patchCustomElements(global, api);
|
||||
});
|
||||
|
||||
Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
|
||||
// Treat XMLHttpRequest as a macrotask.
|
||||
patchXHR(global);
|
||||
|
||||
const XHR_TASK = zoneSymbol('xhrTask');
|
||||
const XHR_SYNC = zoneSymbol('xhrSync');
|
||||
const XHR_LISTENER = zoneSymbol('xhrListener');
|
||||
const XHR_SCHEDULED = zoneSymbol('xhrScheduled');
|
||||
const XHR_URL = zoneSymbol('xhrURL');
|
||||
const XHR_ERROR_BEFORE_SCHEDULED = zoneSymbol('xhrErrorBeforeScheduled');
|
||||
|
||||
interface XHROptions extends TaskData {
|
||||
target: any;
|
||||
url: string;
|
||||
args: any[];
|
||||
aborted: boolean;
|
||||
}
|
||||
|
||||
function patchXHR(window: any) {
|
||||
const XMLHttpRequest = window['XMLHttpRequest'];
|
||||
if (!XMLHttpRequest) {
|
||||
// XMLHttpRequest is not available in service worker
|
||||
return;
|
||||
}
|
||||
const XMLHttpRequestPrototype: any = XMLHttpRequest.prototype;
|
||||
|
||||
function findPendingTask(target: any) { return target[XHR_TASK]; }
|
||||
|
||||
let oriAddListener = XMLHttpRequestPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER];
|
||||
let oriRemoveListener = XMLHttpRequestPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER];
|
||||
if (!oriAddListener) {
|
||||
const XMLHttpRequestEventTarget = window['XMLHttpRequestEventTarget'];
|
||||
if (XMLHttpRequestEventTarget) {
|
||||
const XMLHttpRequestEventTargetPrototype = XMLHttpRequestEventTarget.prototype;
|
||||
oriAddListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER];
|
||||
oriRemoveListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER];
|
||||
}
|
||||
}
|
||||
|
||||
const READY_STATE_CHANGE = 'readystatechange';
|
||||
const SCHEDULED = 'scheduled';
|
||||
|
||||
function scheduleTask(task: Task) {
|
||||
const data = <XHROptions>task.data;
|
||||
const target = data.target;
|
||||
target[XHR_SCHEDULED] = false;
|
||||
target[XHR_ERROR_BEFORE_SCHEDULED] = false;
|
||||
// remove existing event listener
|
||||
const listener = target[XHR_LISTENER];
|
||||
if (!oriAddListener) {
|
||||
oriAddListener = target[ZONE_SYMBOL_ADD_EVENT_LISTENER];
|
||||
oriRemoveListener = target[ZONE_SYMBOL_REMOVE_EVENT_LISTENER];
|
||||
}
|
||||
|
||||
if (listener) {
|
||||
oriRemoveListener.call(target, READY_STATE_CHANGE, listener);
|
||||
}
|
||||
const newListener = target[XHR_LISTENER] = () => {
|
||||
if (target.readyState === target.DONE) {
|
||||
// sometimes on some browsers XMLHttpRequest will fire onreadystatechange with
|
||||
// readyState=4 multiple times, so we need to check task state here
|
||||
if (!data.aborted && target[XHR_SCHEDULED] && task.state === SCHEDULED) {
|
||||
// check whether the xhr has registered onload listener
|
||||
// if that is the case, the task should invoke after all
|
||||
// onload listeners finish.
|
||||
const loadTasks = target[Zone.__symbol__('loadfalse')];
|
||||
if (loadTasks && loadTasks.length > 0) {
|
||||
const oriInvoke = task.invoke;
|
||||
task.invoke = function() {
|
||||
// need to load the tasks again, because in other
|
||||
// load listener, they may remove themselves
|
||||
const loadTasks = target[Zone.__symbol__('loadfalse')];
|
||||
for (let i = 0; i < loadTasks.length; i++) {
|
||||
if (loadTasks[i] === task) {
|
||||
loadTasks.splice(i, 1);
|
||||
}
|
||||
}
|
||||
if (!data.aborted && task.state === SCHEDULED) {
|
||||
oriInvoke.call(task);
|
||||
}
|
||||
};
|
||||
loadTasks.push(task);
|
||||
} else {
|
||||
task.invoke();
|
||||
}
|
||||
} else if (!data.aborted && target[XHR_SCHEDULED] === false) {
|
||||
// error occurs when xhr.send()
|
||||
target[XHR_ERROR_BEFORE_SCHEDULED] = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
oriAddListener.call(target, READY_STATE_CHANGE, newListener);
|
||||
|
||||
const storedTask: Task = target[XHR_TASK];
|
||||
if (!storedTask) {
|
||||
target[XHR_TASK] = task;
|
||||
}
|
||||
sendNative !.apply(target, data.args);
|
||||
target[XHR_SCHEDULED] = true;
|
||||
return task;
|
||||
}
|
||||
|
||||
function placeholderCallback() {}
|
||||
|
||||
function clearTask(task: Task) {
|
||||
const data = <XHROptions>task.data;
|
||||
// Note - ideally, we would call data.target.removeEventListener here, but it's too late
|
||||
// to prevent it from firing. So instead, we store info for the event listener.
|
||||
data.aborted = true;
|
||||
return abortNative !.apply(data.target, data.args);
|
||||
}
|
||||
|
||||
const openNative =
|
||||
patchMethod(XMLHttpRequestPrototype, 'open', () => function(self: any, args: any[]) {
|
||||
self[XHR_SYNC] = args[2] == false;
|
||||
self[XHR_URL] = args[1];
|
||||
return openNative !.apply(self, args);
|
||||
});
|
||||
|
||||
const XMLHTTPREQUEST_SOURCE = 'XMLHttpRequest.send';
|
||||
const fetchTaskAborting = zoneSymbol('fetchTaskAborting');
|
||||
const fetchTaskScheduling = zoneSymbol('fetchTaskScheduling');
|
||||
const sendNative: Function|null =
|
||||
patchMethod(XMLHttpRequestPrototype, 'send', () => function(self: any, args: any[]) {
|
||||
if ((Zone.current as any)[fetchTaskScheduling] === true) {
|
||||
// a fetch is scheduling, so we are using xhr to polyfill fetch
|
||||
// and because we already schedule macroTask for fetch, we should
|
||||
// not schedule a macroTask for xhr again
|
||||
return sendNative !.apply(self, args);
|
||||
}
|
||||
if (self[XHR_SYNC]) {
|
||||
// if the XHR is sync there is no task to schedule, just execute the code.
|
||||
return sendNative !.apply(self, args);
|
||||
} else {
|
||||
const options: XHROptions =
|
||||
{target: self, url: self[XHR_URL], isPeriodic: false, args: args, aborted: false};
|
||||
const task = scheduleMacroTaskWithCurrentZone(
|
||||
XMLHTTPREQUEST_SOURCE, placeholderCallback, options, scheduleTask, clearTask);
|
||||
if (self && self[XHR_ERROR_BEFORE_SCHEDULED] === true && !options.aborted &&
|
||||
task.state === SCHEDULED) {
|
||||
// xhr request throw error when send
|
||||
// we should invoke task instead of leaving a scheduled
|
||||
// pending macroTask
|
||||
task.invoke();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const abortNative =
|
||||
patchMethod(XMLHttpRequestPrototype, 'abort', () => function(self: any, args: any[]) {
|
||||
const task: Task = findPendingTask(self);
|
||||
if (task && typeof task.type == 'string') {
|
||||
// If the XHR has already completed, do nothing.
|
||||
// If the XHR has already been aborted, do nothing.
|
||||
// Fix #569, call abort multiple times before done will cause
|
||||
// macroTask task count be negative number
|
||||
if (task.cancelFn == null || (task.data && (<XHROptions>task.data).aborted)) {
|
||||
return;
|
||||
}
|
||||
task.zone.cancelTask(task);
|
||||
} else if ((Zone.current as any)[fetchTaskAborting] === true) {
|
||||
// the abort is called from fetch polyfill, we need to call native abort of XHR.
|
||||
return abortNative !.apply(self, args);
|
||||
}
|
||||
// Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no
|
||||
// task
|
||||
// to cancel. Do nothing.
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Zone.__load_patch('geolocation', (global: any) => {
|
||||
/// GEO_LOCATION
|
||||
if (global['navigator'] && global['navigator'].geolocation) {
|
||||
patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']);
|
||||
}
|
||||
});
|
||||
|
||||
Zone.__load_patch('PromiseRejectionEvent', (global: any, Zone: ZoneType) => {
|
||||
// handle unhandled promise rejection
|
||||
function findPromiseRejectionHandler(evtName: string) {
|
||||
return function(e: any) {
|
||||
const eventTasks = findEventTasks(global, evtName);
|
||||
eventTasks.forEach(eventTask => {
|
||||
// windows has added unhandledrejection event listener
|
||||
// trigger the event listener
|
||||
const PromiseRejectionEvent = global['PromiseRejectionEvent'];
|
||||
if (PromiseRejectionEvent) {
|
||||
const evt = new PromiseRejectionEvent(evtName, {promise: e.promise, reason: e.rejection});
|
||||
eventTask.invoke(evt);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
if (global['PromiseRejectionEvent']) {
|
||||
(Zone as any)[zoneSymbol('unhandledPromiseRejectionHandler')] =
|
||||
findPromiseRejectionHandler('unhandledrejection');
|
||||
|
||||
(Zone as any)[zoneSymbol('rejectionHandledHandler')] =
|
||||
findPromiseRejectionHandler('rejectionhandled');
|
||||
}
|
||||
});
|
16
packages/zone.js/lib/browser/canvas.ts
Normal file
16
packages/zone.js/lib/browser/canvas.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
Zone.__load_patch('canvas', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
const HTMLCanvasElement = global['HTMLCanvasElement'];
|
||||
if (typeof HTMLCanvasElement !== 'undefined' && HTMLCanvasElement.prototype &&
|
||||
HTMLCanvasElement.prototype.toBlob) {
|
||||
api.patchMacroTask(HTMLCanvasElement.prototype, 'toBlob', (self: any, args: any[]) => {
|
||||
return {name: 'HTMLCanvasElement.toBlob', target: self, cbIdx: 0, args: args};
|
||||
});
|
||||
}
|
||||
});
|
19
packages/zone.js/lib/browser/custom-elements.ts
Normal file
19
packages/zone.js/lib/browser/custom-elements.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export function patchCustomElements(_global: any, api: _ZonePrivate) {
|
||||
const {isBrowser, isMix} = api.getGlobalObjects() !;
|
||||
if ((!isBrowser && !isMix) || !_global['customElements'] || !('customElements' in _global)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const callbacks =
|
||||
['connectedCallback', 'disconnectedCallback', 'adoptedCallback', 'attributeChangedCallback'];
|
||||
|
||||
api.patchCallbacks(api, _global.customElements, 'customElements', 'define', callbacks);
|
||||
}
|
111
packages/zone.js/lib/browser/define-property.ts
Normal file
111
packages/zone.js/lib/browser/define-property.ts
Normal file
@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is necessary for Chrome and Chrome mobile, to enable
|
||||
* things like redefining `createdCallback` on an element.
|
||||
*/
|
||||
|
||||
const zoneSymbol = Zone.__symbol__;
|
||||
const _defineProperty = (Object as any)[zoneSymbol('defineProperty')] = Object.defineProperty;
|
||||
const _getOwnPropertyDescriptor = (Object as any)[zoneSymbol('getOwnPropertyDescriptor')] =
|
||||
Object.getOwnPropertyDescriptor;
|
||||
const _create = Object.create;
|
||||
const unconfigurablesKey = zoneSymbol('unconfigurables');
|
||||
|
||||
export function propertyPatch() {
|
||||
Object.defineProperty = function(obj: any, prop: string, desc: any) {
|
||||
if (isUnconfigurable(obj, prop)) {
|
||||
throw new TypeError('Cannot assign to read only property \'' + prop + '\' of ' + obj);
|
||||
}
|
||||
const originalConfigurableFlag = desc.configurable;
|
||||
if (prop !== 'prototype') {
|
||||
desc = rewriteDescriptor(obj, prop, desc);
|
||||
}
|
||||
return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag);
|
||||
};
|
||||
|
||||
Object.defineProperties = function(obj, props) {
|
||||
Object.keys(props).forEach(function(prop) { Object.defineProperty(obj, prop, props[prop]); });
|
||||
return obj;
|
||||
};
|
||||
|
||||
Object.create = <any>function(obj: any, proto: any) {
|
||||
if (typeof proto === 'object' && !Object.isFrozen(proto)) {
|
||||
Object.keys(proto).forEach(function(prop) {
|
||||
proto[prop] = rewriteDescriptor(obj, prop, proto[prop]);
|
||||
});
|
||||
}
|
||||
return _create(obj, proto);
|
||||
};
|
||||
|
||||
Object.getOwnPropertyDescriptor = function(obj, prop) {
|
||||
const desc = _getOwnPropertyDescriptor(obj, prop);
|
||||
if (desc && isUnconfigurable(obj, prop)) {
|
||||
desc.configurable = false;
|
||||
}
|
||||
return desc;
|
||||
};
|
||||
}
|
||||
|
||||
export function _redefineProperty(obj: any, prop: string, desc: any) {
|
||||
const originalConfigurableFlag = desc.configurable;
|
||||
desc = rewriteDescriptor(obj, prop, desc);
|
||||
return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag);
|
||||
}
|
||||
|
||||
function isUnconfigurable(obj: any, prop: any) {
|
||||
return obj && obj[unconfigurablesKey] && obj[unconfigurablesKey][prop];
|
||||
}
|
||||
|
||||
function rewriteDescriptor(obj: any, prop: string, desc: any) {
|
||||
// issue-927, if the desc is frozen, don't try to change the desc
|
||||
if (!Object.isFrozen(desc)) {
|
||||
desc.configurable = true;
|
||||
}
|
||||
if (!desc.configurable) {
|
||||
// issue-927, if the obj is frozen, don't try to set the desc to obj
|
||||
if (!obj[unconfigurablesKey] && !Object.isFrozen(obj)) {
|
||||
_defineProperty(obj, unconfigurablesKey, {writable: true, value: {}});
|
||||
}
|
||||
if (obj[unconfigurablesKey]) {
|
||||
obj[unconfigurablesKey][prop] = true;
|
||||
}
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
function _tryDefineProperty(obj: any, prop: string, desc: any, originalConfigurableFlag: any) {
|
||||
try {
|
||||
return _defineProperty(obj, prop, desc);
|
||||
} catch (error) {
|
||||
if (desc.configurable) {
|
||||
// In case of errors, when the configurable flag was likely set by rewriteDescriptor(), let's
|
||||
// retry with the original flag value
|
||||
if (typeof originalConfigurableFlag == 'undefined') {
|
||||
delete desc.configurable;
|
||||
} else {
|
||||
desc.configurable = originalConfigurableFlag;
|
||||
}
|
||||
try {
|
||||
return _defineProperty(obj, prop, desc);
|
||||
} catch (error) {
|
||||
let descJson: string|null = null;
|
||||
try {
|
||||
descJson = JSON.stringify(desc);
|
||||
} catch (error) {
|
||||
descJson = desc.toString();
|
||||
}
|
||||
console.log(`Attempting to configure '${prop}' with descriptor '${descJson}' on object '${
|
||||
obj}' and got error, giving up: ${error}`);
|
||||
}
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
110
packages/zone.js/lib/browser/event-target-legacy.ts
Normal file
110
packages/zone.js/lib/browser/event-target-legacy.ts
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export function eventTargetLegacyPatch(_global: any, api: _ZonePrivate) {
|
||||
const {eventNames, globalSources, zoneSymbolEventNames, TRUE_STR, FALSE_STR, ZONE_SYMBOL_PREFIX} =
|
||||
api.getGlobalObjects() !;
|
||||
const WTF_ISSUE_555 =
|
||||
'Anchor,Area,Audio,BR,Base,BaseFont,Body,Button,Canvas,Content,DList,Directory,Div,Embed,FieldSet,Font,Form,Frame,FrameSet,HR,Head,Heading,Html,IFrame,Image,Input,Keygen,LI,Label,Legend,Link,Map,Marquee,Media,Menu,Meta,Meter,Mod,OList,Object,OptGroup,Option,Output,Paragraph,Pre,Progress,Quote,Script,Select,Source,Span,Style,TableCaption,TableCell,TableCol,Table,TableRow,TableSection,TextArea,Title,Track,UList,Unknown,Video';
|
||||
const NO_EVENT_TARGET =
|
||||
'ApplicationCache,EventSource,FileReader,InputMethodContext,MediaController,MessagePort,Node,Performance,SVGElementInstance,SharedWorker,TextTrack,TextTrackCue,TextTrackList,WebKitNamedFlow,Window,Worker,WorkerGlobalScope,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload,IDBRequest,IDBOpenDBRequest,IDBDatabase,IDBTransaction,IDBCursor,DBIndex,WebSocket'
|
||||
.split(',');
|
||||
const EVENT_TARGET = 'EventTarget';
|
||||
|
||||
let apis: any[] = [];
|
||||
const isWtf = _global['wtf'];
|
||||
const WTF_ISSUE_555_ARRAY = WTF_ISSUE_555.split(',');
|
||||
|
||||
if (isWtf) {
|
||||
// Workaround for: https://github.com/google/tracing-framework/issues/555
|
||||
apis = WTF_ISSUE_555_ARRAY.map((v) => 'HTML' + v + 'Element').concat(NO_EVENT_TARGET);
|
||||
} else if (_global[EVENT_TARGET]) {
|
||||
apis.push(EVENT_TARGET);
|
||||
} else {
|
||||
// Note: EventTarget is not available in all browsers,
|
||||
// if it's not available, we instead patch the APIs in the IDL that inherit from EventTarget
|
||||
apis = NO_EVENT_TARGET;
|
||||
}
|
||||
|
||||
const isDisableIECheck = _global['__Zone_disable_IE_check'] || false;
|
||||
const isEnableCrossContextCheck = _global['__Zone_enable_cross_context_check'] || false;
|
||||
const ieOrEdge = api.isIEOrEdge();
|
||||
|
||||
const ADD_EVENT_LISTENER_SOURCE = '.addEventListener:';
|
||||
const FUNCTION_WRAPPER = '[object FunctionWrapper]';
|
||||
const BROWSER_TOOLS = 'function __BROWSERTOOLS_CONSOLE_SAFEFUNC() { [native code] }';
|
||||
|
||||
// predefine all __zone_symbol__ + eventName + true/false string
|
||||
for (let i = 0; i < eventNames.length; i++) {
|
||||
const eventName = eventNames[i];
|
||||
const falseEventName = eventName + FALSE_STR;
|
||||
const trueEventName = eventName + TRUE_STR;
|
||||
const symbol = ZONE_SYMBOL_PREFIX + falseEventName;
|
||||
const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName;
|
||||
zoneSymbolEventNames[eventName] = {};
|
||||
zoneSymbolEventNames[eventName][FALSE_STR] = symbol;
|
||||
zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture;
|
||||
}
|
||||
|
||||
// predefine all task.source string
|
||||
for (let i = 0; i < WTF_ISSUE_555.length; i++) {
|
||||
const target: any = WTF_ISSUE_555_ARRAY[i];
|
||||
const targets: any = globalSources[target] = {};
|
||||
for (let j = 0; j < eventNames.length; j++) {
|
||||
const eventName = eventNames[j];
|
||||
targets[eventName] = target + ADD_EVENT_LISTENER_SOURCE + eventName;
|
||||
}
|
||||
}
|
||||
|
||||
const checkIEAndCrossContext = function(
|
||||
nativeDelegate: any, delegate: any, target: any, args: any) {
|
||||
if (!isDisableIECheck && ieOrEdge) {
|
||||
if (isEnableCrossContextCheck) {
|
||||
try {
|
||||
const testString = delegate.toString();
|
||||
if ((testString === FUNCTION_WRAPPER || testString == BROWSER_TOOLS)) {
|
||||
nativeDelegate.apply(target, args);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
nativeDelegate.apply(target, args);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const testString = delegate.toString();
|
||||
if ((testString === FUNCTION_WRAPPER || testString == BROWSER_TOOLS)) {
|
||||
nativeDelegate.apply(target, args);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (isEnableCrossContextCheck) {
|
||||
try {
|
||||
delegate.toString();
|
||||
} catch (error) {
|
||||
nativeDelegate.apply(target, args);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const apiTypes: any[] = [];
|
||||
for (let i = 0; i < apis.length; i++) {
|
||||
const type = _global[apis[i]];
|
||||
apiTypes.push(type && type.prototype);
|
||||
}
|
||||
// vh is validateHandler to check event handler
|
||||
// is valid or not(for security check)
|
||||
api.patchEventTarget(_global, apiTypes, {vh: checkIEAndCrossContext});
|
||||
(Zone as any)[api.symbol('patchEventTarget')] = !!_global[EVENT_TARGET];
|
||||
return true;
|
||||
}
|
||||
|
||||
export function patchEvent(global: any, api: _ZonePrivate) {
|
||||
api.patchEventPrototype(global, api);
|
||||
}
|
39
packages/zone.js/lib/browser/event-target.ts
Normal file
39
packages/zone.js/lib/browser/event-target.ts
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export function eventTargetPatch(_global: any, api: _ZonePrivate) {
|
||||
if ((Zone as any)[api.symbol('patchEventTarget')]) {
|
||||
// EventTarget is already patched.
|
||||
return;
|
||||
}
|
||||
const {eventNames, zoneSymbolEventNames, TRUE_STR, FALSE_STR, ZONE_SYMBOL_PREFIX} =
|
||||
api.getGlobalObjects() !;
|
||||
// predefine all __zone_symbol__ + eventName + true/false string
|
||||
for (let i = 0; i < eventNames.length; i++) {
|
||||
const eventName = eventNames[i];
|
||||
const falseEventName = eventName + FALSE_STR;
|
||||
const trueEventName = eventName + TRUE_STR;
|
||||
const symbol = ZONE_SYMBOL_PREFIX + falseEventName;
|
||||
const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName;
|
||||
zoneSymbolEventNames[eventName] = {};
|
||||
zoneSymbolEventNames[eventName][FALSE_STR] = symbol;
|
||||
zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture;
|
||||
}
|
||||
|
||||
const EVENT_TARGET = _global['EventTarget'];
|
||||
if (!EVENT_TARGET || !EVENT_TARGET.prototype) {
|
||||
return;
|
||||
}
|
||||
api.patchEventTarget(_global, [EVENT_TARGET && EVENT_TARGET.prototype]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function patchEvent(global: any, api: _ZonePrivate) {
|
||||
api.patchEventPrototype(global, api);
|
||||
}
|
124
packages/zone.js/lib/browser/property-descriptor-legacy.ts
Normal file
124
packages/zone.js/lib/browser/property-descriptor-legacy.ts
Normal file
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
/**
|
||||
* @fileoverview
|
||||
* @suppress {globalThis}
|
||||
*/
|
||||
|
||||
import * as webSocketPatch from './websocket';
|
||||
|
||||
export function propertyDescriptorLegacyPatch(api: _ZonePrivate, _global: any) {
|
||||
const {isNode, isMix} = api.getGlobalObjects() !;
|
||||
if (isNode && !isMix) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canPatchViaPropertyDescriptor(api, _global)) {
|
||||
const supportsWebSocket = typeof WebSocket !== 'undefined';
|
||||
// Safari, Android browsers (Jelly Bean)
|
||||
patchViaCapturingAllTheEvents(api);
|
||||
api.patchClass('XMLHttpRequest');
|
||||
if (supportsWebSocket) {
|
||||
webSocketPatch.apply(api, _global);
|
||||
}
|
||||
(Zone as any)[api.symbol('patchEvents')] = true;
|
||||
}
|
||||
}
|
||||
|
||||
function canPatchViaPropertyDescriptor(api: _ZonePrivate, _global: any) {
|
||||
const {isBrowser, isMix} = api.getGlobalObjects() !;
|
||||
if ((isBrowser || isMix) &&
|
||||
!api.ObjectGetOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') &&
|
||||
typeof Element !== 'undefined') {
|
||||
// WebKit https://bugs.webkit.org/show_bug.cgi?id=134364
|
||||
// IDL interface attributes are not configurable
|
||||
const desc = api.ObjectGetOwnPropertyDescriptor(Element.prototype, 'onclick');
|
||||
if (desc && !desc.configurable) return false;
|
||||
// try to use onclick to detect whether we can patch via propertyDescriptor
|
||||
// because XMLHttpRequest is not available in service worker
|
||||
if (desc) {
|
||||
api.ObjectDefineProperty(
|
||||
Element.prototype, 'onclick',
|
||||
{enumerable: true, configurable: true, get: function() { return true; }});
|
||||
const div = document.createElement('div');
|
||||
const result = !!div.onclick;
|
||||
api.ObjectDefineProperty(Element.prototype, 'onclick', desc);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const XMLHttpRequest = _global['XMLHttpRequest'];
|
||||
if (!XMLHttpRequest) {
|
||||
// XMLHttpRequest is not available in service worker
|
||||
return false;
|
||||
}
|
||||
const ON_READY_STATE_CHANGE = 'onreadystatechange';
|
||||
const XMLHttpRequestPrototype = XMLHttpRequest.prototype;
|
||||
|
||||
const xhrDesc =
|
||||
api.ObjectGetOwnPropertyDescriptor(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE);
|
||||
|
||||
// add enumerable and configurable here because in opera
|
||||
// by default XMLHttpRequest.prototype.onreadystatechange is undefined
|
||||
// without adding enumerable and configurable will cause onreadystatechange
|
||||
// non-configurable
|
||||
// and if XMLHttpRequest.prototype.onreadystatechange is undefined,
|
||||
// we should set a real desc instead a fake one
|
||||
if (xhrDesc) {
|
||||
api.ObjectDefineProperty(
|
||||
XMLHttpRequestPrototype, ON_READY_STATE_CHANGE,
|
||||
{enumerable: true, configurable: true, get: function() { return true; }});
|
||||
const req = new XMLHttpRequest();
|
||||
const result = !!req.onreadystatechange;
|
||||
// restore original desc
|
||||
api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, xhrDesc || {});
|
||||
return result;
|
||||
} else {
|
||||
const SYMBOL_FAKE_ONREADYSTATECHANGE = api.symbol('fake');
|
||||
api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: function() { return this[SYMBOL_FAKE_ONREADYSTATECHANGE]; },
|
||||
set: function(value) { this[SYMBOL_FAKE_ONREADYSTATECHANGE] = value; }
|
||||
});
|
||||
const req = new XMLHttpRequest();
|
||||
const detectFunc = () => {};
|
||||
req.onreadystatechange = detectFunc;
|
||||
const result = (req as any)[SYMBOL_FAKE_ONREADYSTATECHANGE] === detectFunc;
|
||||
req.onreadystatechange = null as any;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Whenever any eventListener fires, we check the eventListener target and all parents
|
||||
// for `onwhatever` properties and replace them with zone-bound functions
|
||||
// - Chrome (for now)
|
||||
function patchViaCapturingAllTheEvents(api: _ZonePrivate) {
|
||||
const {eventNames} = api.getGlobalObjects() !;
|
||||
const unboundKey = api.symbol('unbound');
|
||||
for (let i = 0; i < eventNames.length; i++) {
|
||||
const property = eventNames[i];
|
||||
const onproperty = 'on' + property;
|
||||
self.addEventListener(property, function(event) {
|
||||
let elt: any = <Node>event.target, bound, source;
|
||||
if (elt) {
|
||||
source = elt.constructor['name'] + '.' + onproperty;
|
||||
} else {
|
||||
source = 'unknown.' + onproperty;
|
||||
}
|
||||
while (elt) {
|
||||
if (elt[onproperty] && !elt[onproperty][unboundKey]) {
|
||||
bound = api.wrapWithCurrentZone(elt[onproperty], source);
|
||||
bound[unboundKey] = elt[onproperty];
|
||||
elt[onproperty] = bound;
|
||||
}
|
||||
elt = elt.parentElement;
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
334
packages/zone.js/lib/browser/property-descriptor.ts
Normal file
334
packages/zone.js/lib/browser/property-descriptor.ts
Normal file
@ -0,0 +1,334 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
/**
|
||||
* @fileoverview
|
||||
* @suppress {globalThis}
|
||||
*/
|
||||
|
||||
import {ObjectGetPrototypeOf, isBrowser, isIE, isMix, isNode, patchOnProperties} from '../common/utils';
|
||||
|
||||
const globalEventHandlersEventNames = [
|
||||
'abort',
|
||||
'animationcancel',
|
||||
'animationend',
|
||||
'animationiteration',
|
||||
'auxclick',
|
||||
'beforeinput',
|
||||
'blur',
|
||||
'cancel',
|
||||
'canplay',
|
||||
'canplaythrough',
|
||||
'change',
|
||||
'compositionstart',
|
||||
'compositionupdate',
|
||||
'compositionend',
|
||||
'cuechange',
|
||||
'click',
|
||||
'close',
|
||||
'contextmenu',
|
||||
'curechange',
|
||||
'dblclick',
|
||||
'drag',
|
||||
'dragend',
|
||||
'dragenter',
|
||||
'dragexit',
|
||||
'dragleave',
|
||||
'dragover',
|
||||
'drop',
|
||||
'durationchange',
|
||||
'emptied',
|
||||
'ended',
|
||||
'error',
|
||||
'focus',
|
||||
'focusin',
|
||||
'focusout',
|
||||
'gotpointercapture',
|
||||
'input',
|
||||
'invalid',
|
||||
'keydown',
|
||||
'keypress',
|
||||
'keyup',
|
||||
'load',
|
||||
'loadstart',
|
||||
'loadeddata',
|
||||
'loadedmetadata',
|
||||
'lostpointercapture',
|
||||
'mousedown',
|
||||
'mouseenter',
|
||||
'mouseleave',
|
||||
'mousemove',
|
||||
'mouseout',
|
||||
'mouseover',
|
||||
'mouseup',
|
||||
'mousewheel',
|
||||
'orientationchange',
|
||||
'pause',
|
||||
'play',
|
||||
'playing',
|
||||
'pointercancel',
|
||||
'pointerdown',
|
||||
'pointerenter',
|
||||
'pointerleave',
|
||||
'pointerlockchange',
|
||||
'mozpointerlockchange',
|
||||
'webkitpointerlockerchange',
|
||||
'pointerlockerror',
|
||||
'mozpointerlockerror',
|
||||
'webkitpointerlockerror',
|
||||
'pointermove',
|
||||
'pointout',
|
||||
'pointerover',
|
||||
'pointerup',
|
||||
'progress',
|
||||
'ratechange',
|
||||
'reset',
|
||||
'resize',
|
||||
'scroll',
|
||||
'seeked',
|
||||
'seeking',
|
||||
'select',
|
||||
'selectionchange',
|
||||
'selectstart',
|
||||
'show',
|
||||
'sort',
|
||||
'stalled',
|
||||
'submit',
|
||||
'suspend',
|
||||
'timeupdate',
|
||||
'volumechange',
|
||||
'touchcancel',
|
||||
'touchmove',
|
||||
'touchstart',
|
||||
'touchend',
|
||||
'transitioncancel',
|
||||
'transitionend',
|
||||
'waiting',
|
||||
'wheel'
|
||||
];
|
||||
const documentEventNames = [
|
||||
'afterscriptexecute', 'beforescriptexecute', 'DOMContentLoaded', 'freeze', 'fullscreenchange',
|
||||
'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange', 'fullscreenerror',
|
||||
'mozfullscreenerror', 'webkitfullscreenerror', 'msfullscreenerror', 'readystatechange',
|
||||
'visibilitychange', 'resume'
|
||||
];
|
||||
const windowEventNames = [
|
||||
'absolutedeviceorientation',
|
||||
'afterinput',
|
||||
'afterprint',
|
||||
'appinstalled',
|
||||
'beforeinstallprompt',
|
||||
'beforeprint',
|
||||
'beforeunload',
|
||||
'devicelight',
|
||||
'devicemotion',
|
||||
'deviceorientation',
|
||||
'deviceorientationabsolute',
|
||||
'deviceproximity',
|
||||
'hashchange',
|
||||
'languagechange',
|
||||
'message',
|
||||
'mozbeforepaint',
|
||||
'offline',
|
||||
'online',
|
||||
'paint',
|
||||
'pageshow',
|
||||
'pagehide',
|
||||
'popstate',
|
||||
'rejectionhandled',
|
||||
'storage',
|
||||
'unhandledrejection',
|
||||
'unload',
|
||||
'userproximity',
|
||||
'vrdisplyconnected',
|
||||
'vrdisplaydisconnected',
|
||||
'vrdisplaypresentchange'
|
||||
];
|
||||
const htmlElementEventNames = [
|
||||
'beforecopy', 'beforecut', 'beforepaste', 'copy', 'cut', 'paste', 'dragstart', 'loadend',
|
||||
'animationstart', 'search', 'transitionrun', 'transitionstart', 'webkitanimationend',
|
||||
'webkitanimationiteration', 'webkitanimationstart', 'webkittransitionend'
|
||||
];
|
||||
const mediaElementEventNames =
|
||||
['encrypted', 'waitingforkey', 'msneedkey', 'mozinterruptbegin', 'mozinterruptend'];
|
||||
const ieElementEventNames = [
|
||||
'activate',
|
||||
'afterupdate',
|
||||
'ariarequest',
|
||||
'beforeactivate',
|
||||
'beforedeactivate',
|
||||
'beforeeditfocus',
|
||||
'beforeupdate',
|
||||
'cellchange',
|
||||
'controlselect',
|
||||
'dataavailable',
|
||||
'datasetchanged',
|
||||
'datasetcomplete',
|
||||
'errorupdate',
|
||||
'filterchange',
|
||||
'layoutcomplete',
|
||||
'losecapture',
|
||||
'move',
|
||||
'moveend',
|
||||
'movestart',
|
||||
'propertychange',
|
||||
'resizeend',
|
||||
'resizestart',
|
||||
'rowenter',
|
||||
'rowexit',
|
||||
'rowsdelete',
|
||||
'rowsinserted',
|
||||
'command',
|
||||
'compassneedscalibration',
|
||||
'deactivate',
|
||||
'help',
|
||||
'mscontentzoom',
|
||||
'msmanipulationstatechanged',
|
||||
'msgesturechange',
|
||||
'msgesturedoubletap',
|
||||
'msgestureend',
|
||||
'msgesturehold',
|
||||
'msgesturestart',
|
||||
'msgesturetap',
|
||||
'msgotpointercapture',
|
||||
'msinertiastart',
|
||||
'mslostpointercapture',
|
||||
'mspointercancel',
|
||||
'mspointerdown',
|
||||
'mspointerenter',
|
||||
'mspointerhover',
|
||||
'mspointerleave',
|
||||
'mspointermove',
|
||||
'mspointerout',
|
||||
'mspointerover',
|
||||
'mspointerup',
|
||||
'pointerout',
|
||||
'mssitemodejumplistitemremoved',
|
||||
'msthumbnailclick',
|
||||
'stop',
|
||||
'storagecommit'
|
||||
];
|
||||
const webglEventNames = ['webglcontextrestored', 'webglcontextlost', 'webglcontextcreationerror'];
|
||||
const formEventNames = ['autocomplete', 'autocompleteerror'];
|
||||
const detailEventNames = ['toggle'];
|
||||
const frameEventNames = ['load'];
|
||||
const frameSetEventNames = ['blur', 'error', 'focus', 'load', 'resize', 'scroll', 'messageerror'];
|
||||
const marqueeEventNames = ['bounce', 'finish', 'start'];
|
||||
|
||||
const XMLHttpRequestEventNames = [
|
||||
'loadstart', 'progress', 'abort', 'error', 'load', 'progress', 'timeout', 'loadend',
|
||||
'readystatechange'
|
||||
];
|
||||
const IDBIndexEventNames =
|
||||
['upgradeneeded', 'complete', 'abort', 'success', 'error', 'blocked', 'versionchange', 'close'];
|
||||
const websocketEventNames = ['close', 'error', 'open', 'message'];
|
||||
const workerEventNames = ['error', 'message'];
|
||||
|
||||
export const eventNames = globalEventHandlersEventNames.concat(
|
||||
webglEventNames, formEventNames, detailEventNames, documentEventNames, windowEventNames,
|
||||
htmlElementEventNames, ieElementEventNames);
|
||||
|
||||
export interface IgnoreProperty {
|
||||
target: any;
|
||||
ignoreProperties: string[];
|
||||
}
|
||||
|
||||
export function filterProperties(
|
||||
target: any, onProperties: string[], ignoreProperties: IgnoreProperty[]): string[] {
|
||||
if (!ignoreProperties || ignoreProperties.length === 0) {
|
||||
return onProperties;
|
||||
}
|
||||
|
||||
const tip: IgnoreProperty[] = ignoreProperties.filter(ip => ip.target === target);
|
||||
if (!tip || tip.length === 0) {
|
||||
return onProperties;
|
||||
}
|
||||
|
||||
const targetIgnoreProperties: string[] = tip[0].ignoreProperties;
|
||||
return onProperties.filter(op => targetIgnoreProperties.indexOf(op) === -1);
|
||||
}
|
||||
|
||||
export function patchFilteredProperties(
|
||||
target: any, onProperties: string[], ignoreProperties: IgnoreProperty[], 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);
|
||||
}
|
||||
|
||||
export function propertyDescriptorPatch(api: _ZonePrivate, _global: any) {
|
||||
if (isNode && !isMix) {
|
||||
return;
|
||||
}
|
||||
if ((Zone as any)[api.symbol('patchEvents')]) {
|
||||
// events are already been patched by legacy patch.
|
||||
return;
|
||||
}
|
||||
const supportsWebSocket = typeof WebSocket !== 'undefined';
|
||||
const ignoreProperties: IgnoreProperty[] = _global['__Zone_ignore_on_properties'];
|
||||
// for browsers that we can patch the descriptor: Chrome & Firefox
|
||||
if (isBrowser) {
|
||||
const internalWindow: any = window;
|
||||
const ignoreErrorProperties =
|
||||
isIE ? [{target: internalWindow, ignoreProperties: ['error']}] : [];
|
||||
// in IE/Edge, onProp not exist in window object, but in WindowPrototype
|
||||
// so we need to pass WindowPrototype to check onProp exist or not
|
||||
patchFilteredProperties(
|
||||
internalWindow, eventNames.concat(['messageerror']),
|
||||
ignoreProperties ? ignoreProperties.concat(ignoreErrorProperties) : ignoreProperties,
|
||||
ObjectGetPrototypeOf(internalWindow));
|
||||
patchFilteredProperties(Document.prototype, eventNames, ignoreProperties);
|
||||
|
||||
if (typeof internalWindow['SVGElement'] !== 'undefined') {
|
||||
patchFilteredProperties(internalWindow['SVGElement'].prototype, eventNames, ignoreProperties);
|
||||
}
|
||||
patchFilteredProperties(Element.prototype, eventNames, ignoreProperties);
|
||||
patchFilteredProperties(HTMLElement.prototype, eventNames, ignoreProperties);
|
||||
patchFilteredProperties(HTMLMediaElement.prototype, mediaElementEventNames, ignoreProperties);
|
||||
patchFilteredProperties(
|
||||
HTMLFrameSetElement.prototype, windowEventNames.concat(frameSetEventNames),
|
||||
ignoreProperties);
|
||||
patchFilteredProperties(
|
||||
HTMLBodyElement.prototype, windowEventNames.concat(frameSetEventNames), ignoreProperties);
|
||||
patchFilteredProperties(HTMLFrameElement.prototype, frameEventNames, ignoreProperties);
|
||||
patchFilteredProperties(HTMLIFrameElement.prototype, frameEventNames, ignoreProperties);
|
||||
|
||||
const HTMLMarqueeElement = internalWindow['HTMLMarqueeElement'];
|
||||
if (HTMLMarqueeElement) {
|
||||
patchFilteredProperties(HTMLMarqueeElement.prototype, marqueeEventNames, ignoreProperties);
|
||||
}
|
||||
const Worker = internalWindow['Worker'];
|
||||
if (Worker) {
|
||||
patchFilteredProperties(Worker.prototype, workerEventNames, ignoreProperties);
|
||||
}
|
||||
}
|
||||
const XMLHttpRequest = _global['XMLHttpRequest'];
|
||||
if (XMLHttpRequest) {
|
||||
// XMLHttpRequest is not available in ServiceWorker, so we need to check here
|
||||
patchFilteredProperties(XMLHttpRequest.prototype, XMLHttpRequestEventNames, ignoreProperties);
|
||||
}
|
||||
const XMLHttpRequestEventTarget = _global['XMLHttpRequestEventTarget'];
|
||||
if (XMLHttpRequestEventTarget) {
|
||||
patchFilteredProperties(
|
||||
XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype, XMLHttpRequestEventNames,
|
||||
ignoreProperties);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (supportsWebSocket) {
|
||||
patchFilteredProperties(WebSocket.prototype, websocketEventNames, ignoreProperties);
|
||||
}
|
||||
}
|
19
packages/zone.js/lib/browser/register-element.ts
Normal file
19
packages/zone.js/lib/browser/register-element.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export function registerElementPatch(_global: any, api: _ZonePrivate) {
|
||||
const {isBrowser, isMix} = api.getGlobalObjects() !;
|
||||
if ((!isBrowser && !isMix) || !('registerElement' in (<any>_global).document)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const callbacks =
|
||||
['createdCallback', 'attachedCallback', 'detachedCallback', 'attributeChangedCallback'];
|
||||
|
||||
api.patchCallbacks(api, document, 'Document', 'registerElement', callbacks);
|
||||
}
|
12
packages/zone.js/lib/browser/rollup-common.ts
Normal file
12
packages/zone.js/lib/browser/rollup-common.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import '../zone';
|
||||
import '../common/promise';
|
||||
import '../common/to-string';
|
||||
import './api-util';
|
11
packages/zone.js/lib/browser/rollup-legacy-main.ts
Normal file
11
packages/zone.js/lib/browser/rollup-legacy-main.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import './rollup-common';
|
||||
import './browser-legacy';
|
||||
import './browser';
|
12
packages/zone.js/lib/browser/rollup-legacy-test-main.ts
Normal file
12
packages/zone.js/lib/browser/rollup-legacy-test-main.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import './rollup-legacy-main';
|
||||
|
||||
// load test related files into bundle
|
||||
import '../testing/zone-testing';
|
10
packages/zone.js/lib/browser/rollup-main.ts
Normal file
10
packages/zone.js/lib/browser/rollup-main.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import './rollup-common';
|
||||
import './browser';
|
12
packages/zone.js/lib/browser/rollup-test-main.ts
Normal file
12
packages/zone.js/lib/browser/rollup-test-main.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import './rollup-main';
|
||||
|
||||
// load test related files into bundle
|
||||
import '../testing/zone-testing';
|
24
packages/zone.js/lib/browser/shadydom.ts
Normal file
24
packages/zone.js/lib/browser/shadydom.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
Zone.__load_patch('shadydom', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
// https://github.com/angular/zone.js/issues/782
|
||||
// in web components, shadydom will patch addEventListener/removeEventListener of
|
||||
// Node.prototype and WindowPrototype, this will have conflict with zone.js
|
||||
// so zone.js need to patch them again.
|
||||
const windowPrototype = Object.getPrototypeOf(window);
|
||||
if (windowPrototype && windowPrototype.hasOwnProperty('addEventListener')) {
|
||||
(windowPrototype as any)[Zone.__symbol__('addEventListener')] = null;
|
||||
(windowPrototype as any)[Zone.__symbol__('removeEventListener')] = null;
|
||||
api.patchEventTarget(global, [windowPrototype]);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
});
|
65
packages/zone.js/lib/browser/webapis-media-query.ts
Normal file
65
packages/zone.js/lib/browser/webapis-media-query.ts
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
Zone.__load_patch('mediaQuery', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
function patchAddListener(proto: any) {
|
||||
api.patchMethod(proto, 'addListener', (delegate: Function) => (self: any, args: any[]) => {
|
||||
const callback = args.length > 0 ? args[0] : null;
|
||||
if (typeof callback === 'function') {
|
||||
const wrapperedCallback = Zone.current.wrap(callback, 'MediaQuery');
|
||||
callback[api.symbol('mediaQueryCallback')] = wrapperedCallback;
|
||||
return delegate.call(self, wrapperedCallback);
|
||||
} else {
|
||||
return delegate.apply(self, args);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function patchRemoveListener(proto: any) {
|
||||
api.patchMethod(proto, 'removeListener', (delegate: Function) => (self: any, args: any[]) => {
|
||||
const callback = args.length > 0 ? args[0] : null;
|
||||
if (typeof callback === 'function') {
|
||||
const wrapperedCallback = callback[api.symbol('mediaQueryCallback')];
|
||||
if (wrapperedCallback) {
|
||||
return delegate.call(self, wrapperedCallback);
|
||||
} else {
|
||||
return delegate.apply(self, args);
|
||||
}
|
||||
} else {
|
||||
return delegate.apply(self, args);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (global['MediaQueryList']) {
|
||||
const proto = global['MediaQueryList'].prototype;
|
||||
patchAddListener(proto);
|
||||
patchRemoveListener(proto);
|
||||
} else if (global['matchMedia']) {
|
||||
api.patchMethod(global, 'matchMedia', (delegate: Function) => (self: any, args: any[]) => {
|
||||
const mql = delegate.apply(self, args);
|
||||
if (mql) {
|
||||
// try to patch MediaQueryList.prototype
|
||||
const proto = Object.getPrototypeOf(mql);
|
||||
if (proto && proto['addListener']) {
|
||||
// try to patch proto, don't need to worry about patch
|
||||
// multiple times, because, api.patchEventTarget will check it
|
||||
patchAddListener(proto);
|
||||
patchRemoveListener(proto);
|
||||
patchAddListener(mql);
|
||||
patchRemoveListener(mql);
|
||||
} else if (mql['addListener']) {
|
||||
// proto not exists, or proto has no addListener method
|
||||
// try to patch mql instance
|
||||
patchAddListener(mql);
|
||||
patchRemoveListener(mql);
|
||||
}
|
||||
}
|
||||
return mql;
|
||||
});
|
||||
}
|
||||
});
|
18
packages/zone.js/lib/browser/webapis-notification.ts
Normal file
18
packages/zone.js/lib/browser/webapis-notification.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
Zone.__load_patch('notification', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
const Notification = global['Notification'];
|
||||
if (!Notification || !Notification.prototype) {
|
||||
return;
|
||||
}
|
||||
const desc = Object.getOwnPropertyDescriptor(Notification.prototype, 'onerror');
|
||||
if (!desc || !desc.configurable) {
|
||||
return;
|
||||
}
|
||||
api.patchOnProperties(Notification.prototype, null);
|
||||
});
|
91
packages/zone.js/lib/browser/webapis-resize-observer.ts
Normal file
91
packages/zone.js/lib/browser/webapis-resize-observer.ts
Normal file
@ -0,0 +1,91 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
Zone.__load_patch('ResizeObserver', (global: any, Zone: any, api: _ZonePrivate) => {
|
||||
const ResizeObserver = global['ResizeObserver'];
|
||||
if (!ResizeObserver) {
|
||||
return;
|
||||
}
|
||||
|
||||
const resizeObserverSymbol = api.symbol('ResizeObserver');
|
||||
|
||||
api.patchMethod(global, 'ResizeObserver', (delegate: Function) => (self: any, args: any[]) => {
|
||||
const callback = args.length > 0 ? args[0] : null;
|
||||
if (callback) {
|
||||
args[0] = function(entries: any, observer: any) {
|
||||
const zones: {[zoneName: string]: any} = {};
|
||||
const currZone = Zone.current;
|
||||
for (let entry of entries) {
|
||||
let zone = entry.target[resizeObserverSymbol];
|
||||
if (!zone) {
|
||||
zone = currZone;
|
||||
}
|
||||
let zoneEntriesInfo = zones[zone.name];
|
||||
if (!zoneEntriesInfo) {
|
||||
zones[zone.name] = zoneEntriesInfo = {entries: [], zone: zone};
|
||||
}
|
||||
zoneEntriesInfo.entries.push(entry);
|
||||
}
|
||||
|
||||
Object.keys(zones).forEach(zoneName => {
|
||||
const zoneEntriesInfo = zones[zoneName];
|
||||
if (zoneEntriesInfo.zone !== Zone.current) {
|
||||
zoneEntriesInfo.zone.run(
|
||||
callback, this, [zoneEntriesInfo.entries, observer], 'ResizeObserver');
|
||||
} else {
|
||||
callback.call(this, zoneEntriesInfo.entries, observer);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
return args.length > 0 ? new ResizeObserver(args[0]) : new ResizeObserver();
|
||||
});
|
||||
|
||||
api.patchMethod(
|
||||
ResizeObserver.prototype, 'observe', (delegate: Function) => (self: any, args: any[]) => {
|
||||
const target = args.length > 0 ? args[0] : null;
|
||||
if (!target) {
|
||||
return delegate.apply(self, args);
|
||||
}
|
||||
let targets = self[resizeObserverSymbol];
|
||||
if (!targets) {
|
||||
targets = self[resizeObserverSymbol] = [];
|
||||
}
|
||||
targets.push(target);
|
||||
target[resizeObserverSymbol] = Zone.current;
|
||||
return delegate.apply(self, args);
|
||||
});
|
||||
|
||||
api.patchMethod(
|
||||
ResizeObserver.prototype, 'unobserve', (delegate: Function) => (self: any, args: any[]) => {
|
||||
const target = args.length > 0 ? args[0] : null;
|
||||
if (!target) {
|
||||
return delegate.apply(self, args);
|
||||
}
|
||||
let targets = self[resizeObserverSymbol];
|
||||
if (targets) {
|
||||
for (let i = 0; i < targets.length; i++) {
|
||||
if (targets[i] === target) {
|
||||
targets.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
target[resizeObserverSymbol] = undefined;
|
||||
return delegate.apply(self, args);
|
||||
});
|
||||
|
||||
api.patchMethod(
|
||||
ResizeObserver.prototype, 'disconnect', (delegate: Function) => (self: any, args: any[]) => {
|
||||
const targets = self[resizeObserverSymbol];
|
||||
if (targets) {
|
||||
targets.forEach((target: any) => { target[resizeObserverSymbol] = undefined; });
|
||||
self[resizeObserverSymbol] = undefined;
|
||||
}
|
||||
return delegate.apply(self, args);
|
||||
});
|
||||
});
|
26
packages/zone.js/lib/browser/webapis-rtc-peer-connection.ts
Normal file
26
packages/zone.js/lib/browser/webapis-rtc-peer-connection.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
Zone.__load_patch('RTCPeerConnection', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
||||
const RTCPeerConnection = global['RTCPeerConnection'];
|
||||
if (!RTCPeerConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
const addSymbol = api.symbol('addEventListener');
|
||||
const removeSymbol = api.symbol('removeEventListener');
|
||||
|
||||
RTCPeerConnection.prototype.addEventListener = RTCPeerConnection.prototype[addSymbol];
|
||||
RTCPeerConnection.prototype.removeEventListener = RTCPeerConnection.prototype[removeSymbol];
|
||||
|
||||
// RTCPeerConnection extends EventTarget, so we must clear the symbol
|
||||
// to allow patch RTCPeerConnection.prototype.addEventListener again
|
||||
RTCPeerConnection.prototype[addSymbol] = null;
|
||||
RTCPeerConnection.prototype[removeSymbol] = null;
|
||||
|
||||
api.patchEventTarget(global, [RTCPeerConnection.prototype], {useG: false});
|
||||
});
|
20
packages/zone.js/lib/browser/webapis-user-media.ts
Normal file
20
packages/zone.js/lib/browser/webapis-user-media.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
Zone.__load_patch('getUserMedia', (global: any, Zone: any, api: _ZonePrivate) => {
|
||||
function wrapFunctionArgs(func: Function, source?: string): Function {
|
||||
return function() {
|
||||
const args = Array.prototype.slice.call(arguments);
|
||||
const wrappedArgs = api.bindArguments(args, source ? source : (func as any).name);
|
||||
return func.apply(this, wrappedArgs);
|
||||
};
|
||||
}
|
||||
let navigator = global['navigator'];
|
||||
if (navigator && navigator.getUserMedia) {
|
||||
navigator.getUserMedia = wrapFunctionArgs(navigator.getUserMedia);
|
||||
}
|
||||
});
|
59
packages/zone.js/lib/browser/websocket.ts
Normal file
59
packages/zone.js/lib/browser/websocket.ts
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// we have to patch the instance since the proto is non-configurable
|
||||
export function apply(api: _ZonePrivate, _global: any) {
|
||||
const {ADD_EVENT_LISTENER_STR, REMOVE_EVENT_LISTENER_STR} = api.getGlobalObjects() !;
|
||||
const WS = (<any>_global).WebSocket;
|
||||
// On Safari window.EventTarget doesn't exist so need to patch WS add/removeEventListener
|
||||
// On older Chrome, no need since EventTarget was already patched
|
||||
if (!(<any>_global).EventTarget) {
|
||||
api.patchEventTarget(_global, [WS.prototype]);
|
||||
}
|
||||
(<any>_global).WebSocket = function(x: any, y: any) {
|
||||
const socket = arguments.length > 1 ? new WS(x, y) : new WS(x);
|
||||
let proxySocket: any;
|
||||
|
||||
let proxySocketProto: any;
|
||||
|
||||
// Safari 7.0 has non-configurable own 'onmessage' and friends properties on the socket instance
|
||||
const onmessageDesc = api.ObjectGetOwnPropertyDescriptor(socket, 'onmessage');
|
||||
if (onmessageDesc && onmessageDesc.configurable === false) {
|
||||
proxySocket = api.ObjectCreate(socket);
|
||||
// socket have own property descriptor 'onopen', 'onmessage', 'onclose', 'onerror'
|
||||
// but proxySocket not, so we will keep socket as prototype and pass it to
|
||||
// patchOnProperties method
|
||||
proxySocketProto = socket;
|
||||
[ADD_EVENT_LISTENER_STR, REMOVE_EVENT_LISTENER_STR, 'send', 'close'].forEach(function(
|
||||
propName) {
|
||||
proxySocket[propName] = function() {
|
||||
const args = api.ArraySlice.call(arguments);
|
||||
if (propName === ADD_EVENT_LISTENER_STR || propName === REMOVE_EVENT_LISTENER_STR) {
|
||||
const eventName = args.length > 0 ? args[0] : undefined;
|
||||
if (eventName) {
|
||||
const propertySymbol = Zone.__symbol__('ON_PROPERTY' + eventName);
|
||||
socket[propertySymbol] = proxySocket[propertySymbol];
|
||||
}
|
||||
}
|
||||
return socket[propName].apply(socket, args);
|
||||
};
|
||||
});
|
||||
} else {
|
||||
// we can patch the real socket
|
||||
proxySocket = socket;
|
||||
}
|
||||
|
||||
api.patchOnProperties(proxySocket, ['close', 'error', 'message', 'open'], proxySocketProto);
|
||||
return proxySocket;
|
||||
};
|
||||
|
||||
const globalWebSocket = _global['WebSocket'];
|
||||
for (const prop in WS) {
|
||||
globalWebSocket[prop] = WS[prop];
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user