Skip to content

Instantly share code, notes, and snippets.

@marioloncarek
Created June 25, 2021 12:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marioloncarek/076712aa281000d5a79122ad9119bb18 to your computer and use it in GitHub Desktop.
Save marioloncarek/076712aa281000d5a79122ad9119bb18 to your computer and use it in GitHub Desktop.
import CustomVideoPlayer from "./CustomVideoPlayer";
/**
* Custom video playlist using CustomVideoPlayer.js
*/
export default class VideoPlaylist {
constructor() {
/**
* Video playlist DOM elements and states
* @type {{currentDescription: string, currentTitle: string, videoPlaylist: string, videoDurationEl: string, playlistItem: string, video: string, timeInput: string, videoPlayer: string, videoProgressBarEl: string, states: {paused: string, playing: string}}}
*/
this.DOM = {
videoPlaylist: ".js-video-playlist",
video: ".js-custom-video-player-media",
videoPlayer: ".js-custom-video-player",
playlistItem: ".js-video-playlist-item",
currentTitle: ".js-video-playlist-current-title",
currentDescription: ".js-video-playlist-current-description",
videoProgressBarEl: ".js-custom-video-player-progress-bar",
videoDurationEl: ".js-custom-video-player-video-duration",
timeInput: ".js-custom-video-player-time-input",
states: {
playing: "is-playing",
paused: "is-paused",
active: "is-active",
},
};
/**
* Fetch All Video Playlist component DOM elements
* @type {NodeListOf<Element>}
*/
this.videoPlaylist = document.querySelectorAll(this.DOM.videoPlaylist);
}
/**
* Init
* Init CustomVideoPlayer
* CustomVideoPlayer has internal checks for non existing elements
*/
init() {
if (this.videoPlaylist.length < 1) {
return;
}
this.initPlaylist();
/**
* Custom video player
* @type {CustomVideoPlayer}
*/
this.customVideoPlayer = new CustomVideoPlayer();
this.customVideoPlayer.init();
}
/**
* Loop thru all playlist elements and find all instance items
* Init video element with first instance items props
* Init events to listen for the new video request
*/
initPlaylist() {
for (let i = 0; i < this.videoPlaylist.length; i++) {
const video = this.videoPlaylist[i].querySelector(this.DOM.video);
const playlistItem = this.videoPlaylist[i].querySelectorAll(
this.DOM.playlistItem,
);
const currentTitle = this.videoPlaylist[i].querySelector(
this.DOM.currentTitle,
);
const currentDescription = this.videoPlaylist[i].querySelector(
this.DOM.currentDescription,
);
if (
video === null ||
currentTitle === null ||
currentDescription === null ||
playlistItem.length < 1
) {
return;
}
playlistItem[0].classList.add(this.DOM.states.active);
video.src = playlistItem[0].dataset.videoUrl;
video.poster = playlistItem[0].dataset.videoPoster;
currentTitle.innerHTML = playlistItem[0].dataset.videoTitle;
currentDescription.innerHTML =
playlistItem[0].dataset.videoDescription;
this.initVideoItemsEvents(
playlistItem,
video,
currentTitle,
currentDescription,
this.videoPlaylist[i],
);
}
}
/**
* Watch for clicks on playlist items and play new video
* When clicked, video pauses and video time is reset to start
* Play method is triggered
* All video data is provided from data attributes
* @param elements
* @param video
* @param currentTitle
* @param currentDescription
* @param currentInstance
*/
initVideoItemsEvents(
elements,
video,
currentTitle,
currentDescription,
currentInstance,
) {
for (let i = 0; i < elements.length; i++) {
elements[i].addEventListener("click", (event) => {
event.preventDefault();
if (
!event.currentTarget.classList.contains(
this.DOM.states.active,
)
) {
currentInstance
.querySelector(`.${this.DOM.states.active}`)
.classList.remove(this.DOM.states.active);
elements[i].classList.add(this.DOM.states.active);
video.pause();
video.currentTime = 0;
this.playVideo(
video,
currentTitle,
currentDescription,
event.currentTarget.dataset.videoUrl,
event.currentTarget.dataset.videoPoster,
event.currentTarget.dataset.videoTitle,
event.currentTarget.dataset.videoDescription,
currentInstance,
);
}
});
}
}
/**
* Set and remove right classes needed for CustomVideoPlayer to pause
* Reset video
* Set all new video props
* Trigger loading of the new video
* Apply new meta
* @param video
* @param currentTitle
* @param currentDescription
* @param source
* @param poster
* @param title
* @param description
* @param currentInstance
*/
playVideo(
video,
currentTitle,
currentDescription,
source,
poster,
title,
description,
currentInstance,
) {
let videoPlayer = currentInstance.querySelector(this.DOM.videoPlayer);
let timeInput = currentInstance.querySelector(this.DOM.timeInput);
let videoProgressBarEl = currentInstance.querySelector(
this.DOM.videoProgressBarEl,
);
let videoDurationEl = currentInstance.querySelector(
this.DOM.videoDurationEl,
);
videoPlayer.classList.remove(this.DOM.states.playing);
videoPlayer.classList.add(this.DOM.states.paused);
video.src = source;
video.poster = poster;
currentTitle.innerHTML = title;
currentDescription.innerHTML = description;
video.load();
this.awaitNewVideo(
video,
timeInput,
videoProgressBarEl,
videoDurationEl,
);
}
/**
* Waits for video meta to be loaded and change CustomVideoPlayer HTML
* to match new video
* @param video
* @param timeInput
* @param videoProgressBarEl
* @param videoDurationEl
*/
awaitNewVideo(video, timeInput, videoProgressBarEl, videoDurationEl) {
if (!isNaN(video.duration)) {
timeInput.setAttribute("max", video.duration);
videoProgressBarEl.setAttribute("max", video.duration);
let time = this.customVideoPlayer.formatTime(video.duration);
videoDurationEl.innerText = `${time.minutes}:${time.seconds}`;
} else {
setTimeout(() => {
this.awaitNewVideo(
video,
timeInput,
videoProgressBarEl,
videoDurationEl,
);
}, 10);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment