From 168b9b0c908353c05032ec4c9ffda3fe9f906bf0 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 15 Apr 2025 17:10:18 +0100 Subject: [PATCH] fix: Fix issues with lazy loading and overridden configuration (#2012) - Closes #2011 --- src/components-lib/lazy-load-controller.ts | 17 +++--- src/components/live/provider.ts | 23 ++++---- src/components/viewer/provider.ts | 15 +++-- .../lazy-load-controller.test.ts | 55 +++++++++++-------- 4 files changed, 62 insertions(+), 48 deletions(-) diff --git a/src/components-lib/lazy-load-controller.ts b/src/components-lib/lazy-load-controller.ts index 2440b295..6bcaa3c5 100644 --- a/src/components-lib/lazy-load-controller.ts +++ b/src/components-lib/lazy-load-controller.ts @@ -7,22 +7,25 @@ export class LazyLoadController implements ReactiveController { private _host: ReactiveControllerHost & HTMLElement; private _documentVisible = true; private _intersects = false; - private _loaded: boolean; + private _loaded = false; private _unloadConditions: LazyUnloadCondition[] | null = null; private _intersectionObserver = new IntersectionObserver( this._intersectionHandler.bind(this), ); private _listeners: LazyLoadListener[] = []; - constructor( - host: ReactiveControllerHost & HTMLElement, + constructor(host: ReactiveControllerHost & HTMLElement) { + this._host = host; + this._host.addController(this); + } + + public setConfiguration( lazyLoad?: boolean, lazyUnloadConditions?: LazyUnloadCondition[], ) { - this._host = host; - this._host.addController(this); - - this._loaded = !lazyLoad; + if (!lazyLoad && !this._loaded) { + this._setLoaded(true); + } this._unloadConditions = lazyUnloadConditions ?? null; } diff --git a/src/components/live/provider.ts b/src/components/live/provider.ts index 9b958139..9c19dfb6 100644 --- a/src/components/live/provider.ts +++ b/src/components/live/provider.ts @@ -69,7 +69,7 @@ export class AdvancedCameraCardLiveProvider extends LitElement implements MediaP protected _showStreamTroubleshooting = false; protected _refProvider: Ref = createRef(); - protected _lazyLoadController: LazyLoadController | null = null; + protected _lazyLoadController: LazyLoadController = new LazyLoadController(this); // A note on dynamic imports: // @@ -83,6 +83,16 @@ export class AdvancedCameraCardLiveProvider extends LitElement implements MediaP // background. These calls fail without waiting for loading here. protected _importPromises: Promise[] = []; + constructor() { + super(); + this._lazyLoadController.addListener((loaded: boolean) => { + if (!loaded) { + this._isVideoMediaLoaded = false; + dispatchMediaUnloadedEvent(this); + } + }); + } + public async getMediaPlayerController(): Promise { await this.updateComplete; return (await this._refProvider.value?.getMediaPlayerController()) ?? null; @@ -145,19 +155,10 @@ export class AdvancedCameraCardLiveProvider extends LitElement implements MediaP changedProps.has('liveConfig') || (!this._lazyLoadController && this.liveConfig) ) { - this._lazyLoadController?.destroy(); - this._lazyLoadController?.removeController(); - this._lazyLoadController = new LazyLoadController( - this, + this._lazyLoadController.setConfiguration( this.liveConfig?.lazy_load, this.liveConfig?.lazy_unload, ); - this._lazyLoadController.addListener((loaded: boolean) => { - if (!loaded) { - this._isVideoMediaLoaded = false; - dispatchMediaUnloadedEvent(this); - } - }); } if (changedProps.has('liveConfig')) { diff --git a/src/components/viewer/provider.ts b/src/components/viewer/provider.ts index 1365fcf3..61aa4ae8 100644 --- a/src/components/viewer/provider.ts +++ b/src/components/viewer/provider.ts @@ -69,11 +69,16 @@ export class AdvancedCameraCardViewerProvider extends LitElement implements Medi public cardWideConfig?: CardWideConfig; protected _refProvider: Ref = createRef(); - protected _lazyLoadController: LazyLoadController | null = null; + protected _lazyLoadController: LazyLoadController = new LazyLoadController(this); @state() protected _url: string | null = null; + constructor() { + super(); + this._lazyLoadController.addListener((loaded) => loaded && this._setURL()); + } + public async getMediaPlayerController(): Promise { await this.updateComplete; return (await this._refProvider.value?.getMediaPlayerController()) ?? null; @@ -184,13 +189,7 @@ export class AdvancedCameraCardViewerProvider extends LitElement implements Medi changedProps.has('viewerConfig') || (!this._lazyLoadController && this.viewerConfig) ) { - this._lazyLoadController?.destroy(); - this._lazyLoadController?.removeController(); - this._lazyLoadController = new LazyLoadController( - this, - this.viewerConfig?.lazy_load, - ); - this._lazyLoadController.addListener((loaded) => loaded && this._setURL()); + this._lazyLoadController.setConfiguration(this.viewerConfig?.lazy_load); } if ( diff --git a/tests/components-lib/lazy-load-controller.test.ts b/tests/components-lib/lazy-load-controller.test.ts index 90bd924a..fc009552 100644 --- a/tests/components-lib/lazy-load-controller.test.ts +++ b/tests/components-lib/lazy-load-controller.test.ts @@ -37,13 +37,14 @@ describe('LazyLoadController', () => { vi.restoreAllMocks(); }); - it('should be loaded by default', () => { + it('should be unloaded by default', () => { const controller = new LazyLoadController(createLitElement()); - expect(controller.isLoaded()).toBe(true); + expect(controller.isLoaded()).toBe(false); }); it('should not be loaded by default when lazy load is set to true', () => { - const controller = new LazyLoadController(createLitElement(), true); + const controller = new LazyLoadController(createLitElement()); + controller.setConfiguration(true); expect(controller.isLoaded()).toBe(false); }); @@ -61,10 +62,8 @@ describe('LazyLoadController', () => { }); it('should remove handlers and listeners on destroy', () => { - const controller = new LazyLoadController(createLitElement(), true, [ - 'unselected', - 'hidden', - ]); + const controller = new LazyLoadController(createLitElement()); + controller.setConfiguration(true, ['unselected', 'hidden']); controller.hostConnected(); const listener = vi.fn(); @@ -84,9 +83,26 @@ describe('LazyLoadController', () => { expect(listener).not.toBeCalled(); }); + describe('should set configuration', () => { + it('should set loaded if lazy loading set to false', () => { + const listener = vi.fn(); + const controller = new LazyLoadController(createLitElement()); + controller.addListener(listener); + + expect(controller.isLoaded()).toBe(false); + expect(listener).not.toBeCalled(); + + controller.setConfiguration(false); + + expect(controller.isLoaded()).toBe(true); + expect(listener).toBeCalled(); + }); + }); + describe('should lazy load', () => { it('should load when both visible and intersecting', () => { - const controller = new LazyLoadController(createLitElement(), true); + const controller = new LazyLoadController(createLitElement()); + controller.setConfiguration(true); controller.hostConnected(); expect(controller.isLoaded()).toBe(false); @@ -102,6 +118,9 @@ describe('LazyLoadController', () => { describe('should lazy unload', () => { it('should unload on DOM disconnection', () => { const controller = new LazyLoadController(createLitElement()); + + // No lazy loading. + controller.setConfiguration(false); controller.hostConnected(); expect(controller.isLoaded()).toBe(true); @@ -127,11 +146,8 @@ describe('LazyLoadController', () => { ])( 'when unload conditions are: %s', (unloadConditions: LazyUnloadCondition[], shouldBeLoaded: boolean) => { - const controller = new LazyLoadController( - createLitElement(), - true, - unloadConditions, - ); + const controller = new LazyLoadController(createLitElement()); + controller.setConfiguration(true, unloadConditions); controller.hostConnected(); callIntersectionHandler(true); @@ -153,11 +169,8 @@ describe('LazyLoadController', () => { ])( 'when unload conditions are: %s', (unloadConditions: LazyUnloadCondition[], shouldBeLoaded: boolean) => { - const controller = new LazyLoadController( - createLitElement(), - true, - unloadConditions, - ); + const controller = new LazyLoadController(createLitElement()); + controller.setConfiguration(true, unloadConditions); controller.hostConnected(); callIntersectionHandler(true); @@ -173,10 +186,8 @@ describe('LazyLoadController', () => { it('should call listeners', () => { const listener = vi.fn(); - const controller = new LazyLoadController(createLitElement(), true, [ - 'unselected', - 'hidden', - ]); + const controller = new LazyLoadController(createLitElement()); + controller.setConfiguration(true, ['unselected', 'hidden']); controller.hostConnected(); controller.addListener(listener);