From 2fa2ac80361cd0625a87a3e786c31ef283ed8c7d Mon Sep 17 00:00:00 2001 From: Daniel Wiehl Date: Fri, 26 Jul 2019 11:02:48 +0200 Subject: [PATCH] feat: control if to use native resize observable unless explicitly specified via options object The injection token {USE_NATIVE_RESIZE_OBSERVER} can be provided to control if to use native resize observable by default. The flag has no effect if not supported by the user agent, or if explicitly specified via options object when creating the resize observable. fixes: #156 --- .../dimension/src/lib/dimension.module.ts | 3 +++ .../dimension/src/lib/dimension.service.ts | 23 ++++++++++++++++--- projects/scion/dimension/src/public_api.ts | 2 +- .../src/lib/spec/workbench-testing.module.ts | 9 ++++++++ 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/projects/scion/dimension/src/lib/dimension.module.ts b/projects/scion/dimension/src/lib/dimension.module.ts index 123e62e0b..1308bea4a 100644 --- a/projects/scion/dimension/src/lib/dimension.module.ts +++ b/projects/scion/dimension/src/lib/dimension.module.ts @@ -19,6 +19,9 @@ import { SciDimensionDirective } from './dimension.directive'; * Web Performance Working Group is working on a W3C recommendation for natively observing changes to Element’s size. * The Web API draft is still work in progress and support limited to Google Chrome and Opera. * + * You can control if to use the native {ResizeObserver} by default with {USE_NATIVE_RESIZE_OBSERVER} DI injection token. + * If not provided, the native resize observable is used, unless explicitly set via options object when creating the resize observable. + * * @see https://wicg.github.io/ResizeObserver/ * @see https://caniuse.com/#feat=resizeobserver */ diff --git a/projects/scion/dimension/src/lib/dimension.service.ts b/projects/scion/dimension/src/lib/dimension.service.ts index 333382b7e..cacb1f5be 100644 --- a/projects/scion/dimension/src/lib/dimension.service.ts +++ b/projects/scion/dimension/src/lib/dimension.service.ts @@ -10,10 +10,21 @@ import { concat, fromEvent, Observable, Observer, of, ReplaySubject, Subject, TeardownLogic } from 'rxjs'; import { map, multicast, refCount, switchMap, takeUntil, tap } from 'rxjs/operators'; -import { Injectable } from '@angular/core'; +import { Injectable, InjectionToken, Injector } from '@angular/core'; +/** + * CSS class added to the HTML element emitting resize events if not using the native {ResizeObserver}. + */ const SYNTH_RESIZE_OBSERVABLE_OBJECT_MARKER = 'synth-resize-observable'; +/** + * DI injection token to control if to use the native {ResizeObserver} by default. + * If not provided, the native resize observable is used, unless explicitly set via options object when creating the resize observable. + * + * This flag is only evaluated if the user agent supports {ResizeObserver}. + */ +export const USE_NATIVE_RESIZE_OBSERVER = new InjectionToken('USE_NATIVE_RESIZE_OBSERVER'); + /** * Allows observing the dimension of an element. * @@ -37,6 +48,9 @@ export class SciDimensionService { */ public _objectObservableRegistry = new Map>(); + constructor(private _injector: Injector) { + } + /** * Upon subscription, it emits the element's dimension, and then continuously emits when the dimension of the element changes. It never completes. * @@ -48,9 +62,12 @@ export class SciDimensionService { * By default, this flag is enabled. */ public dimension$(target: HTMLElement, options?: { useNativeResizeObserver: boolean }): Observable { - const useNativeResizeObserver = !options || options.useNativeResizeObserver === undefined || options.useNativeResizeObserver === true; + options = { + useNativeResizeObserver: this._injector.get(USE_NATIVE_RESIZE_OBSERVER, true), + ...options, + }; - if (useNativeResizeObserver && supportsNativeResizeObserver()) { + if (options.useNativeResizeObserver && supportsNativeResizeObserver()) { return createNativeResizeObservable$(target); } diff --git a/projects/scion/dimension/src/public_api.ts b/projects/scion/dimension/src/public_api.ts index 9a68ef84c..cbf97a239 100644 --- a/projects/scion/dimension/src/public_api.ts +++ b/projects/scion/dimension/src/public_api.ts @@ -14,4 +14,4 @@ export { SciDimensionModule } from './lib/dimension.module'; export { SciDimensionDirective } from './lib/dimension.directive'; export { SciMutationService } from './lib/mutation.service'; -export { SciDimensionService, SciDimension } from './lib/dimension.service'; +export { SciDimensionService, SciDimension, USE_NATIVE_RESIZE_OBSERVER } from './lib/dimension.service'; diff --git a/projects/scion/workbench/src/lib/spec/workbench-testing.module.ts b/projects/scion/workbench/src/lib/spec/workbench-testing.module.ts index 71e466586..c3a74d371 100644 --- a/projects/scion/workbench/src/lib/spec/workbench-testing.module.ts +++ b/projects/scion/workbench/src/lib/spec/workbench-testing.module.ts @@ -2,6 +2,7 @@ import { Injectable, ModuleWithProviders, NgModule } from '@angular/core'; import { ViewActivationInstantProvider } from '../view-activation-instant-provider.service'; import { WorkbenchModule } from '../workbench.module'; import { WorkbenchConfig } from '../workbench.config'; +import { USE_NATIVE_RESIZE_OBSERVER } from '@scion/dimension'; @Injectable() export class ViewActivationTestingInstantProvider implements ViewActivationInstantProvider { @@ -27,6 +28,14 @@ export class WorkbenchTestingModule { providers: [ WorkbenchModule.forRoot(config).providers, {provide: ViewActivationInstantProvider, useClass: ViewActivationTestingInstantProvider}, + /** + * Disable native `ResizeObserver` in tests because it sometimes throws 'loop limit exceeded' error which can safely be ignored. + * + * Comment from the specification authors: + * This error means that `ResizeObserver` was not able to deliver all observations within a single animation frame. It is benign and the site will not break. + * See https://stackoverflow.com/a/50387233 + */ + {provide: USE_NATIVE_RESIZE_OBSERVER, useValue: false}, ], }; }