95 lines
2.8 KiB
TypeScript
95 lines
2.8 KiB
TypeScript
import { EmblaCarouselType } from 'embla-carousel';
|
|
import { LooseOptionsType } from 'embla-carousel/components/Options';
|
|
import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins';
|
|
import { MediaLoadedInfo } from '../../../../types';
|
|
import {
|
|
FrigateCardMediaLoadedEventTarget,
|
|
dispatchExistingMediaLoadedInfoAsEvent,
|
|
} from '../../../media-info';
|
|
|
|
declare module 'embla-carousel/components/Plugins' {
|
|
interface EmblaPluginsType {
|
|
autoMediaLoadedInfo?: AutoMediaLoadedInfoType;
|
|
}
|
|
}
|
|
|
|
type AutoMediaLoadedInfoType = CreatePluginType<LoosePluginType, LooseOptionsType>;
|
|
|
|
function AutoMediaLoadedInfo(): AutoMediaLoadedInfoType {
|
|
let emblaApi: EmblaCarouselType;
|
|
let slides: (HTMLElement & FrigateCardMediaLoadedEventTarget)[] = [];
|
|
const mediaLoadedInfo: MediaLoadedInfo[] = [];
|
|
|
|
function init(emblaApiInstance: EmblaCarouselType): void {
|
|
emblaApi = emblaApiInstance;
|
|
slides = emblaApi.slideNodes();
|
|
|
|
for (const slide of slides) {
|
|
slide.addEventListener('frigate-card:media:loaded', mediaLoadedInfoHandler);
|
|
slide.addEventListener('frigate-card:media:unloaded', mediaUnloadedInfoHandler);
|
|
}
|
|
|
|
emblaApi.on('init', slideSelectHandler);
|
|
emblaApi.on('select', slideSelectHandler);
|
|
}
|
|
|
|
function destroy(): void {
|
|
for (const slide of slides) {
|
|
slide.removeEventListener('frigate-card:media:loaded', mediaLoadedInfoHandler);
|
|
slide.removeEventListener('frigate-card:media:unloaded', mediaUnloadedInfoHandler);
|
|
}
|
|
|
|
emblaApi.off('init', slideSelectHandler);
|
|
emblaApi.off('select', slideSelectHandler);
|
|
}
|
|
|
|
function mediaLoadedInfoHandler(ev: CustomEvent<MediaLoadedInfo>): void {
|
|
const eventPath = ev.composedPath();
|
|
|
|
for (const [index, slide] of slides.entries()) {
|
|
if (eventPath.includes(slide)) {
|
|
mediaLoadedInfo[index] = ev.detail;
|
|
if (index !== emblaApi.selectedScrollSnap()) {
|
|
ev.stopPropagation();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
function mediaUnloadedInfoHandler(ev: CustomEvent): void {
|
|
const eventPath = ev.composedPath();
|
|
|
|
for (const [index, slide] of slides.entries()) {
|
|
if (eventPath.includes(slide)) {
|
|
delete mediaLoadedInfo[index];
|
|
if (index !== emblaApi.selectedScrollSnap()) {
|
|
ev.stopPropagation();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
function slideSelectHandler(): void {
|
|
const index = emblaApi.selectedScrollSnap();
|
|
const savedMediaLoadedInfo: MediaLoadedInfo | undefined = mediaLoadedInfo[index];
|
|
if (savedMediaLoadedInfo) {
|
|
dispatchExistingMediaLoadedInfoAsEvent(
|
|
emblaApi.containerNode(),
|
|
savedMediaLoadedInfo,
|
|
);
|
|
}
|
|
}
|
|
|
|
const self: AutoMediaLoadedInfoType = {
|
|
name: 'autoMediaLoadedInfo',
|
|
options: {},
|
|
init,
|
|
destroy,
|
|
};
|
|
return self;
|
|
}
|
|
|
|
export default AutoMediaLoadedInfo;
|