Add new lazily unload criteria .

This commit is contained in:
Dermot Duffy
2022-05-03 22:30:43 -07:00
parent 328a1088b8
commit 26b7bbbb9e
7 changed files with 105 additions and 51 deletions
+51 -36
View File
@@ -1,16 +1,18 @@
import { EmblaCarouselType, EmblaEventType, EmblaPluginType } from 'embla-carousel';
import { LazyUnloadCondition } from '../../types';
export type LazyloadOptionsType = {
// Number of slides to lazyload left/right of selected (0 == only selected
// slide).
lazyloadCount?: number;
lazyLoadCount?: number;
lazyUnloadCondition?: LazyUnloadCondition;
lazyloadCallback?: (index: number, slide: HTMLElement) => void;
lazyunloadCallback?: (index: number, slide: HTMLElement) => void;
lazyLoadCallback?: (index: number, slide: HTMLElement) => void;
lazyUnloadCallback?: (index: number, slide: HTMLElement) => void;
};
export const defaultOptions: Partial<LazyloadOptionsType> = {
lazyloadCount: 0,
lazyLoadCount: 0,
};
export type LazyloadType = EmblaPluginType<LazyloadOptionsType> & {
@@ -22,7 +24,7 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType {
let carousel: EmblaCarouselType;
let slides: HTMLElement[];
const isSlideLazyloaded: Record<number, boolean> = {};
const lazyLoadedSlides: Set<number> = new Set();
const loadEvents: EmblaEventType[] = ['init', 'select', 'resize'];
const unloadEvents: EmblaEventType[] = ['select'];
@@ -34,11 +36,15 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType {
carousel = embla;
slides = carousel.slideNodes();
if (options.lazyloadCallback) {
loadEvents.forEach((evt) => carousel.on(evt, lazyloadHandler));
if (options.lazyLoadCallback) {
loadEvents.forEach((evt) => carousel.on(evt, lazyLoadHandler));
}
if (options.lazyunloadCallback) {
unloadEvents.forEach((evt) => carousel.on(evt, lazyunloadHandler));
if (
options.lazyUnloadCallback &&
options.lazyUnloadCondition &&
['all', 'unselected'].includes(options.lazyUnloadCondition)
) {
unloadEvents.forEach((evt) => carousel.on(evt, lazyUnloadPreviousHandler));
}
document.addEventListener('visibilitychange', visibilityHandler);
}
@@ -47,11 +53,11 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType {
* Destroy the plugin.
*/
function destroy(): void {
if (options.lazyloadCallback) {
loadEvents.forEach((evt) => carousel.off(evt, lazyloadHandler));
if (options.lazyLoadCallback) {
loadEvents.forEach((evt) => carousel.off(evt, lazyLoadHandler));
}
if (options.lazyunloadCallback) {
unloadEvents.forEach((evt) => carousel.off(evt, lazyunloadHandler));
if (options.lazyUnloadCallback) {
unloadEvents.forEach((evt) => carousel.off(evt, lazyUnloadPreviousHandler));
}
document.removeEventListener('visibilitychange', visibilityHandler);
}
@@ -60,10 +66,15 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType {
* Handle document visibility changes.
*/
function visibilityHandler(): void {
if (document.visibilityState == 'hidden' && lazyunloadHandler) {
lazyunloadHandler();
} else if (document.visibilityState == 'visible' && lazyloadHandler) {
lazyloadHandler();
if (
document.visibilityState === 'hidden' &&
options.lazyUnloadCallback &&
options.lazyUnloadCondition &&
['all', 'hidden'].includes(options.lazyUnloadCondition)
) {
lazyUnloadAllHandler();
} else if (document.visibilityState === 'visible' && options.lazyLoadCallback) {
lazyLoadHandler();
}
}
@@ -73,14 +84,14 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType {
* @returns `true` if the slide has been lazily loaded.
*/
function hasLazyloaded(index: number): boolean {
return !!isSlideLazyloaded[index];
return lazyLoadedSlides.has(index);
}
/**
* Lazily load media in the carousel.
*/
function lazyloadHandler(): void {
const lazyLoadCount = options.lazyloadCount ?? 0;
function lazyLoadHandler(): void {
const lazyLoadCount = options.lazyLoadCount ?? 0;
const currentIndex = carousel.selectedScrollSnap();
const slidesToLoad = new Set<number>();
@@ -94,30 +105,34 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType {
}
slidesToLoad.forEach((index) => {
// Only lazy load slides that are not already loaded.
if (isSlideLazyloaded[index]) {
return;
}
if (options.lazyloadCallback) {
isSlideLazyloaded[index] = true;
options.lazyloadCallback(index, slides[index]);
if (!hasLazyloaded(index) && options.lazyLoadCallback) {
lazyLoadedSlides.add(index);
options.lazyLoadCallback(index, slides[index]);
}
});
}
/**
* Lazily unload media in the carousel.
* Lazily unload all media in the carousel.
*/
function lazyunloadHandler(): void {
function lazyUnloadAllHandler(): void {
lazyLoadedSlides.forEach((index) => {
if (options.lazyUnloadCallback) {
options.lazyUnloadCallback(index, slides[index]);
lazyLoadedSlides.delete(index);
}
});
}
/**
* Lazily unload the previously selected media in the carousel.
*/
function lazyUnloadPreviousHandler(): void {
const index = carousel.previousScrollSnap();
// Only lazy unload slides that are lazy loaded.
if (!isSlideLazyloaded[index]) {
return;
}
if (options.lazyunloadCallback) {
options.lazyunloadCallback(index, slides[index]);
isSlideLazyloaded[index] = false;
if (hasLazyloaded(index) && options.lazyUnloadCallback) {
options.lazyUnloadCallback(index, slides[index]);
lazyLoadedSlides.delete(index);
}
}
+13 -11
View File
@@ -288,12 +288,14 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
return [
...super._getPlugins(),
Lazyload({
lazyloadCallback: this.liveConfig?.lazy_load
? (...args) => this._lazyloadOrUnloadSlide('load', ...args)
: undefined,
lazyunloadCallback: this.liveConfig?.lazy_unload
? (...args) => this._lazyloadOrUnloadSlide('unload', ...args)
: undefined,
...(this.liveConfig?.lazy_load && {
lazyLoadCallback: (index, slide) =>
this._lazyloadOrUnloadSlide('load', index, slide),
}),
lazyUnloadCondition: this.liveConfig?.lazy_unload,
lazyUnloadCallback: (index, slide) =>
this._lazyloadOrUnloadSlide('unload', index, slide),
}),
AutoMediaPlugin({
playerSelector: 'frigate-card-live-provider',
@@ -380,7 +382,7 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
'frigate-card-live-provider',
) as FrigateCardLiveProvider;
if (liveProvider) {
liveProvider.disabled = action == 'load' ? false : true;
liveProvider.disabled = action !== 'load';
}
}
@@ -795,7 +797,7 @@ export class FrigateCardLiveWebRTCCard extends LitElement {
/**
* Create the WebRTC element. May throw.
*/
protected _createWebRTC(): HTMLElement | undefined {
protected _createWebRTC(): HTMLElement | null {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const webrtcElement = this._webrtcTask.value;
if (webrtcElement && this.hass) {
@@ -818,7 +820,7 @@ export class FrigateCardLiveWebRTCCard extends LitElement {
webrtc.hass = this.hass;
return webrtc;
}
return undefined;
return null;
}
/**
@@ -827,7 +829,7 @@ export class FrigateCardLiveWebRTCCard extends LitElement {
*/
protected render(): TemplateResult | void {
const render = (): TemplateResult | void => {
let webrtcElement: HTMLElement | undefined;
let webrtcElement: HTMLElement | null;
try {
webrtcElement = this._createWebRTC();
} catch (e) {
@@ -973,7 +975,7 @@ export class FrigateCardLiveJSMPEG extends LitElement {
canvas: this._jsmpegCanvasElement,
},
{
// The media carousel automatically pauses when the browser tab is
// The media carousel may automatically pause when the browser tab is
// inactive, JSMPEG does not need to also do so independently.
pauseWhenHidden: false,
protocols: [],