From cd6b95c49aa1409e1db98542885e7eff3cfdcb5c Mon Sep 17 00:00:00 2001 From: "JiaLi.Passion" Date: Sun, 4 Feb 2018 01:46:06 +0900 Subject: [PATCH] feat(patch): fix #1011, patch ResizeObserver --- NON-STANDARD-APIS.md | 14 +++- gulpfile.js | 10 +++ lib/browser/webapis-resize-observer.ts | 88 ++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 lib/browser/webapis-resize-observer.ts diff --git a/NON-STANDARD-APIS.md b/NON-STANDARD-APIS.md index 71826f7c5..d0825af2a 100644 --- a/NON-STANDARD-APIS.md +++ b/NON-STANDARD-APIS.md @@ -170,7 +170,7 @@ In electron, we patched the following APIs with `zone.js` ## Usage. -add/update following line into `polyfill.ts`. +add following line into `polyfill.ts` after loading zone-mix. ``` //import 'zone.js/dist/zone'; // originally added by angular-cli, comment it out @@ -194,7 +194,17 @@ user need to patch `io` themselves just like following code. ``` - please reference the sample repo [zone-socketio](https://github.com/JiaLiPassion/zone-socketio) about detail usage. +* ResizeObserver + +Currently only `Chrome 64` native support this feature. +you can add the following line into `polyfill.ts` after loading `zone.js`. + +``` +import 'zone.js/dist/zone'; +import 'zone.js/dist/zone-patch-resize-observer'; +``` + +there is a sample repo [zone-resize-observer](https://github.com/JiaLiPassion/zone-resize-observer) here diff --git a/gulpfile.js b/gulpfile.js index c79d1970e..47bbb9451 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -200,6 +200,14 @@ gulp.task('build/zone-patch-socket-io.min.js', ['compile-esm'], function(cb) { return generateScript('./lib/extra/socket-io.ts', 'zone-patch-socket-io.min.js', true, cb); }); +gulp.task('build/zone-patch-resize-observer.js', ['compile-esm'], function(cb) { + return generateScript('./lib/browser/webapis-resize-observer.ts', 'zone-patch-resize-observer.js', false, cb); +}); + +gulp.task('build/zone-patch-resize-observer.min.js', ['compile-esm'], function(cb) { + return generateScript('./lib/browser/webapis-resize-observer.ts', 'zone-patch-resize-observer.min.js', true, cb); +}); + gulp.task('build/bluebird.js', ['compile-esm'], function(cb) { return generateScript('./lib/extra/bluebird.ts', 'zone-bluebird.js', false, cb); }); @@ -307,6 +315,8 @@ gulp.task('build', [ 'build/zone-patch-user-media.min.js', 'build/zone-patch-socket-io.js', 'build/zone-patch-socket-io.min.js', + 'build/zone-patch-resize-observer.js', + 'build/zone-patch-resize-observer.min.js', 'build/zone-mix.js', 'build/bluebird.js', 'build/bluebird.min.js', diff --git a/lib/browser/webapis-resize-observer.ts b/lib/browser/webapis-resize-observer.ts new file mode 100644 index 000000000..cfaa70f0b --- /dev/null +++ b/lib/browser/webapis-resize-observer.ts @@ -0,0 +1,88 @@ +/** + * @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); + }); +});