UNPKG

@ebay/ebayui-core

Version:

Collection of core eBay components; considered to be the building blocks for all composite structures, pages & apps.

394 lines (393 loc) 14.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const shaka_player_1 = require("@internal/shaka-player"); const elements_1 = require("./elements"); const DEFAULT_SPINNER_TIMEOUT = 2000; const eventList = [ "abort", "canplay", "canplaythrough", "durationchange", "emptied", "encrypted", "ended", "error", "loadstart", "progress", "ratechange", "seeked", "seeking", "stalled", "suspend", "timeupdate", "waiting", ]; const defaultControlPanelElements = [ "play_pause", "current_time", "spacer", "total_time", "captions", "mute_popover", "report", "fullscreen_button", ]; const compactLayoutControlPanelElements = [ "remaining_time", "spacer", "mute_popover", "play_pause", ]; const videoConfig = { doubleClickForFullscreen: true, singleClickForPlayAndPause: true, customContextMenu: true, contextMenuElements: ["mute"], showUIAlways: false, addSeekBar: true, controlPanelElements: defaultControlPanelElements, }; const compactConfig = { doubleClickForFullscreen: true, singleClickForPlayAndPause: true, customContextMenu: true, contextMenuElements: ["mute"], showUIAlways: false, addSeekBar: false, controlPanelElements: compactLayoutControlPanelElements, }; class Video { isPlaylist(source) { const type = source.type && source.type.toLowerCase(); const src = source.src; if (type === "dash" || type === "hls") { return true; } else if (source.src) { return (src.indexOf(".mpd") === src.length - 5 || src.indexOf(".m3u8") === src.length - 6); } return false; } handleResize() { if (!this.input.width && this.video && this.root) { const { width: containerWidth } = this.root.getBoundingClientRect(); this.containerEl.setAttribute("width", containerWidth.toString()); this.alignSeekbar(); } } alignSeekbar() { if (this.el) { const buttonPanel = this.el.querySelector(".shaka-controls-button-panel"); const spacer = buttonPanel.querySelector(".shaka-spacer"); const rangeContainer = this.el.querySelector(".shaka-range-container"); if (buttonPanel && spacer && rangeContainer) { const buttonPanelRect = buttonPanel.getBoundingClientRect(); const spacerRect = spacer.getBoundingClientRect(); rangeContainer.style.marginRight = `${buttonPanelRect.right - spacerRect.right}px`; rangeContainer.style.marginLeft = `${spacerRect.left - buttonPanelRect.left}px`; } } } handlePause(originalEvent) { // On IOS, the controls force showing up if the video exist fullscreen while playing. // This forces the controls to always hide this.video.controls = false; if (!this.isAutoPause) { this.userPaused = true; } this.emit("pause", { originalEvent, player: this.player, auto: this.isAutoPause, }); // Reset isAutoPause after emitting the event this.isAutoPause = false; this.alignSeekbar(); } handlePlaying(originalEvent) { this.showControls(); this.alignSeekbar(); if (this.input.playView === "fullscreen" && this.input.layout !== "compact") { this.video.requestFullscreen(); } this.state.played = true; this.userPaused = false; this.emit("play", { originalEvent, player: this.player, auto: this.isAutoPlay, }); // Reset isAutoPlay after emitting the event this.isAutoPlay = false; } handleVolumeChange(originalEvent) { this.emit("volume-change", { originalEvent, volume: this.video.volume, muted: this.video.muted, }); } handleError(err) { this.state.failed = true; this.playButtonContainer.remove(); this.emit("load-error", err); } showControls() { let copyConfig = Object.assign({}, videoConfig); copyConfig.controlPanelElements = [...videoConfig.controlPanelElements]; if (this.input.layout === "compact") { copyConfig = Object.assign({}, compactConfig); } if (this.input.nav) { copyConfig.doubleClickForFullscreen = false; copyConfig.singleClickForPlayAndPause = false; copyConfig.showUIAlways = true; } if (this.state.volumeSlider === true) { const insertAt = copyConfig.controlPanelElements.length - 2 > 0 ? copyConfig.controlPanelElements.length - 2 : copyConfig.controlPanelElements.length; copyConfig.controlPanelElements.splice(insertAt, 0, "volume"); } this.ui.configure(copyConfig); this.video.controls = false; } takeAction() { switch (this.state.action) { case "play": this.video.play(); break; case "pause": this.video.pause(); break; default: } } onInput(input) { var _a, _b; if (this.video) { if (input.width || input.height) { this.containerEl.style.width = `${input.width}px`; } this.video.volume = (_a = input.volume) !== null && _a !== void 0 ? _a : 0; this.video.muted = !!input.muted; } // Check if action is changed if (this.state.action !== input.action) { this.state.action = (_b = input.action) !== null && _b !== void 0 ? _b : ""; this.takeAction(); } if (input.volumeSlider === true) { this.state.volumeSlider = input.volumeSlider; } } onCreate(input) { this.state = { volumeSlider: false, action: "", failed: false, played: false, }; if (input.action === "play" || input.autoplay === true) { this.isAutoPlay = true; } } _loadSrc(index) { const currentIndex = index || 0; const sources = [...this.input.source]; const src = sources[currentIndex]; let nextIndex; if (src && sources.length > currentIndex + 1) { nextIndex = currentIndex + 1; } this.player .load(src.src) .then(() => { this.state.failed = false; return Promise.all((this.input.clip || []).map((track) => { return this.player.addTextTrack(track.src, track.srclang, track.kind); })); }) .then(() => { const [track] = this.player.getTextTracks(); if (track) { this.player.selectTextTrack(track.id); // => this finds the id and everythings fine but it does nothing } }) .catch((err) => { if (nextIndex) { setTimeout(() => this._loadSrc(nextIndex), 0); } else { this.handleError(err); } }); } _attach() { var _a; const { Report, CurrentTime, RemainingTime, TotalTime, MuteButton, FullscreenButton, TextSelection, } = (0, elements_1.getElements)(this); // eslint-disable-next-line no-undef,new-cap this.ui = new this.shaka.ui.Overlay(this.player, this.containerEl, this.video); if ((_a = document === null || document === void 0 ? void 0 : document.documentElement) === null || _a === void 0 ? void 0 : _a.lang) { this.ui .getControls() .getLocalization() .changeLocale([document.documentElement.lang]); } // eslint-disable-next-line no-undef,new-cap this.shaka.ui.Controls.registerElement("report", new Report.Factory()); // eslint-disable-next-line no-undef,new-cap this.shaka.ui.Controls.registerElement("current_time", new CurrentTime.Factory()); this.shaka.ui.Controls.registerElement("remaining_time", new RemainingTime.Factory()); // eslint-disable-next-line no-undef,new-cap this.shaka.ui.Controls.registerElement("total_time", new TotalTime.Factory()); // eslint-disable-next-line no-undef,new-cap this.shaka.ui.Controls.registerElement("mute_popover", new MuteButton.Factory()); // eslint-disable-next-line no-undef,new-cap this.shaka.ui.Controls.registerElement("fullscreen_button", new FullscreenButton.Factory()); // eslint-disable-next-line no-undef,new-cap this.shaka.ui.Controls.registerElement("captions", new TextSelection.Factory()); this.ui.configure({ controlPanelElements: [], addSeekBar: false, }); // Replace play icon if (this.el) { const playIcon = this.getComponent("play-icon").el.cloneNode(true); const container = this.el.querySelector(".shaka-controls-container"); this.playButtonContainer = document.createElement("div"); this.playButtonContainer.classList.add("shaka-play-button-container"); this.playButtonContainer.appendChild(playIcon); container.appendChild(this.playButtonContainer); const shakaSpinner = this.el.querySelector(".shaka-spinner"); if (shakaSpinner) { setTimeout(() => { shakaSpinner.hidden = true; }, this.input.spinnerTimeout || DEFAULT_SPINNER_TIMEOUT); } } } handleSuccess() { // eslint-disable-next-line no-undef,new-cap this.shaka.polyfill.installAll(); // eslint-disable-next-line no-undef,new-cap this.player = new this.shaka.Player(this.video); this.player.configure(this.input.shakaConfig || {}); this._attach(); this._loadSrc(); } onMount() { this.root = this.getEl("root"); this.video = this.root.querySelector("video"); this.containerEl = this.root.querySelector(".video-player__container"); this.video.volume = this.input.volume || 1; this.video.muted = this.input.muted !== false; this.subscribeTo(this.video) .on("playing", this.handlePlaying.bind(this)) .on("pause", this.handlePause.bind(this)) .on("volumechange", this.handleVolumeChange.bind(this)); eventList.forEach((eventName) => { this.subscribeTo(this.video).on(eventName, (e) => this.emit(eventName, e)); }); if (this.input.offscreenPause) { // Set up Intersection Observer to detect when video is 50% in viewport this.setupIntersectionObserver(); // Add mousedown listener to intercept focus events from user clicking on video this.mouseDownHandler = this.handleMouseDown.bind(this); this.root.addEventListener("mousedown", this.mouseDownHandler); // Add window focus event listener to play video when window regains focus this.windowFocusHandler = this.handleWindowFocus.bind(this); window.addEventListener("focus", this.windowFocusHandler); // Add window blur event listener to pause video when window loses focus this.windowBlurHandler = this.handleWindowBlur.bind(this); window.addEventListener("blur", this.windowBlurHandler); } this._loadVideo(); } setupIntersectionObserver() { const options = { root: null, rootMargin: "0px", threshold: 0.5, }; this.observer = new IntersectionObserver((entries) => { // Auto-play when 50% visible and pause when less than 50% visible entries.forEach((entry) => { if (this.userPaused) { // If user has manually paused, do not auto-play/pause return; } if (entry.isIntersecting) { this.isInViewport = true; if (!this.state.failed && this.video.paused) { this.isAutoPlay = true; this.video.play().catch((e) => { this.isAutoPlay = false; }); } } else { this.isInViewport = false; if (!this.video.paused) { this.isAutoPause = true; this.video.pause(); } } }); }, options); this.observer.observe(this.containerEl); } handleMouseDown() { if (!document.hasFocus()) { this.isFocusFromVideoClick = true; } } handleWindowFocus() { if (this.isFocusFromVideoClick) { // Let the video click event handle play this.isFocusFromVideoClick = false; return; } if (this.isInViewport && this.video.paused && !this.userPaused) { this.isAutoPlay = true; this.video.play().catch((e) => { this.isAutoPlay = false; }); } } handleWindowBlur() { if (!this.video.paused) { this.isAutoPause = true; this.video.pause(); } } onDestroy() { if (this.ui) { this.ui.destroy(); } if (this.observer) { this.observer.disconnect(); } if (this.input.offscreenPause) { this.root.removeEventListener("mousedown", this.mouseDownHandler); window.removeEventListener("focus", this.windowFocusHandler); window.removeEventListener("blur", this.windowBlurHandler); } } _loadVideo() { this.state.failed = false; (0, shaka_player_1.load)() .then((shaka) => { this.shaka = shaka.default || shaka; window.shaka = this.shaka; // Set global object for some components to access this.handleSuccess(); }) .catch((e) => { console.log(e); this.handleError(e); }); } } module.exports = Video;