From 0c5da0443248a3bdd46e6e5ac0b15b7bf360b84c Mon Sep 17 00:00:00 2001 From: JiaLiPassion Date: Sat, 3 Jun 2017 01:38:58 +0900 Subject: [PATCH 1/7] fix(doc): fix #793, fix confuse bluebird patch doc (#794) --- NON-STANDARD-APIS.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/NON-STANDARD-APIS.md b/NON-STANDARD-APIS.md index 6e6f6dbb7..2f8967b9b 100644 --- a/NON-STANDARD-APIS.md +++ b/NON-STANDARD-APIS.md @@ -42,13 +42,20 @@ Browser Usage: After those steps, window.Promise will become a ZoneAware Bluebird Promise. -Node Usage: +Node Sample Usage: ``` -require('zone-node.js'); +require('zone.js'); const Bluebird = require('bluebird'); -require('zone-bluebird.js'); +require('zone.js/dist/zone-bluebird'); Zone[Zone['__symbol__']('bluebird')](Bluebird); +Zone.current.fork({ + name: 'bluebird' +}).run(() => { + Bluebird.resolve(1).then(r => { + console.log('result ', r, 'Zone', Zone.current.name); + }); +}); ``` In NodeJS environment, you can choose to use Bluebird Promise as global.Promise From 67634aefcff7c6497e3c8ee9ae7eca9eb41fa0eb Mon Sep 17 00:00:00 2001 From: JiaLiPassion Date: Sat, 3 Jun 2017 01:39:21 +0900 Subject: [PATCH 2/7] fix(patch): fix #791, fix mediaQuery/Notification patch use wrong global (#792) --- lib/browser/webapis-media-query.ts | 2 +- lib/browser/webapis-notification.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/browser/webapis-media-query.ts b/lib/browser/webapis-media-query.ts index dbe709f71..6172239d3 100644 --- a/lib/browser/webapis-media-query.ts +++ b/lib/browser/webapis-media-query.ts @@ -10,7 +10,7 @@ Zone.__load_patch('mediaQuery', (global: any, Zone: ZoneType, api: _ZonePrivate) return; } api.patchEventTargetMethods( - _global['MediaQueryList'].prototype, 'addListener', 'removeListener', + global['MediaQueryList'].prototype, 'addListener', 'removeListener', (self: any, args: any[]) => { return { useCapturing: false, diff --git a/lib/browser/webapis-notification.ts b/lib/browser/webapis-notification.ts index 42ffd0e67..1bccaa9c9 100644 --- a/lib/browser/webapis-notification.ts +++ b/lib/browser/webapis-notification.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ Zone.__load_patch('notification', (global: any, Zone: ZoneType, api: _ZonePrivate) => { - const Notification = _global['Notification']; + const Notification = global['Notification']; if (!Notification || !Notification.prototype) { return; } From 7ca39953196c86e40b522224616fc0be5cd2a05d Mon Sep 17 00:00:00 2001 From: JiaLiPassion Date: Sat, 3 Jun 2017 02:11:34 +0900 Subject: [PATCH 3/7] feat(patch): fix #696, patch HTMLCanvasElement.toBlob as MacroTask (#788) --- lib/browser/browser.ts | 12 +++++++- test/browser/browser.spec.ts | 53 +++++++++++++++++++++++++++++++++++- test/test-util.ts | 41 ++++++++++++++++++++++------ 3 files changed, 95 insertions(+), 11 deletions(-) diff --git a/lib/browser/browser.ts b/lib/browser/browser.ts index 745910db4..7d48acefb 100644 --- a/lib/browser/browser.ts +++ b/lib/browser/browser.ts @@ -7,7 +7,7 @@ */ import {patchTimer} from '../common/timers'; -import {findEventTask, patchClass, patchEventTargetMethods, patchMethod, patchOnProperties, patchPrototype, zoneSymbol} from '../common/utils'; +import {findEventTask, patchClass, patchEventTargetMethods, patchMacroTask, patchMethod, patchOnProperties, patchPrototype, zoneSymbol} from '../common/utils'; import {propertyPatch} from './define-property'; import {eventTargetPatch} from './event-target'; @@ -55,6 +55,16 @@ Zone.__load_patch('on_property', (global: any, Zone: ZoneType, api: _ZonePrivate registerElementPatch(global); }); +Zone.__load_patch('canvas', (global: any, Zone: 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, callbackIndex: 0, args: args}; + }); + } +}); + Zone.__load_patch('XHR', (global: any, Zone: ZoneType, api: _ZonePrivate) => { // Treat XMLHTTPRequest as a macrotask. patchXHR(global); diff --git a/test/browser/browser.spec.ts b/test/browser/browser.spec.ts index eff57d8f3..edbef240a 100644 --- a/test/browser/browser.spec.ts +++ b/test/browser/browser.spec.ts @@ -7,7 +7,7 @@ */ import {isBrowser, isMix, zoneSymbol} from '../../lib/common/utils'; -import {ifEnvSupports} from '../test-util'; +import {ifEnvSupports, ifEnvSupportsWithDone} from '../test-util'; import Spy = jasmine.Spy; declare const global: any; @@ -54,6 +54,17 @@ function supportEventListenerOptions() { (supportEventListenerOptions as any).message = 'supportsEventListenerOptions'; +function supportCanvasTest() { + const HTMLCanvasElement = (window as any)['HTMLCanvasElement']; + const supportCanvas = typeof HTMLCanvasElement !== 'undefined' && HTMLCanvasElement.prototype && + HTMLCanvasElement.prototype.toBlob; + const FileReader = (window as any)['FileReader']; + const supportFileReader = typeof FileReader !== 'undefined'; + return supportCanvas && supportFileReader; +} + +(supportCanvasTest as any).message = 'supportCanvasTest'; + describe('Zone', function() { const rootZone = Zone.current; (Zone as any)[zoneSymbol('ignoreConsoleErrorUncaughtError')] = true; @@ -666,5 +677,45 @@ describe('Zone', function() { }); })); }); + + it('HTMLCanvasElement.toBlob should be a ZoneAware MacroTask', + ifEnvSupportsWithDone(supportCanvasTest, (done: Function) => { + const canvas = document.createElement('canvas'); + const d = canvas.width; + const ctx = canvas.getContext('2d'); + ctx.beginPath(); + ctx.moveTo(d / 2, 0); + ctx.lineTo(d, d); + ctx.lineTo(0, d); + ctx.closePath(); + ctx.fillStyle = 'yellow'; + ctx.fill(); + + const scheduleSpy = jasmine.createSpy('scheduleSpy'); + const zone: Zone = Zone.current.fork({ + name: 'canvas', + onScheduleTask: + (delegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task) => { + scheduleSpy(); + return delegate.scheduleTask(targetZone, task); + } + }); + + zone.run(() => { + const canvasData = canvas.toDataURL(); + canvas.toBlob(function(blob) { + expect(Zone.current.name).toEqual('canvas'); + expect(scheduleSpy).toHaveBeenCalled(); + + const reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onloadend = function() { + const base64data = reader.result; + expect(base64data).toEqual(canvasData); + done(); + }; + }); + }); + })); }); }); diff --git a/test/test-util.ts b/test/test-util.ts index f6236f570..5ff204eb8 100644 --- a/test/test-util.ts +++ b/test/test-util.ts @@ -22,15 +22,38 @@ * ifEnvSupports(supportsOnClick, function() { ... }); */ declare const global: any; -export function ifEnvSupports(test: any, block: Function) { - return function() { - const message = (test.message || test.name || test); - if (typeof test === 'string' ? !!global[test] : test()) { - block(); +export function ifEnvSupports(test: any, block: Function): () => void { + return _ifEnvSupports(test, block); +} + +export function ifEnvSupportsWithDone(test: any, block: Function): (done: Function) => void { + return _ifEnvSupports(test, block, true); +} + +function _ifEnvSupports(test: any, block: Function, withDone = false) { + if (withDone) { + return function(done?: Function) { + _runTest(test, block, done); + }; + } else { + return function() { + _runTest(test, block, undefined); + }; + } +} + +function _runTest(test: any, block: Function, done: Function) { + const message = (test.message || test.name || test); + if (typeof test === 'string' ? !!global[test] : test()) { + if (done) { + block(done); } else { - it('should skip the test if the API does not exist', function() { - console.log('WARNING: skipping ' + message + ' tests (missing this API)'); - }); + block(); } - }; + } else { + done && done(); + it('should skip the test if the API does not exist', function() { + console.log('WARNING: skipping ' + message + ' tests (missing this API)'); + }); + } } From 857929d81a16d09de5ee3d24beaeb44826a779ce Mon Sep 17 00:00:00 2001 From: JiaLiPassion Date: Sat, 3 Jun 2017 13:08:34 +0900 Subject: [PATCH 4/7] feat(patch): fix #758, patch cordova.exec success/error with zone.wrap (#789) * feat(patch): fix #758, patch cordova success/error with zone.wrap * add documents for cordova --- NON-STANDARD-APIS.md | 18 +++++++++ gulpfile.js | 10 +++++ karma-build.conf.js | 2 +- lib/browser/browser.ts | 1 + lib/extra/cordova.ts | 21 ++++++++++ lib/zone.ts | 7 +++- test/browser-zone-setup.ts | 3 +- test/browser_entry_point.ts | 3 +- test/extra/cordova.spec.ts | 40 +++++++++++++++++++ test/node_entry_point.ts | 2 +- ...{custom_error.ts => test_fake_polyfill.ts} | 15 +++++++ 11 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 lib/extra/cordova.ts create mode 100644 test/extra/cordova.spec.ts rename test/{custom_error.ts => test_fake_polyfill.ts} (55%) diff --git a/NON-STANDARD-APIS.md b/NON-STANDARD-APIS.md index 2f8967b9b..f68bc3ddc 100644 --- a/NON-STANDARD-APIS.md +++ b/NON-STANDARD-APIS.md @@ -74,6 +74,24 @@ remove the comment of the following line //import './extra/bluebird.spec'; ``` +## Others + +* Cordova + +patch `cordova.exec` API + +`cordova.exec(success, error, service, action, args);` + +`success` and `error` will be patched with `Zone.wrap`. + +to load the patch, you should load in the following order. + +``` + + + +``` + ## Usage By default, those APIs' support will not be loaded in zone.js or zone-node.js, diff --git a/gulpfile.js b/gulpfile.js index c5579ac6f..6d77c543f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -123,6 +123,14 @@ gulp.task('build/webapis-shadydom.min.js', ['compile-esm'], function(cb) { return generateScript('./lib/browser/shadydom.ts', 'webapis-shadydom.min.js', true, cb); }); +gulp.task('build/zone-patch-cordova.js', ['compile-esm'], function(cb) { + return generateScript('./lib/extra/cordova.ts', 'zone-patch-cordova.js', false, cb); +}); + +gulp.task('build/zone-patch-cordova.min.js', ['compile-esm'], function(cb) { + return generateScript('./lib/extra/cordova.ts', 'zone-patch-cordova.min.js', true, cb); +}); + gulp.task('build/bluebird.js', ['compile-esm'], function(cb) { return generateScript('./lib/extra/bluebird.ts', 'zone-bluebird.js', false, cb); }); @@ -204,6 +212,8 @@ gulp.task('build', [ 'build/webapis-notification.min.js', 'build/webapis-shadydom.js', 'build/webapis-shadydom.min.js', + 'build/zone-patch-cordova.js', + 'build/zone-patch-cordova.min.js', 'build/zone-mix.js', 'build/bluebird.js', 'build/bluebird.min.js', diff --git a/karma-build.conf.js b/karma-build.conf.js index 33ab1fea2..87c87a5ea 100644 --- a/karma-build.conf.js +++ b/karma-build.conf.js @@ -9,7 +9,7 @@ module.exports = function (config) { require('./karma-base.conf.js')(config); config.files.push('build/test/wtf_mock.js'); - config.files.push('build/test/custom_error.js'); + config.files.push('build/test/test_fake_polyfill.js'); config.files.push('build/lib/zone.js'); config.files.push('build/lib/common/promise.js'); config.files.push('build/lib/common/error-rewrite.js'); diff --git a/lib/browser/browser.ts b/lib/browser/browser.ts index 7d48acefb..63f045df0 100644 --- a/lib/browser/browser.ts +++ b/lib/browser/browser.ts @@ -203,4 +203,5 @@ Zone.__load_patch('PromiseRejectionEvent', (global: any, Zone: ZoneType, api: _Z Zone.__load_patch('util', (global: any, Zone: ZoneType, api: _ZonePrivate) => { api.patchEventTargetMethods = patchEventTargetMethods; api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; }); \ No newline at end of file diff --git a/lib/extra/cordova.ts b/lib/extra/cordova.ts new file mode 100644 index 000000000..d6ac49b12 --- /dev/null +++ b/lib/extra/cordova.ts @@ -0,0 +1,21 @@ +/** + * @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('cordova', (global: any, Zone: ZoneType, api: _ZonePrivate) => { + if (global.cordova) { + const nativeExec: Function = api.patchMethod( + global.cordova, 'exec', (delegate: Function) => function(self: any, args: any[]) { + if (args.length > 0 && typeof args[0] === 'function') { + args[0] = Zone.current.wrap(args[0], 'cordova.exec.success'); + } + if (args.length > 1 && typeof args[1] === 'function') { + args[1] = Zone.current.wrap(args[1], 'cordova.exec.error'); + } + return nativeExec.apply(self, args); + }); + } +}); \ No newline at end of file diff --git a/lib/zone.ts b/lib/zone.ts index d3f2bf597..38cb179ad 100644 --- a/lib/zone.ts +++ b/lib/zone.ts @@ -323,6 +323,10 @@ interface _ZonePrivate { patchEventTargetMethods: (obj: any, addFnName?: string, removeFnName?: string, metaCreator?: any) => boolean; patchOnProperties: (obj: any, properties: string[]) => void; + patchMethod: + (target: any, name: string, + patchFn: (delegate: Function, delegateName: string, name: string) => + (self: any, args: any[]) => any) => Function; } /** @internal */ @@ -1294,7 +1298,8 @@ const Zone: ZoneType = (function(global: any) { scheduleMicroTask: scheduleMicroTask, showUncaughtError: () => !(Zone as any)[__symbol__('ignoreConsoleErrorUncaughtError')], patchEventTargetMethods: () => false, - patchOnProperties: noop + patchOnProperties: noop, + patchMethod: () => noop }; let _currentZoneFrame: _ZoneFrame = {parent: null, zone: new Zone(null, null)}; let _currentTask: Task = null; diff --git a/test/browser-zone-setup.ts b/test/browser-zone-setup.ts index 70ec87fd5..1b3d6d6ed 100644 --- a/test/browser-zone-setup.ts +++ b/test/browser-zone-setup.ts @@ -14,4 +14,5 @@ import '../lib/zone-spec/long-stack-trace'; import '../lib/zone-spec/proxy'; import '../lib/zone-spec/sync-test'; import '../lib/zone-spec/task-tracking'; -import '../lib/zone-spec/wtf'; \ No newline at end of file +import '../lib/zone-spec/wtf'; +import '../lib/extra/cordova'; \ No newline at end of file diff --git a/test/browser_entry_point.ts b/test/browser_entry_point.ts index 99183dbec..25efb0b0f 100644 --- a/test/browser_entry_point.ts +++ b/test/browser_entry_point.ts @@ -22,4 +22,5 @@ import './browser/XMLHttpRequest.spec'; import './browser/MediaQuery.spec'; import './browser/Notification.spec'; import './mocha-patch.spec'; -import './jasmine-patch.spec'; \ No newline at end of file +import './jasmine-patch.spec'; +import './extra/cordova.spec'; \ No newline at end of file diff --git a/test/extra/cordova.spec.ts b/test/extra/cordova.spec.ts new file mode 100644 index 000000000..5884845a7 --- /dev/null +++ b/test/extra/cordova.spec.ts @@ -0,0 +1,40 @@ +/** + * @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 + */ +describe('cordova test', () => { + it('cordova.exec() should be patched as macroTask', (done) => { + const cordova = (window as any).cordova; + if (!cordova) { + done(); + return; + } + + const zone = Zone.current.fork({name: 'cordova'}); + + zone.run(() => { + cordova.exec( + () => { + expect(Zone.current.name).toEqual('cordova'); + done(); + }, + () => { + fail('should not fail'); + }, + 'service', 'successAction', ['arg0', 'arg1']); + + cordova.exec( + () => { + fail('should not success'); + }, + () => { + expect(Zone.current.name).toEqual('cordova'); + done(); + }, + 'service', 'failAction', ['arg0', 'arg1']); + }); + }); +}); \ No newline at end of file diff --git a/test/node_entry_point.ts b/test/node_entry_point.ts index a30da33c7..0c54d2511 100644 --- a/test/node_entry_point.ts +++ b/test/node_entry_point.ts @@ -8,7 +8,7 @@ // Must be loaded before zone loads, so that zone can detect WTF. import './wtf_mock'; -import './custom_error'; +import './test_fake_polyfill'; // Setup tests for Zone without microtask support import '../lib/zone'; diff --git a/test/custom_error.ts b/test/test_fake_polyfill.ts similarity index 55% rename from test/custom_error.ts rename to test/test_fake_polyfill.ts index d5dc968e7..87ed43f3e 100644 --- a/test/custom_error.ts +++ b/test/test_fake_polyfill.ts @@ -8,7 +8,22 @@ 'use strict'; (function(global: any) { + // add custom properties to Native Error const NativeError = global['Error']; NativeError.customProperty = 'customProperty'; NativeError.customFunction = function() {}; + + // add fake cordova polyfill for test + const fakeCordova = function() {}; + + (fakeCordova as any).exec = function( + success: Function, error: Function, service: string, action: string, args: any[]) { + if (action === 'successAction') { + success(); + } else { + error(); + } + }; + + global.cordova = fakeCordova; })(typeof window === 'object' && window || typeof self === 'object' && self || global); From 7bd1418974e5517b9cb2a5517cd7899a70f7d252 Mon Sep 17 00:00:00 2001 From: JiaLiPassion Date: Tue, 6 Jun 2017 03:30:25 +0900 Subject: [PATCH 5/7] fix(xhr): inner onreadystatechange should not triigger Zone callback (#800) fix https://github.com/angular/angular/issues/17167, zone.js will patch xhr, and add onreadystatechange internally, this onreadystatechange just for invoke the xhr MacroTask, so it should not trigger ZoneSpec's callback. in this commit, use original native addEventListener/removeEventListener to add internal onreadystatechange event listener. --- lib/browser/browser.ts | 7 +++-- test/browser/XMLHttpRequest.spec.ts | 40 +++++++++++++++++++++++----- test/test-util.ts | 11 ++++++++ test/zone-spec/task-tracking.spec.ts | 6 ++++- 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/lib/browser/browser.ts b/lib/browser/browser.ts index 63f045df0..397295953 100644 --- a/lib/browser/browser.ts +++ b/lib/browser/browser.ts @@ -91,8 +91,11 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType, api: _ZonePrivate) => { const data = task.data; // remove existing event listener const listener = data.target[XHR_LISTENER]; + const oriAddListener = data.target[zoneSymbol('addEventListener')]; + const oriRemoveListener = data.target[zoneSymbol('removeEventListener')]; + if (listener) { - data.target.removeEventListener('readystatechange', listener); + oriRemoveListener.apply(data.target, ['readystatechange', listener]); } const newListener = data.target[XHR_LISTENER] = () => { if (data.target.readyState === data.target.DONE) { @@ -104,7 +107,7 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType, api: _ZonePrivate) => { } } }; - data.target.addEventListener('readystatechange', newListener); + oriAddListener.apply(data.target, ['readystatechange', newListener]); const storedTask: Task = data.target[XHR_TASK]; if (!storedTask) { diff --git a/test/browser/XMLHttpRequest.spec.ts b/test/browser/XMLHttpRequest.spec.ts index 67df6d7c1..41f5d62c9 100644 --- a/test/browser/XMLHttpRequest.spec.ts +++ b/test/browser/XMLHttpRequest.spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ifEnvSupports} from '../test-util'; +import {ifEnvSupports, supportPatchXHROnProperty} from '../test-util'; describe('XMLHttpRequest', function() { let testZone: Zone; @@ -26,14 +26,14 @@ describe('XMLHttpRequest', function() { // The last entry in the log should be the invocation for the current onload, // which will vary depending on browser environment. The prior entries // should be the invocation of the send macrotask. - expect(wtfMock.log[wtfMock.log.length - 5]) - .toMatch(/\> Zone\:invokeTask.*addEventListener\:readystatechange/); - expect(wtfMock.log[wtfMock.log.length - 4]) - .toEqual('> Zone:invokeTask:XMLHttpRequest.send("::ProxyZone::WTF::TestZone")'); expect(wtfMock.log[wtfMock.log.length - 3]) - .toEqual('< Zone:invokeTask:XMLHttpRequest.send'); + .toEqual('> Zone:invokeTask:XMLHttpRequest.send("::ProxyZone::WTF::TestZone")'); expect(wtfMock.log[wtfMock.log.length - 2]) - .toMatch(/\< Zone\:invokeTask.*addEventListener\:readystatechange/); + .toEqual('< Zone:invokeTask:XMLHttpRequest.send'); + if (supportPatchXHROnProperty()) { + expect(wtfMock.log[wtfMock.log.length - 1]) + .toMatch(/\> Zone\:invokeTask.*addEventListener\:load/); + } done(); }; @@ -44,6 +44,32 @@ describe('XMLHttpRequest', function() { }, null, null, 'unit-test'); }); + it('should not trigger Zone callback of internal onreadystatechange', function(done) { + const scheduleSpy = jasmine.createSpy('schedule'); + const xhrZone = Zone.current.fork({ + name: 'xhr', + onScheduleTask: (delegate: ZoneDelegate, currentZone: Zone, targetZone, task: Task) => { + if (task.type === 'eventTask') { + scheduleSpy(task.source); + } + return delegate.scheduleTask(targetZone, task); + } + }); + + xhrZone.run(() => { + const req = new XMLHttpRequest(); + req.onload = function() { + expect(Zone.current.name).toEqual('xhr'); + if (supportPatchXHROnProperty()) { + expect(scheduleSpy).toHaveBeenCalled(); + } + done(); + }; + req.open('get', '/', true); + req.send(); + }); + }); + it('should work with onreadystatechange', function(done) { let req: XMLHttpRequest; diff --git a/test/test-util.ts b/test/test-util.ts index 5ff204eb8..180c350f1 100644 --- a/test/test-util.ts +++ b/test/test-util.ts @@ -57,3 +57,14 @@ function _runTest(test: any, block: Function, done: Function) { }); } } + +export function supportPatchXHROnProperty() { + let desc = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'onload'); + if (!desc && (window as any)['XMLHttpRequestEventTarget']) { + desc = Object.getOwnPropertyDescriptor(global['XMLHttpRequestEventTarget'].prototype, 'onload'); + } + if (!desc || !desc.configurable) { + return false; + } + return true; +} \ No newline at end of file diff --git a/test/zone-spec/task-tracking.spec.ts b/test/zone-spec/task-tracking.spec.ts index 27c1d6c5c..fb4aae36b 100644 --- a/test/zone-spec/task-tracking.spec.ts +++ b/test/zone-spec/task-tracking.spec.ts @@ -8,6 +8,8 @@ import '../../lib/zone-spec/task-tracking'; +import {supportPatchXHROnProperty} from '../test-util'; + declare const global: any; describe('TaskTrackingZone', function() { @@ -47,7 +49,9 @@ describe('TaskTrackingZone', function() { setTimeout(() => { expect(taskTrackingZoneSpec.macroTasks.length).toBe(0); expect(taskTrackingZoneSpec.microTasks.length).toBe(0); - expect(taskTrackingZoneSpec.eventTasks.length).not.toBe(0); + if (supportPatchXHROnProperty()) { + expect(taskTrackingZoneSpec.eventTasks.length).not.toBe(0); + } taskTrackingZoneSpec.clearEvents(); expect(taskTrackingZoneSpec.eventTasks.length).toBe(0); done(); From 68aa03ef74e20c4c9f560de73467f091f7a66c72 Mon Sep 17 00:00:00 2001 From: JiaLiPassion Date: Thu, 8 Jun 2017 07:06:58 +0900 Subject: [PATCH 6/7] fix(toString): fix #802, fix ios 9 MutationObserver toString error (#803) --- lib/common/to-string.ts | 9 +++++++-- test/common/toString.spec.ts | 12 ++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/common/to-string.ts b/lib/common/to-string.ts index 12c75320d..ac3fab2e6 100644 --- a/lib/common/to-string.ts +++ b/lib/common/to-string.ts @@ -14,8 +14,13 @@ Zone.__load_patch('toString', (global: any, Zone: ZoneType, api: _ZonePrivate) = const originalFunctionToString = Function.prototype.toString; Function.prototype.toString = function() { if (typeof this === 'function') { - if (this[zoneSymbol('OriginalDelegate')]) { - return originalFunctionToString.apply(this[zoneSymbol('OriginalDelegate')], arguments); + const originalDelegate = this[zoneSymbol('OriginalDelegate')]; + if (originalDelegate) { + if (typeof originalDelegate === 'function') { + return originalFunctionToString.apply(this[zoneSymbol('OriginalDelegate')], arguments); + } else { + return Object.prototype.toString.call(originalDelegate); + } } if (this === Promise) { const nativePromise = global[zoneSymbol('Promise')]; diff --git a/test/common/toString.spec.ts b/test/common/toString.spec.ts index ae96ad266..48e7474f0 100644 --- a/test/common/toString.spec.ts +++ b/test/common/toString.spec.ts @@ -17,6 +17,18 @@ describe('global function patch', () => { expect(Function.prototype.toString.call(setTimeout)) .toEqual(Function.prototype.toString.call(g[zoneSymbol('setTimeout')])); }); + + it('MutationObserver toString should be the same with native version', + ifEnvSupports('MutationObserver', () => { + const nativeMutationObserver = g[zoneSymbol('MutationObserver')]; + if (typeof nativeMutationObserver === 'function') { + expect(Function.prototype.toString.call(g['MutationObserver'])) + .toEqual(Function.prototype.toString.call(nativeMutationObserver)); + } else { + expect(Function.prototype.toString.call(g['MutationObserver'])) + .toEqual(Object.prototype.toString.call(nativeMutationObserver)); + } + })); }); describe('isNative', () => { From 351115926ca2c00029130641e822faba5571f165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C5=A1ko=20Hevery?= Date: Wed, 7 Jun 2017 15:16:10 -0700 Subject: [PATCH 7/7] chore: release v0.8.12 --- CHANGELOG.md | 19 ++++++++++++ dist/webapis-media-query.js | 2 +- dist/webapis-media-query.min.js | 2 +- dist/webapis-notification.js | 2 +- dist/webapis-notification.min.js | 2 +- dist/zone-mix.js | 29 +++++++++++++++--- dist/zone-node.js | 13 ++++++-- dist/zone-patch-cordova.js | 35 +++++++++++++++++++++ dist/zone-patch-cordova.min.js | 1 + dist/zone.js | 52 ++++++++++++++++++++++++++++---- dist/zone.min.js | 4 +-- package.json | 2 +- 12 files changed, 142 insertions(+), 21 deletions(-) create mode 100644 dist/zone-patch-cordova.js create mode 100644 dist/zone-patch-cordova.min.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 891c67bb2..e5ba1a624 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ + +## [0.8.12](https://github.com/angular/zone.js/compare/v0.8.11...0.8.12) (2017-06-07) + + +### Bug Fixes + +* **doc:** fix [#793](https://github.com/angular/zone.js/issues/793), fix confuseing bluebird patch doc ([#794](https://github.com/angular/zone.js/issues/794)) ([0c5da04](https://github.com/angular/zone.js/commit/0c5da04)) +* **patch:** fix [#791](https://github.com/angular/zone.js/issues/791), fix mediaQuery/Notification patch uses wrong global ([#792](https://github.com/angular/zone.js/issues/792)) ([67634ae](https://github.com/angular/zone.js/commit/67634ae)) +* **toString:** fix [#802](https://github.com/angular/zone.js/issues/802), fix ios 9 MutationObserver toString error ([#803](https://github.com/angular/zone.js/issues/803)) ([68aa03e](https://github.com/angular/zone.js/commit/68aa03e)) +* **xhr:** inner onreadystatechange should not triigger Zone callback ([#800](https://github.com/angular/zone.js/issues/800)) ([7bd1418](https://github.com/angular/zone.js/commit/7bd1418)) + + +### Features + +* **patch:** fix [#696](https://github.com/angular/zone.js/issues/696), patch HTMLCanvasElement.toBlob as MacroTask ([#788](https://github.com/angular/zone.js/issues/788)) ([7ca3995](https://github.com/angular/zone.js/commit/7ca3995)) +* **patch:** fix [#758](https://github.com/angular/zone.js/issues/758), patch cordova.exec success/error with zone.wrap ([#789](https://github.com/angular/zone.js/issues/789)) ([857929d](https://github.com/angular/zone.js/commit/857929d)) + + + ## [0.8.11](https://github.com/angular/zone.js/compare/v0.8.10...0.8.11) (2017-05-19) diff --git a/dist/webapis-media-query.js b/dist/webapis-media-query.js index 5b51f9fe9..1b4ac8f92 100644 --- a/dist/webapis-media-query.js +++ b/dist/webapis-media-query.js @@ -22,7 +22,7 @@ Zone.__load_patch('mediaQuery', function (global, Zone, api) { if (!global['MediaQueryList']) { return; } - api.patchEventTargetMethods(_global['MediaQueryList'].prototype, 'addListener', 'removeListener', function (self, args) { + api.patchEventTargetMethods(global['MediaQueryList'].prototype, 'addListener', 'removeListener', function (self, args) { return { useCapturing: false, eventName: 'mediaQuery', diff --git a/dist/webapis-media-query.min.js b/dist/webapis-media-query.min.js index 993afd1ba..728cb07a9 100644 --- a/dist/webapis-media-query.min.js +++ b/dist/webapis-media-query.min.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t():"function"==typeof define&&define.amd?define(t):t()}(this,function(){"use strict";Zone.__load_patch("mediaQuery",function(e,t,n){e.MediaQueryList&&n.patchEventTargetMethods(_global.MediaQueryList.prototype,"addListener","removeListener",function(t,n){return{useCapturing:!1,eventName:"mediaQuery",handler:n[0],target:t||e,name:"mediaQuery",invokeAddFunc:function(e,t){return t&&t.invoke?this.target[e](t.invoke):this.target[e](t)},invokeRemoveFunc:function(e,t){return t&&t.invoke?this.target[e](t.invoke):this.target[e](t)}}})})}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t():"function"==typeof define&&define.amd?define(t):t()}(this,function(){"use strict";Zone.__load_patch("mediaQuery",function(e,t,n){e.MediaQueryList&&n.patchEventTargetMethods(e.MediaQueryList.prototype,"addListener","removeListener",function(t,n){return{useCapturing:!1,eventName:"mediaQuery",handler:n[0],target:t||e,name:"mediaQuery",invokeAddFunc:function(e,t){return t&&t.invoke?this.target[e](t.invoke):this.target[e](t)},invokeRemoveFunc:function(e,t){return t&&t.invoke?this.target[e](t.invoke):this.target[e](t)}}})})}); \ No newline at end of file diff --git a/dist/webapis-notification.js b/dist/webapis-notification.js index b466819ba..476d1f929 100644 --- a/dist/webapis-notification.js +++ b/dist/webapis-notification.js @@ -19,7 +19,7 @@ * found in the LICENSE file at https://angular.io/license */ Zone.__load_patch('notification', function (global, Zone, api) { - var Notification = _global['Notification']; + var Notification = global['Notification']; if (!Notification || !Notification.prototype) { return; } diff --git a/dist/webapis-notification.min.js b/dist/webapis-notification.min.js index 48f15a6b6..cf8cdf11b 100644 --- a/dist/webapis-notification.min.js +++ b/dist/webapis-notification.min.js @@ -1 +1 @@ -!function(o,t){"object"==typeof exports&&"undefined"!=typeof module?t():"function"==typeof define&&define.amd?define(t):t()}(this,function(){"use strict";Zone.__load_patch("notification",function(o,t,e){var n=_global.Notification;if(n&&n.prototype){var i=Object.getOwnPropertyDescriptor(n.prototype,"onerror");i&&i.configurable&&e.patchOnProperties(n.prototype,null)}})}); \ No newline at end of file +!function(t,o){"object"==typeof exports&&"undefined"!=typeof module?o():"function"==typeof define&&define.amd?define(o):o()}(this,function(){"use strict";Zone.__load_patch("notification",function(t,o,e){var n=t.Notification;if(n&&n.prototype){var i=Object.getOwnPropertyDescriptor(n.prototype,"onerror");i&&i.configurable&&e.patchOnProperties(n.prototype,null)}})}); \ No newline at end of file diff --git a/dist/zone-mix.js b/dist/zone-mix.js index 37541fbc2..d336e23c7 100644 --- a/dist/zone-mix.js +++ b/dist/zone-mix.js @@ -610,7 +610,8 @@ var Zone$1 = (function (global) { scheduleMicroTask: scheduleMicroTask, showUncaughtError: function () { return !Zone[__symbol__('ignoreConsoleErrorUncaughtError')]; }, patchEventTargetMethods: function () { return false; }, - patchOnProperties: noop + patchOnProperties: noop, + patchMethod: function () { return noop; } }; var _currentZoneFrame = { parent: null, zone: new Zone(null, null) }; var _currentTask = null; @@ -1556,8 +1557,14 @@ Zone.__load_patch('toString', function (global, Zone, api) { var originalFunctionToString = Function.prototype.toString; Function.prototype.toString = function () { if (typeof this === 'function') { - if (this[zoneSymbol('OriginalDelegate')]) { - return originalFunctionToString.apply(this[zoneSymbol('OriginalDelegate')], arguments); + var originalDelegate = this[zoneSymbol('OriginalDelegate')]; + if (originalDelegate) { + if (typeof originalDelegate === 'function') { + return originalFunctionToString.apply(this[zoneSymbol('OriginalDelegate')], arguments); + } + else { + return Object.prototype.toString.call(originalDelegate); + } } if (this === Promise) { var nativePromise = global[zoneSymbol('Promise')]; @@ -2278,6 +2285,15 @@ Zone.__load_patch('on_property', function (global, Zone, api) { propertyPatch(); registerElementPatch(global); }); +Zone.__load_patch('canvas', function (global, Zone, api) { + var HTMLCanvasElement = global['HTMLCanvasElement']; + if (typeof HTMLCanvasElement !== 'undefined' && HTMLCanvasElement.prototype && + HTMLCanvasElement.prototype.toBlob) { + patchMacroTask(HTMLCanvasElement.prototype, 'toBlob', function (self, args) { + return { name: 'HTMLCanvasElement.toBlob', target: self, callbackIndex: 0, args: args }; + }); + } +}); Zone.__load_patch('XHR', function (global, Zone, api) { // Treat XMLHTTPRequest as a macrotask. patchXHR(global); @@ -2295,8 +2311,10 @@ Zone.__load_patch('XHR', function (global, Zone, api) { var data = task.data; // remove existing event listener var listener = data.target[XHR_LISTENER]; + var oriAddListener = data.target[zoneSymbol('addEventListener')]; + var oriRemoveListener = data.target[zoneSymbol('removeEventListener')]; if (listener) { - data.target.removeEventListener('readystatechange', listener); + oriRemoveListener.apply(data.target, ['readystatechange', listener]); } var newListener = data.target[XHR_LISTENER] = function () { if (data.target.readyState === data.target.DONE) { @@ -2308,7 +2326,7 @@ Zone.__load_patch('XHR', function (global, Zone, api) { } } }; - data.target.addEventListener('readystatechange', newListener); + oriAddListener.apply(data.target, ['readystatechange', newListener]); var storedTask = data.target[XHR_TASK]; if (!storedTask) { data.target[XHR_TASK] = task; @@ -2390,6 +2408,7 @@ Zone.__load_patch('PromiseRejectionEvent', function (global, Zone, api) { Zone.__load_patch('util', function (global, Zone, api) { api.patchEventTargetMethods = patchEventTargetMethods; api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; }); /** diff --git a/dist/zone-node.js b/dist/zone-node.js index 594c51ece..741df771c 100644 --- a/dist/zone-node.js +++ b/dist/zone-node.js @@ -610,7 +610,8 @@ var Zone$1 = (function (global) { scheduleMicroTask: scheduleMicroTask, showUncaughtError: function () { return !Zone[__symbol__('ignoreConsoleErrorUncaughtError')]; }, patchEventTargetMethods: function () { return false; }, - patchOnProperties: noop + patchOnProperties: noop, + patchMethod: function () { return noop; } }; var _currentZoneFrame = { parent: null, zone: new Zone(null, null) }; var _currentTask = null; @@ -1342,8 +1343,14 @@ Zone.__load_patch('toString', function (global, Zone, api) { var originalFunctionToString = Function.prototype.toString; Function.prototype.toString = function () { if (typeof this === 'function') { - if (this[zoneSymbol('OriginalDelegate')]) { - return originalFunctionToString.apply(this[zoneSymbol('OriginalDelegate')], arguments); + var originalDelegate = this[zoneSymbol('OriginalDelegate')]; + if (originalDelegate) { + if (typeof originalDelegate === 'function') { + return originalFunctionToString.apply(this[zoneSymbol('OriginalDelegate')], arguments); + } + else { + return Object.prototype.toString.call(originalDelegate); + } } if (this === Promise) { var nativePromise = global[zoneSymbol('Promise')]; diff --git a/dist/zone-patch-cordova.js b/dist/zone-patch-cordova.js new file mode 100644 index 000000000..2f7dcbbed --- /dev/null +++ b/dist/zone-patch-cordova.js @@ -0,0 +1,35 @@ +/** +* @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 +*/ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); +}(this, (function () { 'use strict'; + +/** + * @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('cordova', function (global, Zone, api) { + if (global.cordova) { + var nativeExec_1 = api.patchMethod(global.cordova, 'exec', function (delegate) { return function (self, args) { + if (args.length > 0 && typeof args[0] === 'function') { + args[0] = Zone.current.wrap(args[0], 'cordova.exec.success'); + } + if (args.length > 1 && typeof args[1] === 'function') { + args[1] = Zone.current.wrap(args[1], 'cordova.exec.error'); + } + return nativeExec_1.apply(self, args); + }; }); + } +}); + +}))); diff --git a/dist/zone-patch-cordova.min.js b/dist/zone-patch-cordova.min.js new file mode 100644 index 000000000..a7c794185 --- /dev/null +++ b/dist/zone-patch-cordova.min.js @@ -0,0 +1 @@ +!function(e,o){"object"==typeof exports&&"undefined"!=typeof module?o():"function"==typeof define&&define.amd?define(o):o()}(this,function(){"use strict";Zone.__load_patch("cordova",function(e,o,n){if(e.cordova)var t=n.patchMethod(e.cordova,"exec",function(e){return function(e,n){return n.length>0&&"function"==typeof n[0]&&(n[0]=o.current.wrap(n[0],"cordova.exec.success")),n.length>1&&"function"==typeof n[1]&&(n[1]=o.current.wrap(n[1],"cordova.exec.error")),t.apply(e,n)}})})}); \ No newline at end of file diff --git a/dist/zone.js b/dist/zone.js index 91cc928f6..f7719b6f2 100644 --- a/dist/zone.js +++ b/dist/zone.js @@ -610,7 +610,8 @@ var Zone$1 = (function (global) { scheduleMicroTask: scheduleMicroTask, showUncaughtError: function () { return !Zone[__symbol__('ignoreConsoleErrorUncaughtError')]; }, patchEventTargetMethods: function () { return false; }, - patchOnProperties: noop + patchOnProperties: noop, + patchMethod: function () { return noop; } }; var _currentZoneFrame = { parent: null, zone: new Zone(null, null) }; var _currentTask = null; @@ -1429,7 +1430,28 @@ function patchMethod(target, name, patchFn) { return delegate; } // TODO: @JiaLiPassion, support cancel task later if necessary - +function patchMacroTask(obj, funcName, metaCreator) { + var setNative = null; + function scheduleTask(task) { + var data = task.data; + data.args[data.callbackIndex] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, function (delegate) { return function (self, args) { + var meta = metaCreator(self, args); + if (meta.callbackIndex >= 0 && typeof args[meta.callbackIndex] === 'function') { + var task = Zone.current.scheduleMacroTask(meta.name, args[meta.callbackIndex], meta, scheduleTask, null); + return task; + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }; }); +} function findEventTask(target, evtName) { var eventTasks = target[zoneSymbol('eventTasks')]; @@ -1464,8 +1486,14 @@ Zone.__load_patch('toString', function (global, Zone, api) { var originalFunctionToString = Function.prototype.toString; Function.prototype.toString = function () { if (typeof this === 'function') { - if (this[zoneSymbol('OriginalDelegate')]) { - return originalFunctionToString.apply(this[zoneSymbol('OriginalDelegate')], arguments); + var originalDelegate = this[zoneSymbol('OriginalDelegate')]; + if (originalDelegate) { + if (typeof originalDelegate === 'function') { + return originalFunctionToString.apply(this[zoneSymbol('OriginalDelegate')], arguments); + } + else { + return Object.prototype.toString.call(originalDelegate); + } } if (this === Promise) { var nativePromise = global[zoneSymbol('Promise')]; @@ -2186,6 +2214,15 @@ Zone.__load_patch('on_property', function (global, Zone, api) { propertyPatch(); registerElementPatch(global); }); +Zone.__load_patch('canvas', function (global, Zone, api) { + var HTMLCanvasElement = global['HTMLCanvasElement']; + if (typeof HTMLCanvasElement !== 'undefined' && HTMLCanvasElement.prototype && + HTMLCanvasElement.prototype.toBlob) { + patchMacroTask(HTMLCanvasElement.prototype, 'toBlob', function (self, args) { + return { name: 'HTMLCanvasElement.toBlob', target: self, callbackIndex: 0, args: args }; + }); + } +}); Zone.__load_patch('XHR', function (global, Zone, api) { // Treat XMLHTTPRequest as a macrotask. patchXHR(global); @@ -2203,8 +2240,10 @@ Zone.__load_patch('XHR', function (global, Zone, api) { var data = task.data; // remove existing event listener var listener = data.target[XHR_LISTENER]; + var oriAddListener = data.target[zoneSymbol('addEventListener')]; + var oriRemoveListener = data.target[zoneSymbol('removeEventListener')]; if (listener) { - data.target.removeEventListener('readystatechange', listener); + oriRemoveListener.apply(data.target, ['readystatechange', listener]); } var newListener = data.target[XHR_LISTENER] = function () { if (data.target.readyState === data.target.DONE) { @@ -2216,7 +2255,7 @@ Zone.__load_patch('XHR', function (global, Zone, api) { } } }; - data.target.addEventListener('readystatechange', newListener); + oriAddListener.apply(data.target, ['readystatechange', newListener]); var storedTask = data.target[XHR_TASK]; if (!storedTask) { data.target[XHR_TASK] = task; @@ -2298,6 +2337,7 @@ Zone.__load_patch('PromiseRejectionEvent', function (global, Zone, api) { Zone.__load_patch('util', function (global, Zone, api) { api.patchEventTargetMethods = patchEventTargetMethods; api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; }); /** diff --git a/dist/zone.min.js b/dist/zone.min.js index 52f5e47f4..d1fa5c608 100644 --- a/dist/zone.min.js +++ b/dist/zone.min.js @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t():"function"==typeof define&&define.amd?define(t):t()}(this,function(){"use strict";function e(e,t){for(var n=e.length-1;n>=0;n--)"function"==typeof e[n]&&(e[n]=Zone.current.wrap(e[n],t+"_"+n));return e}function t(t,n){for(var r=t.constructor.name,o=function(o){var a=n[o],i=t[a];i&&(t[a]=function(t){var n=function(){return t.apply(this,e(arguments,r+"."+a))};return f(n,t),n}(i))},a=0;a1?new t(e,n):new t(e),i=Object.getOwnPropertyDescriptor(a,"onmessage");return i&&i.configurable===!1?(o=Object.create(a),["addEventListener","removeEventListener","send","close"].forEach(function(e){o[e]=function(){return a[e].apply(a,arguments)}})):o=a,r(o,["close","error","message","open"]),o};for(var n in t)e.WebSocket[n]=t[n]}function T(e){if(!O||j){var t="undefined"!=typeof WebSocket;if(w()){if(P){r(window,ae,Object.getPrototypeOf(window)),r(Document.prototype,ae),"undefined"!=typeof window.SVGElement&&r(window.SVGElement.prototype,ae),r(Element.prototype,ae),r(HTMLElement.prototype,ae),r(HTMLMediaElement.prototype,V),r(HTMLFrameSetElement.prototype,U.concat(ee)),r(HTMLBodyElement.prototype,U.concat(ee)),r(HTMLFrameElement.prototype,$),r(HTMLIFrameElement.prototype,$);var n=window.HTMLMarqueeElement;n&&r(n.prototype,te)}r(XMLHttpRequest.prototype,ne);var o=e.XMLHttpRequestEventTarget;o&&r(o&&o.prototype,ne),"undefined"!=typeof IDBIndex&&(r(IDBIndex.prototype,re),r(IDBRequest.prototype,re),r(IDBOpenDBRequest.prototype,re),r(IDBDatabase.prototype,re),r(IDBTransaction.prototype,re),r(IDBCursor.prototype,re)),t&&r(WebSocket.prototype,oe)}else E(),l("XMLHttpRequest"),t&&b(e)}}function w(){if((P||j)&&!Object.getOwnPropertyDescriptor(HTMLElement.prototype,"onclick")&&"undefined"!=typeof Element){var e=Object.getOwnPropertyDescriptor(Element.prototype,"onclick");if(e&&!e.configurable)return!1}var t=Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype,"onreadystatechange");if(t){Object.defineProperty(XMLHttpRequest.prototype,"onreadystatechange",{enumerable:!0,configurable:!0,get:function(){return!0}});var n=new XMLHttpRequest,r=!!n.onreadystatechange;return Object.defineProperty(XMLHttpRequest.prototype,"onreadystatechange",t||{}),r}Object.defineProperty(XMLHttpRequest.prototype,"onreadystatechange",{enumerable:!0,configurable:!0,get:function(){return this[Z("fakeonreadystatechange")]},set:function(e){this[Z("fakeonreadystatechange")]=e}});var n=new XMLHttpRequest,o=function(){};n.onreadystatechange=o;var r=n[Z("fakeonreadystatechange")]===o;return n.onreadystatechange=null,r}function E(){for(var e=function(e){var t=ae[e],n="on"+t;self.addEventListener(t,function(e){var t,r,o=e.target;for(r=o?o.constructor.name+"."+n:"unknown."+n;o;)o[n]&&!o[n][ie]&&(t=Zone.current.wrap(o[n],r),t[ie]=o[n],o[n]=t),o=o.parentElement},!0)},t=0;t",this._properties=t&&t.properties||{},this._zoneDelegate=new l(this,this._parent&&this._parent._zoneDelegate,t)}return r.assertZonePatched=function(){if(e.Promise!==z.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")},Object.defineProperty(r,"root",{get:function(){for(var e=r.current;e.parent;)e=e.parent;return e},enumerable:!0,configurable:!0}),Object.defineProperty(r,"current",{get:function(){return O.zone},enumerable:!0,configurable:!0}),Object.defineProperty(r,"currentTask",{get:function(){return P},enumerable:!0,configurable:!0}),r.__load_patch=function(o,a){if(z.hasOwnProperty(o))throw Error("Already loaded patch: "+o);if(!e["__Zone_disable_"+o]){var i="Zone:"+o;t(i),z[o]=a(e,r,S),n(i,i)}},Object.defineProperty(r.prototype,"parent",{get:function(){return this._parent},enumerable:!0,configurable:!0}),Object.defineProperty(r.prototype,"name",{get:function(){return this._name},enumerable:!0,configurable:!0}),r.prototype.get=function(e){var t=this.getZoneWith(e);if(t)return t._properties[e]},r.prototype.getZoneWith=function(e){for(var t=this;t;){if(t._properties.hasOwnProperty(e))return t;t=t._parent}return null},r.prototype.fork=function(e){if(!e)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,e)},r.prototype.wrap=function(e,t){if("function"!=typeof e)throw new Error("Expecting function got: "+e);var n=this._zoneDelegate.intercept(this,e,t),r=this;return function(){return r.runGuarded(n,this,arguments,t)}},r.prototype.run=function(e,t,n,r){void 0===t&&(t=void 0),void 0===n&&(n=null),void 0===r&&(r=null),O={parent:O,zone:this};try{return this._zoneDelegate.invoke(this,e,t,n,r)}finally{O=O.parent}},r.prototype.runGuarded=function(e,t,n,r){void 0===t&&(t=null),void 0===n&&(n=null),void 0===r&&(r=null),O={parent:O,zone:this};try{try{return this._zoneDelegate.invoke(this,e,t,n,r)}catch(o){if(this._zoneDelegate.handleError(this,o))throw o}}finally{O=O.parent}},r.prototype.runTask=function(e,t,n){if(e.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(e.zone||y).name+"; Execution: "+this.name+")");var r=e.state===k;if(!r||e.type!==Z){var o=e.state!=b;o&&e._transitionTo(b,_),e.runCount++;var a=P;P=e,O={parent:O,zone:this};try{e.type==D&&e.data&&!e.data.isPeriodic&&(e.cancelFn=null);try{return this._zoneDelegate.invokeTask(this,e,t,n)}catch(i){if(this._zoneDelegate.handleError(this,i))throw i}}finally{e.state!==k&&e.state!==w&&(e.type==Z||e.data&&e.data.isPeriodic?o&&e._transitionTo(_,b):(e.runCount=0,this._updateTaskCount(e,-1),o&&e._transitionTo(k,b,k))),O=O.parent,P=a}}},r.prototype.scheduleTask=function(e){if(e.zone&&e.zone!==this)for(var t=this;t;){if(t===e.zone)throw Error("can not reschedule task to "+this.name+" which is descendants of the original zone "+e.zone.name);t=t.parent}e._transitionTo(m,k);var n=[];e._zoneDelegates=n,e._zone=this;try{e=this._zoneDelegate.scheduleTask(this,e)}catch(r){throw e._transitionTo(w,m,k),this._zoneDelegate.handleError(this,r),r}return e._zoneDelegates===n&&this._updateTaskCount(e,1),e.state==m&&e._transitionTo(_,m),e},r.prototype.scheduleMicroTask=function(e,t,n,r){return this.scheduleTask(new p(E,e,t,n,r,null))},r.prototype.scheduleMacroTask=function(e,t,n,r,o){return this.scheduleTask(new p(D,e,t,n,r,o))},r.prototype.scheduleEventTask=function(e,t,n,r,o){return this.scheduleTask(new p(Z,e,t,n,r,o))},r.prototype.cancelTask=function(e){if(e.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(e.zone||y).name+"; Execution: "+this.name+")");e._transitionTo(T,_,b);try{this._zoneDelegate.cancelTask(this,e)}catch(t){throw e._transitionTo(w,T),this._zoneDelegate.handleError(this,t),t}return this._updateTaskCount(e,-1),e._transitionTo(k,T),e.runCount=0,e},r.prototype._updateTaskCount=function(e,t){var n=e._zoneDelegates;t==-1&&(e._zoneDelegates=null);for(var r=0;r0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:e};this.hasTask(this.zone,a)}},e}(),p=function(){function e(e,t,n,r,a,i){this._zone=null,this.runCount=0,this._zoneDelegates=null,this._state="notScheduled",this.type=e,this.source=t,this.data=r,this.scheduleFn=a,this.cancelFn=i,this.callback=n;var s=this;this.invoke=function(){j++;try{return s.runCount++,s.zone.runTask(s,this,arguments)}finally{1==j&&o(),j--}}}return Object.defineProperty(e.prototype,"zone",{get:function(){return this._zone},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"state",{get:function(){return this._state},enumerable:!0,configurable:!0}),e.prototype.cancelScheduleRequest=function(){this._transitionTo(k,m)},e.prototype._transitionTo=function(e,t,n){if(this._state!==t&&this._state!==n)throw new Error(this.type+" '"+this.source+"': can not transition to '"+e+"', expecting state '"+t+"'"+(n?" or '"+n+"'":"")+", was '"+this._state+"'.");this._state=e,e==k&&(this._zoneDelegates=null)},e.prototype.toString=function(){return this.data&&"undefined"!=typeof this.data.handleId?this.data.handleId:Object.prototype.toString.call(this)},e.prototype.toJSON=function(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,invoke:this.invoke,scheduleFn:this.scheduleFn,cancelFn:this.cancelFn,runCount:this.runCount,callback:this.callback}},e}(),h=i("setTimeout"),f=i("Promise"),d=i("then"),v=[],g=!1,y={name:"NO ZONE"},k="notScheduled",m="scheduling",_="scheduled",b="running",T="canceling",w="unknown",E="microTask",D="macroTask",Z="eventTask",z={},S={symbol:i,currentZoneFrame:function(){return O},onUnhandledError:a,microtaskDrainDone:a,scheduleMicroTask:r,showUncaughtError:function(){return!c[i("ignoreConsoleErrorUncaughtError")]},patchEventTargetMethods:function(){return!1},patchOnProperties:a},O={parent:null,zone:new c(null,null)},P=null,j=0;return n("Zone","Zone"),e.Zone=c})("undefined"!=typeof window&&window||"undefined"!=typeof self&&self||global);Zone.__load_patch("ZoneAwarePromise",function(e,t,n){function r(e){n.onUnhandledError(e);try{var r=t[f("unhandledPromiseRejectionHandler")];r&&"function"==typeof r&&r.apply(this,[e])}catch(o){}}function o(e){return e&&e.then}function a(e){return e}function i(e){return D.reject(e)}function s(e,t){return function(n){try{c(e,t,n)}catch(r){c(e,!1,r)}}}function c(e,r,o){var a=E();if(e===o)throw new TypeError("Promise resolved with itself");if(e[y]===_){var i=null;try{"object"!=typeof o&&"function"!=typeof o||(i=o&&o.then)}catch(p){return a(function(){c(e,!1,p)})(),e}if(r!==T&&o instanceof D&&o.hasOwnProperty(y)&&o.hasOwnProperty(k)&&o[y]!==_)u(o),c(e,o[y],o[k]);else if(r!==T&&"function"==typeof i)try{i.apply(o,[a(s(e,r)),a(s(e,!1))])}catch(p){a(function(){c(e,!1,p)})()}else{e[y]=r;var h=e[k];e[k]=o,r===T&&o instanceof Error&&(o[f("currentTask")]=t.currentTask);for(var v=0;v=0;n--)"function"==typeof e[n]&&(e[n]=Zone.current.wrap(e[n],t+"_"+n));return e}function t(t,n){for(var r=t.constructor.name,o=function(o){var a=n[o],i=t[a];i&&(t[a]=function(t){var n=function(){return t.apply(this,e(arguments,r+"."+a))};return d(n,t),n}(i))},a=0;a=0&&"function"==typeof o[a.callbackIndex]){var i=Zone.current.scheduleMacroTask(a.name,o[a.callbackIndex],a,r,null);return i}return e.apply(t,o)}})}function f(e,t){var n=e[S("eventTasks")],r=[];if(n)for(var o=0;o1?new t(e,n):new t(e),i=Object.getOwnPropertyDescriptor(a,"onmessage");return i&&i.configurable===!1?(o=Object.create(a),["addEventListener","removeEventListener","send","close"].forEach(function(e){o[e]=function(){return a[e].apply(a,arguments)}})):o=a,r(o,["close","error","message","open"]),o};for(var n in t)e.WebSocket[n]=t[n]}function w(e){if(!P||C){var t="undefined"!=typeof WebSocket;if(E()){if(j){r(window,ie,Object.getPrototypeOf(window)),r(Document.prototype,ie),"undefined"!=typeof window.SVGElement&&r(window.SVGElement.prototype,ie),r(Element.prototype,ie),r(HTMLElement.prototype,ie),r(HTMLMediaElement.prototype,K),r(HTMLFrameSetElement.prototype,G.concat(te)),r(HTMLBodyElement.prototype,G.concat(te)),r(HTMLFrameElement.prototype,ee),r(HTMLIFrameElement.prototype,ee);var n=window.HTMLMarqueeElement;n&&r(n.prototype,ne)}r(XMLHttpRequest.prototype,re);var o=e.XMLHttpRequestEventTarget;o&&r(o&&o.prototype,re),"undefined"!=typeof IDBIndex&&(r(IDBIndex.prototype,oe),r(IDBRequest.prototype,oe),r(IDBOpenDBRequest.prototype,oe),r(IDBDatabase.prototype,oe),r(IDBTransaction.prototype,oe),r(IDBCursor.prototype,oe)),t&&r(WebSocket.prototype,ae)}else Z(),l("XMLHttpRequest"),t&&T(e)}}function E(){if((j||C)&&!Object.getOwnPropertyDescriptor(HTMLElement.prototype,"onclick")&&"undefined"!=typeof Element){var e=Object.getOwnPropertyDescriptor(Element.prototype,"onclick");if(e&&!e.configurable)return!1}var t=Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype,"onreadystatechange");if(t){Object.defineProperty(XMLHttpRequest.prototype,"onreadystatechange",{enumerable:!0,configurable:!0,get:function(){return!0}});var n=new XMLHttpRequest,r=!!n.onreadystatechange;return Object.defineProperty(XMLHttpRequest.prototype,"onreadystatechange",t||{}),r}Object.defineProperty(XMLHttpRequest.prototype,"onreadystatechange",{enumerable:!0,configurable:!0,get:function(){return this[S("fakeonreadystatechange")]},set:function(e){this[S("fakeonreadystatechange")]=e}});var n=new XMLHttpRequest,o=function(){};n.onreadystatechange=o;var r=n[S("fakeonreadystatechange")]===o;return n.onreadystatechange=null,r}function Z(){for(var e=function(e){var t=ie[e],n="on"+t;self.addEventListener(t,function(e){var t,r,o=e.target;for(r=o?o.constructor.name+"."+n:"unknown."+n;o;)o[n]&&!o[n][se]&&(t=Zone.current.wrap(o[n],r),t[se]=o[n],o[n]=t),o=o.parentElement},!0)},t=0;t",this._properties=t&&t.properties||{},this._zoneDelegate=new l(this,this._parent&&this._parent._zoneDelegate,t)}return r.assertZonePatched=function(){if(e.Promise!==S.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")},Object.defineProperty(r,"root",{get:function(){for(var e=r.current;e.parent;)e=e.parent;return e},enumerable:!0,configurable:!0}),Object.defineProperty(r,"current",{get:function(){return O.zone},enumerable:!0,configurable:!0}),Object.defineProperty(r,"currentTask",{get:function(){return P},enumerable:!0,configurable:!0}),r.__load_patch=function(o,a){if(S.hasOwnProperty(o))throw Error("Already loaded patch: "+o);if(!e["__Zone_disable_"+o]){var i="Zone:"+o;t(i),S[o]=a(e,r,z),n(i,i)}},Object.defineProperty(r.prototype,"parent",{get:function(){return this._parent},enumerable:!0,configurable:!0}),Object.defineProperty(r.prototype,"name",{get:function(){return this._name},enumerable:!0,configurable:!0}),r.prototype.get=function(e){var t=this.getZoneWith(e);if(t)return t._properties[e]},r.prototype.getZoneWith=function(e){for(var t=this;t;){if(t._properties.hasOwnProperty(e))return t;t=t._parent}return null},r.prototype.fork=function(e){if(!e)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,e)},r.prototype.wrap=function(e,t){if("function"!=typeof e)throw new Error("Expecting function got: "+e);var n=this._zoneDelegate.intercept(this,e,t),r=this;return function(){return r.runGuarded(n,this,arguments,t)}},r.prototype.run=function(e,t,n,r){void 0===t&&(t=void 0),void 0===n&&(n=null),void 0===r&&(r=null),O={parent:O,zone:this};try{return this._zoneDelegate.invoke(this,e,t,n,r)}finally{O=O.parent}},r.prototype.runGuarded=function(e,t,n,r){void 0===t&&(t=null),void 0===n&&(n=null),void 0===r&&(r=null),O={parent:O,zone:this};try{try{return this._zoneDelegate.invoke(this,e,t,n,r)}catch(o){if(this._zoneDelegate.handleError(this,o))throw o}}finally{O=O.parent}},r.prototype.runTask=function(e,t,n){if(e.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(e.zone||y).name+"; Execution: "+this.name+")");var r=e.state===k;if(!r||e.type!==D){var o=e.state!=_;o&&e._transitionTo(_,b),e.runCount++;var a=P;P=e,O={parent:O,zone:this};try{e.type==Z&&e.data&&!e.data.isPeriodic&&(e.cancelFn=null);try{return this._zoneDelegate.invokeTask(this,e,t,n)}catch(i){if(this._zoneDelegate.handleError(this,i))throw i}}finally{e.state!==k&&e.state!==w&&(e.type==D||e.data&&e.data.isPeriodic?o&&e._transitionTo(b,_):(e.runCount=0,this._updateTaskCount(e,-1),o&&e._transitionTo(k,_,k))),O=O.parent,P=a}}},r.prototype.scheduleTask=function(e){if(e.zone&&e.zone!==this)for(var t=this;t;){if(t===e.zone)throw Error("can not reschedule task to "+this.name+" which is descendants of the original zone "+e.zone.name);t=t.parent}e._transitionTo(m,k);var n=[];e._zoneDelegates=n,e._zone=this;try{e=this._zoneDelegate.scheduleTask(this,e)}catch(r){throw e._transitionTo(w,m,k),this._zoneDelegate.handleError(this,r),r}return e._zoneDelegates===n&&this._updateTaskCount(e,1),e.state==m&&e._transitionTo(b,m),e},r.prototype.scheduleMicroTask=function(e,t,n,r){return this.scheduleTask(new p(E,e,t,n,r,null))},r.prototype.scheduleMacroTask=function(e,t,n,r,o){return this.scheduleTask(new p(Z,e,t,n,r,o))},r.prototype.scheduleEventTask=function(e,t,n,r,o){return this.scheduleTask(new p(D,e,t,n,r,o))},r.prototype.cancelTask=function(e){if(e.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(e.zone||y).name+"; Execution: "+this.name+")");e._transitionTo(T,b,_);try{this._zoneDelegate.cancelTask(this,e)}catch(t){throw e._transitionTo(w,T),this._zoneDelegate.handleError(this,t),t}return this._updateTaskCount(e,-1),e._transitionTo(k,T),e.runCount=0,e},r.prototype._updateTaskCount=function(e,t){var n=e._zoneDelegates;t==-1&&(e._zoneDelegates=null);for(var r=0;r0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:e};this.hasTask(this.zone,a)}},e}(),p=function(){function e(e,t,n,r,a,i){this._zone=null,this.runCount=0,this._zoneDelegates=null,this._state="notScheduled",this.type=e,this.source=t,this.data=r,this.scheduleFn=a,this.cancelFn=i,this.callback=n;var s=this;this.invoke=function(){j++;try{return s.runCount++,s.zone.runTask(s,this,arguments)}finally{1==j&&o(),j--}}}return Object.defineProperty(e.prototype,"zone",{get:function(){return this._zone},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"state",{get:function(){return this._state},enumerable:!0,configurable:!0}),e.prototype.cancelScheduleRequest=function(){this._transitionTo(k,m)},e.prototype._transitionTo=function(e,t,n){if(this._state!==t&&this._state!==n)throw new Error(this.type+" '"+this.source+"': can not transition to '"+e+"', expecting state '"+t+"'"+(n?" or '"+n+"'":"")+", was '"+this._state+"'.");this._state=e,e==k&&(this._zoneDelegates=null)},e.prototype.toString=function(){return this.data&&"undefined"!=typeof this.data.handleId?this.data.handleId:Object.prototype.toString.call(this)},e.prototype.toJSON=function(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,invoke:this.invoke,scheduleFn:this.scheduleFn,cancelFn:this.cancelFn,runCount:this.runCount,callback:this.callback}},e}(),h=i("setTimeout"),f=i("Promise"),d=i("then"),v=[],g=!1,y={name:"NO ZONE"},k="notScheduled",m="scheduling",b="scheduled",_="running",T="canceling",w="unknown",E="microTask",Z="macroTask",D="eventTask",S={},z={symbol:i,currentZoneFrame:function(){return O},onUnhandledError:a,microtaskDrainDone:a,scheduleMicroTask:r,showUncaughtError:function(){return!c[i("ignoreConsoleErrorUncaughtError")]},patchEventTargetMethods:function(){return!1},patchOnProperties:a,patchMethod:function(){return a}},O={parent:null,zone:new c(null,null)},P=null,j=0;return n("Zone","Zone"),e.Zone=c})("undefined"!=typeof window&&window||"undefined"!=typeof self&&self||global);Zone.__load_patch("ZoneAwarePromise",function(e,t,n){function r(e){n.onUnhandledError(e);try{var r=t[f("unhandledPromiseRejectionHandler")];r&&"function"==typeof r&&r.apply(this,[e])}catch(o){}}function o(e){return e&&e.then}function a(e){return e}function i(e){return Z.reject(e)}function s(e,t){return function(n){try{c(e,t,n)}catch(r){c(e,!1,r)}}}function c(e,r,o){var a=E();if(e===o)throw new TypeError("Promise resolved with itself");if(e[y]===b){var i=null;try{"object"!=typeof o&&"function"!=typeof o||(i=o&&o.then)}catch(p){return a(function(){c(e,!1,p)})(),e}if(r!==T&&o instanceof Z&&o.hasOwnProperty(y)&&o.hasOwnProperty(k)&&o[y]!==b)u(o),c(e,o[y],o[k]);else if(r!==T&&"function"==typeof i)try{i.apply(o,[a(s(e,r)),a(s(e,!1))])}catch(p){a(function(){c(e,!1,p)})()}else{e[y]=r;var h=e[k];e[k]=o,r===T&&o instanceof Error&&(o[f("currentTask")]=t.currentTask);for(var v=0;v