diff --git a/NON-STANDARD-APIS.md b/NON-STANDARD-APIS.md index 6e6f6dbb7..c3c9676cb 100644 --- a/NON-STANDARD-APIS.md +++ b/NON-STANDARD-APIS.md @@ -67,6 +67,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 745910db4..42ae9937a 100644 --- a/lib/browser/browser.ts +++ b/lib/browser/browser.ts @@ -193,4 +193,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);