@ribajs/bs5
Version:
Bootstrap 5 module for Riba.js
131 lines (109 loc) • 3.59 kB
text/typescript
import { Component, TemplateFunction } from "@ribajs/core";
import { Bs5SliderComponent } from "../bs5-slider/bs5-slider.component.js";
import { VideoComponent } from "@ribajs/extras/src/components/index.js";
import type { ScrollEvent } from "@ribajs/extras";
interface Scope {
/** Set to true to play the video automatically when the slide is active */
autoplay: boolean;
}
/**
* A slide with a video, used to play the video when the slide is active
*/
export class Bs5SlideVideoComponent extends Component {
public static tagName = "bs5-slide-video";
public scope: Scope = {
autoplay: false,
};
slider: Bs5SliderComponent | null = null;
videoCo: VideoComponent | null = null;
videoEl: HTMLVideoElement | null = null;
slideEl: HTMLElement | null = null;
static get observedAttributes(): string[] {
return ["autoplay"];
}
protected connectedCallback() {
super.connectedCallback();
this.init(Bs5SlideVideoComponent.observedAttributes);
this.onSlideEnd = this.onSlideEnd.bind(this);
}
protected onSlideEnd(event: ScrollEvent) {
this.debug(
"[Bs5SlideVideoComponent] onSlideEnd",
event,
this.slideEl?.classList,
);
if (this.scope.autoplay) {
this.playIfActive();
}
}
protected playIfActive() {
if (this.slideEl?.classList.contains("active")) {
if (this.videoCo) {
this.videoCo.play();
} else if (this.videoEl) {
this.videoEl.play();
}
}
}
async waitForUserInteraction() {
return new Promise((resolve) => {
const removeEventListeners = () => {
document.removeEventListener("click", clickHandler);
document.removeEventListener("scroll", scrollHandler);
document.removeEventListener("mousemove", mouseMoveHandler);
};
const clickHandler = () => {
removeEventListeners();
resolve("click");
};
const scrollHandler = () => {
removeEventListeners();
resolve("scroll");
};
const mouseMoveHandler = () => {
removeEventListeners();
resolve("mousemove");
};
document.addEventListener("click", clickHandler);
document.addEventListener("scroll", scrollHandler);
document.addEventListener("mousemove", mouseMoveHandler);
});
}
protected addEventListeners() {
this.slider?.addEventListener(
Bs5SliderComponent.EVENTS.scrollended,
this.onSlideEnd as EventListener,
);
}
protected removeEventListeners() {
this.slider?.removeEventListener(
Bs5SliderComponent.EVENTS.scrollended,
this.onSlideEnd as EventListener,
);
}
protected async beforeBind(): Promise<void> {
await super.beforeBind();
this.addEventListeners();
}
protected async afterBind(): Promise<void> {
if (this.scope.autoplay) {
if (this.slideEl?.classList.contains("active")) {
const event = await this.waitForUserInteraction();
console.debug("[Bs5SlideVideoComponent] event", event);
if (this.slideEl?.classList.contains("active")) {
this.playIfActive();
}
}
}
await super.beforeBind();
}
protected async beforeTemplate(): Promise<void> {
this.slider = this.closest<Bs5SliderComponent>(Bs5SliderComponent.tagName);
this.videoCo = this.querySelector<VideoComponent>(VideoComponent.tagName);
this.videoEl = this.querySelector<HTMLVideoElement>("video");
this.slideEl = this.closest<HTMLElement>(".slide");
}
protected template(): ReturnType<TemplateFunction> {
return null;
}
}