Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.
Merged
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
7 changes: 6 additions & 1 deletion file-size-limit.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
{
"targets": [
{
"path": "dist/zone.min.js",
"path": "dist/zone-evergreen.min.js",
"checkTarget": true,
"limit": 43000
},
{
"path": "dist/zone.min.js",
"checkTarget": true,
"limit": 44000
}
]
}
33 changes: 32 additions & 1 deletion lib/browser/api-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/

import {bindArguments, patchMacroTask, patchMethod, patchOnProperties} from '../common/utils';
import {globalSources, patchEventPrototype, patchEventTarget, zoneSymbolEventNames} from '../common/events';
import {ADD_EVENT_LISTENER_STR, ArraySlice, attachOriginToPatched, bindArguments, FALSE_STR, isBrowser, isIEOrEdge, isMix, isNode, ObjectCreate, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, patchClass, patchMacroTask, patchMethod, patchOnProperties, REMOVE_EVENT_LISTENER_STR, TRUE_STR, wrapWithCurrentZone, ZONE_SYMBOL_PREFIX} 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;
Expand All @@ -28,4 +33,30 @@ Zone.__load_patch('util', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
(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
});
});
19 changes: 12 additions & 7 deletions lib/browser/browser-legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@ import {eventTargetLegacyPatch} from './event-target-legacy';
import {propertyDescriptorLegacyPatch} from './property-descriptor-legacy';
import {registerElementPatch} from './register-element';

Zone.__load_patch('registerElement', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
registerElementPatch(global);
});
(function(_global: any) {
_global['__zone_symbol__legacyPatch'] = function() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it necessary to add __zone_symbol__legacyPatch to the global? Who invokes that function?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, here is the flow.

  1. loading browser-legacy.js, and register this factory function in global.
  2. loading zone-evergreen.js, and call this __zone_symbol__legacyPatch here, https://github.com/angular/zone.js/pull/1201/files#diff-75082c639aefcc47b3b8df57c8870867R23, so the legacy patch can be loaded after the common logic of zone is loaded.

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);
});
Zone.__load_patch('EventTargetLegacy', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
eventTargetLegacyPatch(global, api);
propertyDescriptorLegacyPatch(api, global);
});
};
})(typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global);
38 changes: 38 additions & 0 deletions lib/browser/browser-util.ts
Original file line number Diff line number Diff line change
@@ -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);
}
10 changes: 8 additions & 2 deletions lib/browser/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ import {patchCustomElements} from './custom-elements';
import {propertyPatch} from './define-property';
import {eventTargetPatch, patchEvent} from './event-target';
import {propertyDescriptorPatch} from './property-descriptor';
import {registerElementPatch} from './register-element';

Zone.__load_patch('legacy', (global: any) => {
const legacyPatch = global[Zone.__symbol__('legacyPatch')];
if (legacyPatch) {
legacyPatch();
}
});

Zone.__load_patch('timers', (global: any) => {
const set = 'set';
Expand Down Expand Up @@ -66,7 +72,7 @@ Zone.__load_patch('on_property', (global: any, Zone: ZoneType, api: _ZonePrivate
});

Zone.__load_patch('customElements', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
patchCustomElements(global);
patchCustomElements(global, api);
});

Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
Expand Down
41 changes: 3 additions & 38 deletions lib/browser/custom-elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/

import {attachOriginToPatched, isBrowser, isMix, ObjectGetOwnPropertyDescriptor, wrapWithCurrentZone} from '../common/utils';

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

export function patchCallbacks(
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 = ObjectGetOwnPropertyDescriptor(prototype, callback);
if (descriptor && descriptor.value) {
descriptor.value = wrapWithCurrentZone(descriptor.value, source);
_redefineProperty(opts.prototype, callback, descriptor);
} else if (prototype[callback]) {
prototype[callback] = wrapWithCurrentZone(prototype[callback], source);
}
} else if (prototype[callback]) {
prototype[callback] = wrapWithCurrentZone(prototype[callback], source);
}
});
}

return nativeDelegate.call(target, name, opts, options);
};

attachOriginToPatched(target[method], nativeDelegate);
}

export function patchCustomElements(_global: any) {
export function patchCustomElements(_global: any, api: _ZonePrivate) {
const {isBrowser, isMix} = api.getGlobalObjects()!;
if ((!isBrowser && !isMix) || !('customElements' in _global)) {
return;
}

const callbacks =
['connectedCallback', 'disconnectedCallback', 'adoptedCallback', 'attributeChangedCallback'];

patchCallbacks(_global.customElements, 'customElements', 'define', callbacks);
api.patchCallbacks(api, _global.customElements, 'customElements', 'define', callbacks);
}
2 changes: 1 addition & 1 deletion lib/browser/define-property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/

import {zoneSymbol} from '../common/utils';
/*
* 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;
Expand Down
13 changes: 5 additions & 8 deletions lib/browser/event-target-legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/

import {globalSources, patchEventPrototype, patchEventTarget, zoneSymbolEventNames} from '../common/events';
import {FALSE_STR, isIEOrEdge, TRUE_STR, ZONE_SYMBOL_PREFIX} from '../common/utils';

import {eventNames} from './property-descriptor';

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 =
Expand All @@ -36,7 +33,7 @@ export function eventTargetLegacyPatch(_global: any, api: _ZonePrivate) {

const isDisableIECheck = _global['__Zone_disable_IE_check'] || false;
const isEnableCrossContextCheck = _global['__Zone_enable_cross_context_check'] || false;
const ieOrEdge = isIEOrEdge();
const ieOrEdge = api.isIEOrEdge();

const ADD_EVENT_LISTENER_SOURCE = '.addEventListener:';
const FUNCTION_WRAPPER = '[object FunctionWrapper]';
Expand Down Expand Up @@ -103,11 +100,11 @@ export function eventTargetLegacyPatch(_global: any, api: _ZonePrivate) {
}
// vh is validateHandler to check event handler
// is valid or not(for security check)
patchEventTarget(_global, apiTypes, {vh: checkIEAndCrossContext});
api.patchEventTarget(_global, apiTypes, {vh: checkIEAndCrossContext});

return true;
}

export function patchEvent(global: any, api: _ZonePrivate) {
patchEventPrototype(global, api);
api.patchEventPrototype(global, api);
}
12 changes: 4 additions & 8 deletions lib/browser/event-target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/

import {globalSources, patchEventPrototype, patchEventTarget, zoneSymbolEventNames} from '../common/events';
import {FALSE_STR, TRUE_STR, ZONE_SYMBOL_PREFIX} from '../common/utils';

import {eventNames} from './property-descriptor';

export function eventTargetPatch(_global: any, api: _ZonePrivate) {
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];
Expand All @@ -28,12 +25,11 @@ export function eventTargetPatch(_global: any, api: _ZonePrivate) {
if (!EVENT_TARGET || !EVENT_TARGET.prototype) {
return;
}
patchEventTarget(_global, [EVENT_TARGET && EVENT_TARGET.prototype]);
api.patchEventTarget = patchEventTarget;
api.patchEventTarget(_global, [EVENT_TARGET && EVENT_TARGET.prototype]);

return true;
}

export function patchEvent(global: any, api: _ZonePrivate) {
patchEventPrototype(global, api);
api.patchEventPrototype(global, api);
}
48 changes: 19 additions & 29 deletions lib/browser/property-descriptor-legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,52 +10,42 @@
* @suppress {globalThis}
*/

import {isBrowser, isMix, isNode, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, patchClass, patchOnProperties, wrapWithCurrentZone, zoneSymbol} from '../common/utils';

import {eventNames, filterProperties, IgnoreProperty} from './property-descriptor';
import * as webSocketPatch from './websocket';

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 propertyDescriptorLegacyPatch(api: _ZonePrivate, _global: any) {
const {isNode, isMix} = api.getGlobalObjects()!;
if (isNode && !isMix) {
return;
}

const supportsWebSocket = typeof WebSocket !== 'undefined';
if (!canPatchViaPropertyDescriptor()) {
if (!canPatchViaPropertyDescriptor(api)) {
// Safari, Android browsers (Jelly Bean)
patchViaCapturingAllTheEvents();
patchClass('XMLHttpRequest');
patchViaCapturingAllTheEvents(api);
api.patchClass('XMLHttpRequest');
if (supportsWebSocket) {
webSocketPatch.apply(api, _global);
}
(Zone as any)[api.symbol('patchEvents')] = true;
}
}

function canPatchViaPropertyDescriptor() {
if ((isBrowser || isMix) && !ObjectGetOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') &&
function canPatchViaPropertyDescriptor(api: _ZonePrivate) {
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 = ObjectGetOwnPropertyDescriptor(Element.prototype, 'onclick');
const desc = api.ObjectGetOwnPropertyDescriptor(Element.prototype, 'onclick');
if (desc && !desc.configurable) return false;
}

const ON_READY_STATE_CHANGE = 'onreadystatechange';
const XMLHttpRequestPrototype = XMLHttpRequest.prototype;

const xhrDesc = ObjectGetOwnPropertyDescriptor(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE);
const xhrDesc =
api.ObjectGetOwnPropertyDescriptor(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE);

// add enumerable and configurable here because in opera
// by default XMLHttpRequest.prototype.onreadystatechange is undefined
Expand All @@ -64,7 +54,7 @@ function canPatchViaPropertyDescriptor() {
// and if XMLHttpRequest.prototype.onreadystatechange is undefined,
// we should set a real desc instead a fake one
if (xhrDesc) {
ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, {
api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, {
enumerable: true,
configurable: true,
get: function() {
Expand All @@ -74,11 +64,11 @@ function canPatchViaPropertyDescriptor() {
const req = new XMLHttpRequest();
const result = !!req.onreadystatechange;
// restore original desc
ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, xhrDesc || {});
api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, xhrDesc || {});
return result;
} else {
const SYMBOL_FAKE_ONREADYSTATECHANGE = zoneSymbol('fake');
ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, {
const SYMBOL_FAKE_ONREADYSTATECHANGE = api.symbol('fake');
api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, {
enumerable: true,
configurable: true,
get: function() {
Expand All @@ -97,12 +87,12 @@ function canPatchViaPropertyDescriptor() {
}
}

const unboundKey = zoneSymbol('unbound');

// 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() {
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;
Expand All @@ -115,7 +105,7 @@ function patchViaCapturingAllTheEvents() {
}
while (elt) {
if (elt[onproperty] && !elt[onproperty][unboundKey]) {
bound = wrapWithCurrentZone(elt[onproperty], source);
bound = api.wrapWithCurrentZone(elt[onproperty], source);
bound[unboundKey] = elt[onproperty];
elt[onproperty] = bound;
}
Expand Down
Loading