UNPKG

@splidejs/splide-extension-video

Version:
287 lines (249 loc) 7.13 kB
import { EVENT_DRAG, EVENT_DRAGGING, EVENT_MOUNTED, EVENT_MOVE, EVENT_MOVED, EVENT_SCROLL, EVENT_SCROLLED, EventInterface, EventInterfaceObject, Splide, } from '@splidejs/splide'; import { addClass, getAttribute, merge, toggleClass } from '@splidejs/splide/src/js/utils'; import { CLASS_ERROR, CLASS_PLAYING, CLASS_VIDEO_DISABLED } from '../constants/classes'; import { HTML_VIDEO__DATA_ATTRIBUTE, VIMEO_DATA_ATTRIBUTE, YOUTUBE_DATA_ATTRIBUTE } from '../constants/data-attributes'; import { DEFAULTS } from '../constants/defaults'; import { EVENT_VIDEO_CLICK, EVENT_VIDEO_ENDED, EVENT_VIDEO_ERROR, EVENT_VIDEO_PAUSE, EVENT_VIDEO_PLAY, } from '../constants/events'; import { HTMLVideoPlayer } from '../players/html/HTMLVideoPlayer'; import { VimeoPlayer } from '../players/vimeo/VimeoPlayer'; import { YouTubePlayer } from '../players/youtube/YouTubePlayer'; import { VideoPlayerConstructor, VideoPlayerInterface } from '../types/general'; import { VideoOptions } from '../types/options'; import { PlayerUI } from './PlayerUI'; /** * Associates the data attribute name with the player constructor. * * @since 0.5.0 */ const VIDEO_PLAYER_MAP: Array<[ string, VideoPlayerConstructor ]> = [ [ YOUTUBE_DATA_ATTRIBUTE, YouTubePlayer ], [ VIMEO_DATA_ATTRIBUTE, VimeoPlayer ], [ HTML_VIDEO__DATA_ATTRIBUTE, HTMLVideoPlayer ], ]; /** * The class for the video player that connects a Splide slide with PlayerUI and VideoPlayer instances. * * @since 0.5.0 */ export class Player { /** * The Splide instance. */ private readonly Splide: Splide; /** * The slide element. */ private readonly slide: HTMLElement; /** * Video options. */ private readonly options: VideoOptions; /** * The PlayerUI instance. */ private ui: PlayerUI; /** * The VideoPlayer instance. */ private player: VideoPlayerInterface; /** * The EventInterface object. */ private event: EventInterfaceObject; /** * Indicates whether the player is disabled or not. */ private disabled: boolean; /** * The Player constructor. * * @param Splide - A Splide instance. * @param slide - A slide element where the player is applied. */ constructor( Splide: Splide, slide: HTMLElement ) { this.Splide = Splide; this.slide = slide; this.event = EventInterface( Splide ); this.options = merge( merge( {}, DEFAULTS ), this.Splide.options.video ); this.createPlayer( slide ); if ( this.player ) { this.listen(); } } /** * Creates a Player. * This will fail when the slide element does not have the data attribute for the video. * * @param slide - A slide element. */ private createPlayer( slide: HTMLElement ): void { VIDEO_PLAYER_MAP.forEach( ( [ attr, Constructor ] ) => { const id = getAttribute( slide, attr ); if ( id ) { this.ui = new PlayerUI( this.Splide, slide ); this.player = new Constructor( this.ui.getPlaceholder(), id, this.options ); this.ui.disable( this.options.disableOverlayUI ); } } ); } /** * Listens to UI, VideoPlayer and Splide events. */ private listen(): void { const { player, event } = this; this.ui.on( 'click', this.onClick.bind( this ) ); player.on( 'play', this.onPlay.bind( this ) ); player.on( 'played', this.onPlayed.bind( this ) ); player.on( 'pause', this.onPause.bind( this ) ); player.on( 'paused', this.onPaused.bind( this ) ); player.on( 'ended', this.onEnded.bind( this ) ); player.on( 'error', this.onError.bind( this ) ); event.on( [ EVENT_MOVE, EVENT_SCROLL ], this.pause.bind( this ) ); event.on( EVENT_VIDEO_CLICK, this.onVideoClick.bind( this ) ); event.on( EVENT_DRAG, () => { event.off( EVENT_DRAGGING ); event.on( EVENT_DRAGGING, () => { this.pause(); event.off( EVENT_DRAGGING ); } ); } ); if ( this.options.autoplay ) { event.on( [ EVENT_MOUNTED, EVENT_MOVED, EVENT_SCROLLED ], this.onAutoplayRequested.bind( this ) ); } } /** * Called when the slide element is clicked. */ private onClick(): void { this.isPaused() ? this.play() : this.pause(); this.event.emit( EVENT_VIDEO_CLICK, this ); } /** * Called when any slides that have a video are clicked. * * @param player - A player instance that the clicked slide has. */ private onVideoClick( player: Player ): void { if ( this !== player ) { this.pause(); } } /** * Called when the video is requested to start. * The video may be loading at this moment. */ private onPlay(): void { this.ui.hide(); } /** * Called when the video begins. */ private onPlayed(): void { this.ui.hide(); this.togglePlaying( true ); this.event.emit( EVENT_VIDEO_PLAY, this ); } /** * Called when the video is requested to pause. */ private onPause(): void { this.ui.show(); } /** * Called when the video is paused. */ private onPaused(): void { this.togglePlaying( false ); this.event.emit( EVENT_VIDEO_PAUSE, this ); } /** * Called when the video ends. */ private onEnded(): void { this.togglePlaying( false ); this.event.emit( EVENT_VIDEO_ENDED, this ); } /** * Called when an error occurs. */ private onError(): void { addClass( this.slide, CLASS_ERROR ); this.ui.show(); this.event.emit( EVENT_VIDEO_ERROR, this ); } /** * Called when the autoplay option is `true` and the slider should start the video. */ private onAutoplayRequested(): void { const activeSlide = this.Splide.Components.Slides.getAt( this.Splide.index ); if ( activeSlide.slide === this.slide ) { this.play(); } } /** * Toggles the playing status class. * * @param add - Determines whether to add or remove the class. */ private togglePlaying( add: boolean ): void { toggleClass( this.Splide.root, CLASS_PLAYING, add ); } /** * Starts the video. */ play(): void { if ( this.player && ! this.disabled ) { this.player.play(); } } /** * Pauses the video. */ pause(): void { if ( this.player && ! this.disabled ) { this.player.pause(); } } /** * Destroys the instance. */ destroy(): void { if ( this.player ) { this.ui.destroy(); this.player.destroy(); } this.disable( false ); } /** * Disables the play/pause control. */ disable( disabled: boolean ): void { this.disabled = disabled; toggleClass( this.Splide.root, CLASS_VIDEO_DISABLED, disabled ); } /** * Checks if the video is paused or not. * * @return `true` if the video is paused. */ isPaused(): boolean { return this.player.isPaused(); } }