import { version as VERSION } from '../package.json'; import 'mediacms-vjs-plugin-font-icons/dist/mediacms-vjs-icons.css'; import './styles.scss'; let Plugin = null; function generatePlugin() { const videojsComponent = videojs.getComponent('Component'); const videojsClickableComponent = videojs.getComponent('ClickableComponent'); const videojsComponentButton = videojs.getComponent('Button'); const __MediaCMSComponent__ = videojs.extend(videojsComponent, { constructor() { videojsComponent.apply(this, arguments); this.setAttribute('class', this.buildCSSClass()); }, buildCSSClass() { return ''; }, }); const __MediaCMSButtonClickableComponent__ = videojs.extend(videojsClickableComponent, { buildCSSClass() { return ''; }, }); const __SettingsPanelComponent__ = composeAndExtendCustomComp('vjs-settings-panel'); const __SettingsPanelInnerComponent__ = composeAndExtendCustomComp('vjs-settings-panel-inner'); const __SettingsPanelTitleComponent__ = composeAndExtendCustomComp('vjs-setting-panel-title'); const __SettingsMenuComponent__ = composeAndExtendCustomComp('vjs-settings-menu'); const __SettingsMenuItemComponent__ = videojsComposeAndExtendCustomComp( __MediaCMSButtonClickableComponent__, 'vjs-settings-menu-item' ); const __SettingsMenuItemLabelComponent__ = composeAndExtendCustomComp('vjs-setting-menu-item-label'); const __SettingsMenuItemContentComponent__ = composeAndExtendCustomComp('vjs-setting-menu-item-content'); function composeCustomCompMethods(ret, extnd, innerHtml, extraCSSClass, htmlAttr) { var innerHtmlIsHTMLElement = !!innerHtml && innerHtml.nodeType === 1; if (!innerHtmlIsHTMLElement) { switch (typeof innerHtml) { case 'string': innerHtml = innerHtml.trim(); innerHtml = '' === innerHtml ? null : innerHtml; break; case 'number': innerHtml = innerHtml.toString(); break; default: innerHtml = null; } } switch (typeof extraCSSClass) { case 'string': extraCSSClass = extraCSSClass.trim(); extraCSSClass = '' === extraCSSClass ? null : extraCSSClass; break; default: extraCSSClass = null; } if (!htmlAttr || !Object.keys(htmlAttr).length) { htmlAttr = null; } if (innerHtml || htmlAttr) { ret.constructor = function () { extnd.apply(this, arguments); let k; if (innerHtml) { if (innerHtmlIsHTMLElement) { this.el_.appendChild(innerHtml); } else { this.el_.innerHTML = innerHtml; } } if (htmlAttr) { for (k in htmlAttr) { if (htmlAttr.hasOwnProperty(k)) { this.el_.setAttribute(k, htmlAttr[k]); } } } }; } if (extraCSSClass) { ret.buildCSSClass = function () { return extraCSSClass + ' ' + extnd.prototype.buildCSSClass.call(this); }; } } function videosjsExtendCustomComp(parent, methods) { return videojs.extend(parent, methods); } function videosjsFormatExtendObj(parent, methods) { return { extend: parent, methods: methods, }; } function videojsComposeAndExtendCustomComp(extnd, extraCSSClass, innerHtml, htmlAttr) { const ret = {}; composeCustomCompMethods(ret, extnd, innerHtml, extraCSSClass, htmlAttr); return videosjsExtendCustomComp(extnd, ret); } function composeCustomComp(extnd, extraCSSClass, innerHtml, htmlAttr) { const ret = {}; composeCustomCompMethods(ret, extnd, innerHtml, extraCSSClass, htmlAttr); return videosjsFormatExtendObj(extnd, ret); } function composeAndExtendCustomComp(extraCSSClass, innerHtml, htmlAttr) { return videojsComposeAndExtendCustomComp(__MediaCMSComponent__, extraCSSClass, innerHtml, htmlAttr); } /* ################################################## */ function generateControlBarComponents(pluginInstanceRef) { function childrenGen(parentKey, child, allComps, parentsConn, level) { var k, addedChild = false; allComps[level] = void 0 === allComps[level] ? [] : allComps[level]; for (k in child) { if (child.hasOwnProperty(k)) { if (child[k] && child[k].children) { if (childrenGen(k, child[k].children, allComps, parentsConn, level + 1)) { addedChild = true; allComps[level].push(k); parentsConn[k] = parentKey; } } else { addedChild = true; allComps[level].push(k); parentsConn[k] = parentKey; } } } return addedChild; } function gen(parent, ControlBar) { const componentsToAppend = [], parentsConnections = {}, appendedComponents = {}; let i, j, prnt, customCompKey, customCompName; if (parent.children) { childrenGen('controlBar', parent.children, componentsToAppend, parentsConnections, 0); /*console.log( componentsToAppend ); console.log( parentsConnections );*/ i = 0; while (i < componentsToAppend.length) { j = 0; while (j < componentsToAppend[i].length) { prnt = 0 === i ? pluginInstanceRef.player.getChild(parentsConnections[componentsToAppend[i][j]]) : appendedComponents[parentsConnections[componentsToAppend[i][j]]]; prnt.addChild(componentsToAppend[i][j], {}); appendedComponents[componentsToAppend[i][j]] = prnt.getChild(componentsToAppend[i][j]); j++; } i++; } } } return gen; } function generateTouchControlComponents(pluginInstanceRef, options) { if (options.enabledTouchControls) { let TouchControls, TouchControlsInner, TouchPrevious, TouchPlay, TouchNext; const previousButton = composeCustomComp(videojsComponentButton, 'vjs-icon-previous-item'); const playButton = composeCustomComp(videojsComponentButton, 'vjs-icon-play'); const nextButton = composeCustomComp(videojsComponentButton, 'vjs-icon-next-item'); playButton.methods.handleClick = function (ev) { if (this.player_.paused()) { this.player_.play(); setTimeout( function () { this.player_.userActive(false); }.bind(this), 250 ); } else { this.player_.pause(); } }; if (options.controlBar.next) { nextButton.methods.handleClick = function (ev) { this.player_.trigger('clicked_next_button'); }; } if (options.controlBar.previous) { previousButton.methods.handleClick = function (ev) { this.player_.trigger('clicked_previous_button'); }; } videojs.registerComponent( 'TouchControls', videojs.extend(__MediaCMSComponent__, composeCustomComp(__MediaCMSComponent__, 'vjs-touch-controls').methods) ); videojs.registerComponent( 'TouchControlsInner', videojs.extend(__MediaCMSComponent__, composeCustomComp(__MediaCMSComponent__).methods) ); videojs.registerComponent('TouchPreviousButton', videojs.extend(previousButton.extend, previousButton.methods)); videojs.registerComponent('TouchPlayButton', videojs.extend(playButton.extend, playButton.methods)); videojs.registerComponent('TouchNextButton', videojs.extend(nextButton.extend, nextButton.methods)); videojs.registerComponent( 'TouchPlay', videojs.extend(__MediaCMSComponent__, composeCustomComp(__MediaCMSComponent__, 'vjs-touch-play-button').methods) ); if (options.controlBar.next || options.controlBar.previous) { videojs.registerComponent( 'TouchPrevious', videojs.extend( __MediaCMSComponent__, composeCustomComp( __MediaCMSComponent__, 'vjs-touch-previous-button' + (!options.controlBar.previous ? ' vjs-touch-disabled-button' : '') ).methods ) ); videojs.registerComponent( 'TouchNext', videojs.extend( __MediaCMSComponent__, composeCustomComp( __MediaCMSComponent__, 'vjs-touch-next-button' + (!options.controlBar.next ? ' vjs-touch-disabled-button' : '') ).methods ) ); } else { videojs.registerComponent( 'TouchPrevious', videojs.extend( __MediaCMSComponent__, composeCustomComp( __MediaCMSComponent__, 'vjs-touch-previous-button' + (!options.controlBar.previous ? ' vjs-touch-hidden-button' : '') ).methods ) ); videojs.registerComponent( 'TouchNext', videojs.extend( __MediaCMSComponent__, composeCustomComp( __MediaCMSComponent__, 'vjs-touch-next-button' + (!options.controlBar.next ? ' vjs-touch-hidden-button' : '') ).methods ) ); } pluginInstanceRef.player.addChild('TouchControls'); TouchControls = pluginInstanceRef.player.getChild('TouchControls'); TouchControls.addChild('TouchControlsInner'); TouchControlsInner = TouchControls.getChild('TouchControlsInner'); TouchControlsInner.addChild('TouchPrevious'); TouchControlsInner.addChild('TouchPlay'); TouchControlsInner.addChild('TouchNext'); TouchPrevious = TouchControlsInner.getChild('TouchPrevious'); TouchPlay = TouchControlsInner.getChild('TouchPlay'); TouchNext = TouchControlsInner.getChild('TouchNext'); TouchPrevious.addChild('TouchPreviousButton'); TouchPlay.addChild('TouchPlayButton'); TouchNext.addChild('TouchNextButton'); } } function generateCornerLayersComponents(pluginInstanceRef, options) { const layers = {}; const compPrefix = 'CornerLayer_'; let k; if (options.cornerLayers.topLeft) { layers.topLeft = { className: 'vjs-corner-layer vjs-corner-top-left', parent: pluginInstanceRef.player, content: options.cornerLayers.topLeft, }; } if (options.cornerLayers.topRight) { layers.topRight = { className: 'vjs-corner-layer vjs-corner-top-right', parent: pluginInstanceRef.player, content: options.cornerLayers.topRight, }; } if (options.cornerLayers.bottomLeft) { layers.bottomLeft = { className: 'vjs-corner-layer vjs-corner-bottom-left', parent: pluginInstanceRef.player, content: options.cornerLayers.bottomLeft, }; } if (options.cornerLayers.bottomRight) { layers.bottomRight = { className: 'vjs-corner-layer vjs-corner-bottom-right', parent: pluginInstanceRef.player, content: options.cornerLayers.bottomRight, }; } for (k in layers) { if (layers.hasOwnProperty(k)) { if (layers[k].content) { videojs.registerComponent( compPrefix + k, videojs.extend( __MediaCMSComponent__, composeCustomComp(__MediaCMSComponent__, layers[k].className, layers[k].content).methods ) ); layers[k].parent.addChild(compPrefix + k); } } } } function generateActionsAnimationsComponents(pluginInstanceRef) { videojs.registerComponent( 'ActionsAnimations', videojs.extend( __MediaCMSComponent__, composeCustomComp(__MediaCMSComponent__, 'vjs-actions-anim', '').methods ) ); pluginInstanceRef.player.addChild('ActionsAnimations'); } function generateLoadingSpinnerComponent(pluginInstanceRef) { pluginInstanceRef.player.removeChild('LoadingSpinner'); videojs.registerComponent( 'LoadingSpinner', videojs.extend( __MediaCMSComponent__, composeCustomComp( __MediaCMSComponent__, 'vjs-loading-spinner', '
\
\
\
\
\
\
\
' ).methods ) ); pluginInstanceRef.player.addChild('LoadingSpinner'); } function initComponents(pluginInstanceRef, which, struct, args) { let k, i; let tmp; switch (which) { case 'bottomBackground': struct.bottomBackground = null; videojs.registerComponent( 'BottomBackground', videojs.extend(__MediaCMSComponent__, composeCustomComp(__MediaCMSComponent__, 'vjs-bottom-bg').methods) ); break; case 'progressControl': struct.progressControl = null; break; case '__subtitles': struct.subtitlesPanel = { children: { subtitlesPanelInner: { children: { subtitlesMenuTitle: null, subtitlesMenu: { children: {} }, }, }, }, }; tmp = composeCustomComp(__SettingsPanelComponent__, 'vjs-subtitles-panel'); tmp.methods.constructor = function () { videojsComponent.apply(this, arguments); this.setAttribute('class', this.buildCSSClass()); const that = this; function onFocusout(ev) { if (that.el_.contains(ev.relatedTarget)) { return; } that.player_.trigger('focusoutSubtitlesPanel'); } pluginInstanceRef.on(this.player_, ['updatedSubtitlesPanelsVisibility'], function () { videojs.dom[this.state.isOpenSubtitlesOptions ? 'addClass' : 'removeClass'](that.el_, 'vjs-visible-panel'); }); pluginInstanceRef.on(this.player_, ['openedSubtitlesPanel'], function (ev, openedFromKeyboard) { that.el_.setAttribute('tabindex', '-1'); that.el_.addEventListener('focusout', onFocusout); if (!!openedFromKeyboard) { that.el_.querySelector('.vjs-settings-menu-item').focus(); } else { that.el_.focus(); } }); pluginInstanceRef.on(this.player_, ['closedSubtitlesPanel'], function (ev, closedFromKeyboard) { that.el_.removeAttribute('tabindex'); that.el_.removeEventListener('focusout', onFocusout); if (!!closedFromKeyboard) { that.el_.querySelector('.vjs-settings-menu-item').focus(); } }); }; videojs.registerComponent('SubtitlesPanel', videojs.extend(tmp.extend, tmp.methods)); videojs.registerComponent( 'SubtitlesPanelInner', videojs.extend(__SettingsPanelInnerComponent__, composeCustomComp(__SettingsPanelInnerComponent__).methods) ); videojs.registerComponent( 'SubtitlesMenu', videojs.extend(__SettingsMenuComponent__, composeCustomComp(__SettingsMenuComponent__).methods) ); videojs.registerComponent( 'SubtitlesMenuTitle', videojs.extend( __SettingsPanelTitleComponent__, composeCustomComp(__SettingsPanelTitleComponent__, null, 'Subtitles').methods ) ); i = 0; while (i < args.options.subtitles.languages.length) { k = args.options.subtitles.languages[i]; struct.subtitlesPanel.children.subtitlesPanelInner.children.subtitlesMenu.children['subtitleOption_' + k.srclang] = { children: { ['subtitleOption_' + k.srclang + '_content']: null, }, }; (function (key, title) { tmp = composeCustomComp( __SettingsMenuItemComponent__, key === pluginInstanceRef.state.theSelectedSubtitleOption ? 'vjs-selected-menu-item' : null, null ); tmp.methods.constructor = function () { __SettingsMenuItemComponent__.apply(this, arguments); this.subtitleKey = key; const that = this; this.setAttribute('data-opt', key); pluginInstanceRef.on(this.player_, ['updatedSelectedSubtitleOption'], function () { if (that.subtitleKey === this.state.theSelectedSubtitleOption) { videojs.dom.addClass(that.el_, 'vjs-selected-menu-item'); } else { videojs.dom.removeClass(that.el_, 'vjs-selected-menu-item'); } }); }; tmp.methods.handleClick = function () { this.player_.trigger('selectedSubtitleOption', this.el_.getAttribute('data-opt')); }; videojs.registerComponent('SubtitleOption_' + key, videojs.extend(tmp.extend, tmp.methods)); tmp = composeCustomComp(__SettingsMenuItemContentComponent__, null, title); videojs.registerComponent('SubtitleOption_' + key + '_content', videojs.extend(tmp.extend, tmp.methods)); })(k.srclang, k.label); i += 1; } break; case '__settings': struct.settingsPanel = { children: { settingsPanelInner: { children: { settingsMenu: { children: {} }, }, }, }, }; tmp = composeCustomComp(__SettingsPanelComponent__, 'vjs-settings-root'); tmp.methods.constructor = function () { videojsComponent.apply(this, arguments); this.setAttribute('class', this.buildCSSClass()); const that = this; function onFocusout(ev) { if (that.el_.contains(ev.relatedTarget)) { return; } that.player_.trigger('focusoutSettingsPanel'); } pluginInstanceRef.on(this.player_, ['updatedSettingsPanelsVisibility'], function () { videojs.dom[this.state.isOpenSettingsOptions ? 'addClass' : 'removeClass'](that.el_, 'vjs-visible-panel'); }); pluginInstanceRef.on(this.player_, ['openedSettingsPanel'], function (ev, openedFromKeyboard) { that.el_.setAttribute('tabindex', '-1'); that.el_.addEventListener('focusout', onFocusout); if (!!openedFromKeyboard) { that.el_.querySelector('.vjs-settings-menu-item').focus(); } else { that.el_.focus(); } }); pluginInstanceRef.on(this.player_, ['closedSettingsPanel'], function (ev, closedFromKeyboard) { that.el_.removeAttribute('tabindex'); that.el_.removeEventListener('focusout', onFocusout); if (!!closedFromKeyboard) { that.el_.querySelector('.vjs-settings-menu-item').focus(); } }); }; videojs.registerComponent('SettingsPanel', videojs.extend(tmp.extend, tmp.methods)); videojs.registerComponent( 'SettingsPanelInner', videojs.extend(__SettingsPanelInnerComponent__, composeCustomComp(__SettingsPanelInnerComponent__).methods) ); videojs.registerComponent( 'SettingsMenu', videojs.extend(__SettingsMenuComponent__, composeCustomComp(__SettingsMenuComponent__).methods) ); if (args.enabledPlaybackSpeedPanel) { struct.settingsPanel.children.settingsPanelInner.children.settingsMenu.children.selectedPlaybackSpeed = { children: { selectedPlaybackSpeedLabel: null, selectedPlaybackSpeedContent: null, }, }; tmp = composeCustomComp(__SettingsMenuItemComponent__, 'vjs-selected-speed'); tmp.methods.handleClick = function (ev) { this.player_.trigger('openPlaybackSpeedOptions', !ev.screenX && !ev.screenY); }; videojs.registerComponent('SelectedPlaybackSpeed', videojs.extend(tmp.extend, tmp.methods)); videojs.registerComponent( 'SelectedPlaybackSpeedLabel', videojs.extend( __SettingsMenuItemLabelComponent__, composeCustomComp(__SettingsMenuItemLabelComponent__, null, 'Playback speed').methods ) ); tmp = composeCustomComp(__SettingsMenuItemContentComponent__, null, args.selectedPlaybackSpeed); tmp.methods.constructor = function () { videojsComponent.apply(this, arguments); const that = this; that.el_.innerHTML = pluginInstanceRef.selectedPlaybackSpeedTitle(); this.setAttribute('class', this.buildCSSClass()); pluginInstanceRef.on(this.player_, ['updatedSelectedPlaybackSpeed'], function () { that.el_.innerHTML = this.selectedPlaybackSpeedTitle(); }); }; videojs.registerComponent('SelectedPlaybackSpeedContent', videojs.extend(tmp.extend, tmp.methods)); } if (args.enabledResolutionsPanel) { struct.settingsPanel.children.settingsPanelInner.children.settingsMenu.children.selectedResolution = { children: { selectedResolutionLabel: null, selectedResolutionContent: null, }, }; tmp = composeCustomComp(__SettingsMenuItemComponent__, 'vjs-selected-quality'); tmp.methods.handleClick = function (ev) { this.player_.trigger('openQualityOptions', !ev.screenX && !ev.screenY); }; videojs.registerComponent('SelectedResolution', videojs.extend(tmp.extend, tmp.methods)); videojs.registerComponent( 'SelectedResolutionLabel', videojs.extend( __SettingsMenuItemLabelComponent__, composeCustomComp(__SettingsMenuItemLabelComponent__, null, 'Quality').methods ) ); tmp = composeCustomComp(__SettingsMenuItemContentComponent__, null, args.selectedResolution); tmp.methods.constructor = function () { videojsComponent.apply(this, arguments); const that = this; that.el_.innerHTML = args.selectedResolution; this.setAttribute('class', this.buildCSSClass()); pluginInstanceRef.on(this.player_, ['updatedSelectedQuality'], function () { that.el_.innerHTML = this.selectedQualityTitle(); }); }; videojs.registerComponent('SelectedResolutionContent', videojs.extend(tmp.extend, tmp.methods)); } break; case '__resolution': struct.resolutionsPanel = { children: { resolutionsPanelInner: { children: { resolutionsMenuTitle: { children: { resolutionsMenuBackButton: null, }, }, resolutionsMenu: { children: {} }, }, }, }, }; tmp = composeCustomComp(__SettingsPanelComponent__, 'vjs-resolutions-panel'); tmp.methods.constructor = function () { videojsComponent.apply(this, arguments); this.setAttribute('class', this.buildCSSClass()); const that = this; function onFocusout(ev) { if (that.el_.contains(ev.relatedTarget)) { return; } that.player_.trigger('focusoutResolutionsPanel'); } pluginInstanceRef.on(this.player_, ['updatedSettingsPanelsVisibility'], function () { videojs.dom[this.state.isOpenQualityOptions ? 'addClass' : 'removeClass'](that.el_, 'vjs-visible-panel'); }); pluginInstanceRef.on(this.player_, ['openedQualities'], function (ev, openedFromKeyboard) { that.el_.setAttribute('tabindex', '-1'); that.el_.addEventListener('focusout', onFocusout); if (!!openedFromKeyboard) { that.el_.querySelector('.vjs-setting-panel-title > *[role="button"]').focus(); } else { that.el_.focus(); } }); pluginInstanceRef.on(this.player_, ['closedQualities'], function (ev, closedFromKeyboard) { that.el_.removeAttribute('tabindex'); that.el_.removeEventListener('focusout', onFocusout); if (!!closedFromKeyboard) { that.el_.querySelector('.vjs-settings-menu-item').focus(); } }); }; videojs.registerComponent('ResolutionsPanel', videojs.extend(tmp.extend, tmp.methods)); videojs.registerComponent( 'ResolutionsPanelInner', videojs.extend(__SettingsPanelInnerComponent__, composeCustomComp(__SettingsPanelInnerComponent__).methods) ); videojs.registerComponent( 'ResolutionsMenu', videojs.extend(__SettingsMenuComponent__, composeCustomComp(__SettingsMenuComponent__).methods) ); videojs.registerComponent( 'ResolutionsMenuTitle', videojs.extend( __SettingsPanelTitleComponent__, composeCustomComp(__SettingsPanelTitleComponent__, 'vjs-settings-back').methods ) ); tmp = composeCustomComp(__MediaCMSButtonClickableComponent__, null, 'Quality'); tmp.methods.handleClick = function (ev) { this.player_.trigger('closeQualityOptions', !ev.screenX && !ev.screenY); }; videojs.registerComponent('ResolutionsMenuBackButton', videojs.extend(tmp.extend, tmp.methods)); const resolutionKeys = (function () { let i; const ret = []; const keys = Object.keys(args.resolutions); const stringKeys = []; const numericKeys = []; i = 0; while (i < keys.length) { if (isNaN(0 + keys[i])) { stringKeys.push(keys[i]); } else { numericKeys.push([parseFloat(keys[i]), keys[i]]); } i += 1; } numericKeys.sort((a, b) => b[0] - a[0]); i = 0; while (i < numericKeys.length) { ret.push(numericKeys[i][1]); i += 1; } i = 0; while (i < stringKeys.length) { ret.push(stringKeys[i]); i += 1; } return ret; })(); i = 0; while (i < resolutionKeys.length) { k = resolutionKeys[i]; struct.resolutionsPanel.children.resolutionsPanelInner.children.resolutionsMenu.children['resolutionOption_' + k] = { children: { ['resolutionOption_' + k + '_content']: null, }, }; (function (key, title) { tmp = composeCustomComp( __SettingsMenuItemComponent__, key.toString() === pluginInstanceRef.state.theSelectedQuality.toString() ? 'vjs-selected-menu-item' : null, null /*, { 'data-opt': key }*/ ); tmp.methods.constructor = function () { __SettingsMenuItemComponent__.apply(this, arguments); const that = this; this.qualityKey = key; this.setAttribute('data-opt', key); pluginInstanceRef.on(this.player_, ['updatedSelectedQuality'], function () { videojs.dom[that.qualityKey === this.state.theSelectedQuality ? 'addClass' : 'removeClass']( that.el_, 'vjs-selected-menu-item' ); }); }; tmp.methods.handleClick = function () { this.player_.trigger('selectedQuality', this.el_.getAttribute('data-opt')); }; videojs.registerComponent('ResolutionOption_' + key, videojs.extend(tmp.extend, tmp.methods)); tmp = composeCustomComp(__SettingsMenuItemContentComponent__, null, title); videojs.registerComponent('ResolutionOption_' + key + '_content', videojs.extend(tmp.extend, tmp.methods)); })(k, args.resolutions[k].title || k); i += 1; } break; case '__playbackSpeed': struct.playbackSpeedsPanel = { children: { playbackSpeedsPanelInner: { children: { playbackSpeedsMenuTitle: { children: { playbackSpeedsMenuBackButton: null, }, }, playbackSpeedsMenu: { children: {} }, }, }, }, }; tmp = composeCustomComp(__SettingsPanelComponent__, 'vjs-playback-speed-panel'); tmp.methods.constructor = function () { videojsComponent.apply(this, arguments); this.setAttribute('class', this.buildCSSClass()); const that = this; function onFocusout(ev) { if (that.el_.contains(ev.relatedTarget)) { return; } that.player_.trigger('focusoutPlaybackSpeedsPanel'); } pluginInstanceRef.on(this.player_, ['updatedSettingsPanelsVisibility'], function () { videojs.dom[this.state.isOpenPlaybackSpeedOptions ? 'addClass' : 'removeClass'](that.el_, 'vjs-visible-panel'); }); pluginInstanceRef.on(this.player_, ['openedPlaybackSpeeds'], function (ev, openedFromKeyboard) { that.el_.setAttribute('tabindex', '-1'); that.el_.addEventListener('focusout', onFocusout); if (!!openedFromKeyboard) { that.el_.querySelector('.vjs-setting-panel-title > *[role="button"]').focus(); } else { that.el_.focus(); } }); pluginInstanceRef.on(this.player_, ['closedPlaybackSpeeds'], function (ev, closedFromKeyboard) { that.el_.removeAttribute('tabindex'); that.el_.removeEventListener('focusout', onFocusout); if (!!closedFromKeyboard) { that.el_.querySelector('.vjs-settings-menu-item').focus(); } }); }; videojs.registerComponent('PlaybackSpeedsPanel', videojs.extend(tmp.extend, tmp.methods)); videojs.registerComponent( 'PlaybackSpeedsPanelInner', videojs.extend(__SettingsPanelInnerComponent__, composeCustomComp(__SettingsPanelInnerComponent__).methods) ); videojs.registerComponent( 'PlaybackSpeedsMenu', videojs.extend(__SettingsMenuComponent__, composeCustomComp(__SettingsMenuComponent__).methods) ); videojs.registerComponent( 'PlaybackSpeedsMenuTitle', videojs.extend( __SettingsPanelTitleComponent__, composeCustomComp(__SettingsPanelTitleComponent__, 'vjs-settings-back').methods ) ); tmp = composeCustomComp(__MediaCMSButtonClickableComponent__, null, 'Playback speed'); tmp.methods.handleClick = function (ev) { this.player_.trigger('closePlaybackSpeedOptions', !ev.screenX && !ev.screenY); }; videojs.registerComponent('PlaybackSpeedsMenuBackButton', videojs.extend(tmp.extend, tmp.methods)); for (k in args.playbackSpeeds) { if (args.playbackSpeeds.hasOwnProperty(k)) { struct.playbackSpeedsPanel.children.playbackSpeedsPanelInner.children.playbackSpeedsMenu.children[ 'playbackSpeedOption_' + args.playbackSpeeds[k].speed ] = { children: { ['playbackSpeedOption_' + args.playbackSpeeds[k].speed + '_content']: null, }, }; (function (key, title) { tmp = composeCustomComp( __SettingsMenuItemComponent__, key.toString() === pluginInstanceRef.state.theSelectedPlaybackSpeed.toString() ? 'vjs-selected-menu-item' : null, null /*, { 'data-opt': key }*/ ); tmp.methods.constructor = function () { __SettingsMenuItemComponent__.apply(this, arguments); const that = this; this.playbackSpeedKey = key; this.setAttribute('data-opt', key); pluginInstanceRef.on(this.player_, ['updatedSelectedPlaybackSpeed'], function () { videojs.dom[that.playbackSpeedKey === this.state.theSelectedPlaybackSpeed ? 'addClass' : 'removeClass']( that.el_, 'vjs-selected-menu-item' ); }); }; tmp.methods.handleClick = function () { this.player_.trigger('selectedPlaybackSpeed', this.el_.getAttribute('data-opt')); }; videojs.registerComponent('PlaybackSpeedOption_' + key, videojs.extend(tmp.extend, tmp.methods)); tmp = composeCustomComp(__SettingsMenuItemContentComponent__, null, title); videojs.registerComponent('PlaybackSpeedOption_' + key + '_content', videojs.extend(tmp.extend, tmp.methods)); })(args.playbackSpeeds[k].speed, args.playbackSpeeds[k].title || k); } } break; case '__leftControls': struct.leftControls = { children: {} }; if (args.options.controlBar.previous) { tmp = composeCustomComp(videojsComponentButton, 'vjs-previous-button'); tmp.methods.handleClick = function (ev) { this.player_.trigger('clicked_previous_button'); }; videojs.registerComponent('PreviousButton', videojs.extend(tmp.extend, tmp.methods)); struct.leftControls.children.previousButton = null; } if (args.options.controlBar.play) { struct.leftControls.children.playToggle = null; } if (args.options.controlBar.next) { tmp = composeCustomComp(videojsComponentButton, 'vjs-next-button'); tmp.methods.handleClick = function (ev) { this.player_.trigger('clicked_next_button'); }; videojs.registerComponent('NextButton', videojs.extend(tmp.extend, tmp.methods)); struct.leftControls.children.nextButton = null; } /*if( args.options.controlBar.previous ){ struct.leftControls.children.previous = null; } if( args.options.controlBar.next ){ // videojs.registerComponent("Next", videojs.extend( __MediaCMSComponent__ , composeCustomComp( __MediaCMSComponent__, 'vjs-bottom-bg' ).methods)); videojs.registerComponent("Next", videojs.extend( __MediaCMSComponent__ , composeCustomComp( __MediaCMSComponent__, 'vjs-bottom-bg' ).methods)); struct.leftControls.children.next = null; }*/ if (args.options.controlBar.volume) { struct.leftControls.children.volumePanel = null; } if (args.options.controlBar.time) { struct.leftControls.children.currentTimeDisplay = null; struct.leftControls.children.timeDivider = null; struct.leftControls.children.durationDisplay = null; } /*console.log( struct.leftControls.children );*/ videojs.registerComponent( 'LeftControls', videojs.extend(__MediaCMSComponent__, composeCustomComp(__MediaCMSComponent__, 'vjs-left-controls').methods) ); break; case '__rightControls': struct.rightControls = { children: {} }; if (args.options.subtitles) { struct.rightControls.children.subtitlesToggle = null; } if (args.enabledSettingsPanel) { struct.rightControls.children.settingsToggle = null; } if (args.options.controlBar.theaterMode) { struct.rightControls.children.theaterModeToggle = null; } if (args.options.controlBar.pictureInPicture) { struct.rightControls.children.pictureInPictureToggle = null; } if (args.options.controlBar.fullscreen) { struct.rightControls.children.fullscreenToggle = null; } videojs.registerComponent( 'RightControls', videojs.extend(__MediaCMSComponent__, composeCustomComp(__MediaCMSComponent__, 'vjs-right-controls').methods) ); if (args.options.subtitles) { tmp = composeCustomComp(videojsComponentButton, 'vjs-subtitles-control'); tmp.methods.handleClick = function (ev) { this.player_.trigger( pluginInstanceRef.state.isOpenSubtitlesOptions ? 'closeSubtitlesPanel' : 'openSubtitlesPanel', !ev.screenX && !ev.screenY ); }; videojs.registerComponent('SubtitlesToggle', videojs.extend(tmp.extend, tmp.methods)); } if (args.enabledSettingsPanel) { tmp = composeCustomComp(videojsComponentButton, 'vjs-settings-control vjs-icon-cog'); tmp.methods.handleClick = function (ev) { this.player_.trigger( pluginInstanceRef.state.isOpenSettingsOptions ? 'closeSettingsPanel' : 'openSettingsPanel', !ev.screenX && !ev.screenY ); }; videojs.registerComponent('SettingsToggle', videojs.extend(tmp.extend, tmp.methods)); } if (args.options.controlBar.theaterMode) { tmp = composeCustomComp(videojsComponentButton, 'vjs-theater-mode-control'); tmp.methods.handleClick = function () { this.player_.trigger('theatermodechange'); this.updateControlText(); }; tmp.methods.updateControlText = function () { this.controlText(this.player_.localize(pluginInstanceRef.isTheaterMode() ? 'Default mode' : 'Theater mode')); }; videojs.registerComponent('TheaterModeToggle', videojs.extend(tmp.extend, tmp.methods)); } break; } } function controlBarComponentsStructs(pluginInstanceRef, options) { let struct = {}; const enabledResolutionsPanel = void 0 !== options.resolutions && void 0 !== options.resolutions.options && !!Object.keys(options.resolutions.options).length; const enabledPlaybackSpeedPanel = void 0 !== options.playbackSpeeds && void 0 !== options.playbackSpeeds.options && !!Object.keys(options.playbackSpeeds.options).length; const enabledSettingsPanel = enabledResolutionsPanel || enabledPlaybackSpeedPanel; // @note: At the moment the only setting option is video resolution. if (options.controlBar.bottomBackground) { initComponents(pluginInstanceRef, 'bottomBackground', struct); } if (options.controlBar.progress) { initComponents(pluginInstanceRef, 'progressControl', struct); } if (enabledResolutionsPanel) { initComponents(pluginInstanceRef, '__resolution', struct, { resolutions: options.resolutions.options }); } if (enabledPlaybackSpeedPanel) { initComponents(pluginInstanceRef, '__playbackSpeed', struct, { playbackSpeeds: options.playbackSpeeds.options }); } if (options.subtitles) { initComponents(pluginInstanceRef, '__subtitles', struct, { options: options }); } if (enabledSettingsPanel) { if (enabledResolutionsPanel && enabledPlaybackSpeedPanel) { initComponents(pluginInstanceRef, '__settings', struct, { enabledResolutionsPanel: enabledResolutionsPanel, selectedResolution: enabledResolutionsPanel ? options.resolutions.default : null, enabledPlaybackSpeedPanel: enabledPlaybackSpeedPanel, selectedPlaybackSpeed: enabledPlaybackSpeedPanel ? options.playbackSpeeds.default : null, }); } else if (enabledResolutionsPanel) { initComponents(pluginInstanceRef, '__settings', struct, { enabledResolutionsPanel: enabledResolutionsPanel, selectedResolution: enabledResolutionsPanel ? options.resolutions.default : null, }); } else if (enabledPlaybackSpeedPanel) { initComponents(pluginInstanceRef, '__settings', struct, { enabledPlaybackSpeedPanel: enabledPlaybackSpeedPanel, selectedPlaybackSpeed: enabledPlaybackSpeedPanel ? options.playbackSpeeds.default : null, }); } } if ( options.controlBar.play || options.controlBar.previous || options.controlBar.next || options.controlBar.volume || options.controlBar.time ) { initComponents(pluginInstanceRef, '__leftControls', struct, { options: options }); } if ( enabledSettingsPanel || options.subtitles || options.controlBar.theaterMode || options.controlBar.fullscreen || options.controlBar.pictureInPictureToggle ) { initComponents(pluginInstanceRef, '__rightControls', struct, { options: options, enabledSettingsPanel: enabledSettingsPanel, }); } return { children: struct }; } /* ################################################## */ function setControlBarComponents(pluginInstncRef, options, player) { if (isDefined(options) && isDefined(options.controlBar)) { generateControlBarComponents(pluginInstncRef)( controlBarComponentsStructs(pluginInstncRef, options), player.getChild('controlBar') ); } } function setCornerLayersComponents(pluginInstncRef, options) { if (isDefined(options)) { generateCornerLayersComponents(pluginInstncRef, options); } } function setActionsAnimationsComponents(pluginInstncRef) { generateActionsAnimationsComponents(pluginInstncRef); } function replaceLoadingSpinnerComponent(pluginInstncRef) { generateLoadingSpinnerComponent(pluginInstncRef); } function setTouchControlComponents(pluginInstncRef, options) { generateTouchControlComponents(pluginInstncRef, options); } function removeClassname(el, cls) { if (el.classList) { el.classList.remove(cls); } else { el.className = el.className.replace(new RegExp('(^|\\b)' + cls.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); } } function addClassname(el, cls) { if (el.classList) { el.classList.add(cls); } else { el.className += ' ' + cls; } } function centralizeBoxPosition(vw, vh, vr, pw, ph, pr) { const ret = {}; const videoRatio = isDefined(vr) && !isNull(vr) ? vr : vw / vh, playerRatio = isDefined(pr) && !isNull(pr) ? pr : pw / ph, playerVerticalOrientation = 1 > playerRatio, videoVerticalOrientation = 1 > videoRatio; if (!playerVerticalOrientation) { if (!videoVerticalOrientation) { // Both ARE NOT "vertical"; if (videoRatio > playerRatio) { if (vw >= pw) { ret.w = pw; ret.h = ret.w / videoRatio; } else { ret.w = vw; ret.h = vh; } } else { ret.h = vw >= pw ? ph : vh >= ph ? ph : vh; ret.w = ret.h * videoRatio; } } else { // Video IS "vertical" and player IS NOT "vertical"; if (vh >= ph) { ret.h = ph; ret.w = ret.h * videoRatio; } else { ret.w = vw; ret.h = vh; } } } else if (!videoVerticalOrientation) { // Player IS "vertical" and video IS NOT "vertical"; if (vw >= pw) { ret.w = pw; ret.h = ret.w / videoRatio; } else { ret.w = vw; ret.h = vh; } } else { // Both ARE "vertical"; if (videoRatio > playerRatio) { if (vw >= pw) { ret.w = pw; ret.h = ret.w / videoRatio; } else { ret.w = vw; ret.h = vh; } } else if (vw >= pw) { ret.h = ph; ret.w = ret.h * videoRatio; } else if (vh >= ph) { ret.h = ph; ret.w = ret.h * videoRatio; } else { ret.w = vw; ret.h = vh; } } ret.t = (ph - ret.h) / 2; ret.l = (pw - ret.w) / 2; return ret; } function isBoolean(v) { return 'boolean' === typeof v || v instanceof Boolean; } function isString(v) { return 'string' === typeof v || v instanceof String; } function isDefined(v) { return void 0 != v; } function isNull(v) { return null === v; } function isArray(v) { return !Array.isArray ? '[object Array]' === Object.prototype.toString.call(v) : Array.isArray(v); } function ifBooleanElse(bol, els) { return isBoolean(bol) ? bol : els; } function applyCssTransform(elem, val) { val = val.replace(/ /g, ''); // Remove all blank characters, otherwise doesn't work in IE. elem.style.transform = val; elem.style.msTransform = val; elem.style.MozTransform = val; elem.style.WebkitTransform = val; elem.style.OTransform = val; } function browserSupports_csstransforms() { var i, v, b = document.body || document.documentElement, s = b.style, p = 'transition'; if ('string' === typeof s[p]) { return true; } v = ['Moz', 'webkit', 'Webkit', 'Khtml', 'O', 'ms']; p = p.charAt(0).toUpperCase() + p.substr(1); i = 0; while (i < v.length) { if ('string' === typeof s[v[i] + p]) { return true; } i += 1; } return false; } function browserSupports(type) { switch (type) { case 'csstransforms': return browserSupports_csstransforms(); } return null; } function extractSupportedAndUsedVideoFormat(defaultSource, defaultResolution, availabeResolutions) { if (defaultResolution && availabeResolutions) { const x = availabeResolutions[defaultResolution]; let i = 0; while (i < x.src.length) { if (defaultSource === x.src[i] /*|| -1 < defaultSource.indexOf( x.src[i] )*/) { // console.log( "C", { defaultResolution: defaultResolution, format: x.format[i], order: i } ); return { defaultResolution: defaultResolution, format: x.format[i], order: i }; } i += 1; } } // console.warn( 'Default Source: ', defaultSource ); // console.warn( 'Selected resolution: ', defaultResolution ); // console.warn( 'Video Resolutions: ', availabeResolutions ); // console.log( availabeResolutions[defaultResolution].format[0] ); // return null; let k, j; for (k in availabeResolutions) { if (availabeResolutions.hasOwnProperty(k)) { j = 0; while (j < availabeResolutions[k].src.length) { if (defaultSource === availabeResolutions[k].src[j]) { while (void 0 === availabeResolutions[k].format[j] && j < availabeResolutions[k].format.length) { j += 1; } defaultResolution = k; j = void 0 === availabeResolutions[k].format[j] ? availabeResolutions[k].format.length - 1 : j; // console.log( "A", { defaultResolution: k, format: availabeResolutions[k].format[j], order: j }, defaultSource ); return { defaultResolution: k, format: availabeResolutions[k].format[j], order: j }; } j += 1; } } } // console.log( "B", { defaultResolution: defaultResolution, format: availabeResolutions[defaultResolution].format[0], order: 0 } ); return { defaultResolution: defaultResolution, format: availabeResolutions[defaultResolution].format[0], order: 0 }; } function initElementsFocus(player) { var controlBar = player.getChild('controlBar'); var progressControl = void 0 === controlBar ? controlBar : controlBar.getChild('progressControl'); var leftControls = void 0 === controlBar ? controlBar : controlBar.getChild('leftControls'); var rightControls = void 0 === controlBar ? controlBar : controlBar.getChild('rightControls'); var volumePanel = void 0 === leftControls ? leftControls : leftControls.getChild('volumePanel'); var volumeControl = void 0 === volumePanel ? volumePanel : volumePanel.getChild('volumeControl'); var elems = { playToggle: void 0 === leftControls ? leftControls : leftControls.getChild('playToggle'), previousButton: void 0 === leftControls ? leftControls : leftControls.getChild('previousButton'), nextButton: void 0 === leftControls ? leftControls : leftControls.getChild('nextButton'), muteToggle: void 0 === volumePanel ? volumePanel : volumePanel.getChild('muteToggle'), volumeBar: void 0 === volumePanel ? volumePanel : volumePanel.getChild('volumeControl').getChild('volumeBar'), subtitlesToggle: void 0 === rightControls ? rightControls : rightControls.getChild('subtitlesToggle'), settingsToggle: void 0 === rightControls ? rightControls : rightControls.getChild('settingsToggle'), fullscreenToggle: void 0 === rightControls ? rightControls : rightControls.getChild('fullscreenToggle'), theaterModeToggle: void 0 === rightControls ? rightControls : rightControls.getChild('theaterModeToggle'), pictureInPictureToggle: void 0 === rightControls ? rightControls : rightControls.getChild('PictureInPictureToggle'), seekBar: void 0 === progressControl ? progressControl : progressControl.getChild('seekBar'), }; if (void 0 !== elems.playToggle) { handleElemFocus(player, elems.playToggle.el_); } if (void 0 !== elems.previousButton) { handleElemFocus(player, elems.previousButton.el_); } if (void 0 !== elems.nextButton) { handleElemFocus(player, elems.nextButton.el_); } if (void 0 !== elems.muteToggle) { handleElemFocus(player, elems.muteToggle.el_); } if (void 0 !== elems.volumeBar) { handleElemFocus(player, elems.volumeBar.el_); } if (void 0 !== elems.subtitlesToggle) { handleElemFocus(player, elems.subtitlesToggle.el_); } if (void 0 !== elems.settingsToggle) { handleElemFocus(player, elems.settingsToggle.el_); } if (void 0 !== elems.fullscreenToggle) { handleElemFocus(player, elems.fullscreenToggle.el_); } if (void 0 !== elems.theaterModeToggle) { handleElemFocus(player, elems.theaterModeToggle.el_); } if (void 0 !== elems.pictureInPictureToggle) { handleElemFocus(player, elems.pictureInPictureToggle.el_); } if (void 0 !== elems.seekBar) { handleElemFocus(player, elems.seekBar.el_); } } function handleElemFocus(player, elem) { function onFocus(ev) { if (!isMouseDown) { isKeyboardFocus = true; ev.target.setAttribute('key-focus', ''); } } function onBlur(ev) { if (isKeyboardFocus) { isKeyboardFocus = false; ev.target.removeAttribute('key-focus'); } } var isMouseDown = false; var isKeyboardFocus = false; elem.addEventListener('blur', onBlur); elem.addEventListener('focus', onFocus); elem.addEventListener('mouseup', function () { isMouseDown = false; }); elem.addEventListener('mousedown', function () { isMouseDown = true; }); } /* ################################################## */ function videoPreviewThumb(player, options) { player.getChild('ControlBar').getChild('ProgressControl').getChild('SeekBar').removeChild('MouseTimeDisplay'); var halfThumbWidth = -1; var defaults = { frame: { width: 160, height: 120, }, }; function extend() { var args = Array.prototype.slice.call(arguments); var target = args.shift() || {}; var i, obj, prop; for (i in args) { obj = args[i]; for (prop in obj) { if (obj.hasOwnProperty(prop)) { target[prop] = 'object' === typeof obj[prop] ? extend(target[prop], obj[prop]) : obj[prop]; } } } return target; } function getAllComputedStyles(el) { return window.getComputedStyle ? window.getComputedStyle(el) : el.currentStyle; } function getComputedStyle(el, pseudo) { return function (prop) { return window.getComputedStyle ? window.getComputedStyle(el, pseudo)[prop] : el.currentStyle[prop]; }; } function offsetParent(el) { return 'HTML' !== el.nodeName && 'static' === getComputedStyle(el)('position') ? offsetParent(el.offsetParent) : el; } function updateDimensions() { if (isFullscreen) { halfThumbWidth = (innerBorderWidth.left + innerBorderWidth.right + 1.5 * settings.frame.width) / 2; spriteDom.inner.style.height = innerBorderWidth.top + innerBorderWidth.bottom + 1.5 * settings.frame.height + 'px'; spriteDom.inner.style.width = innerBorderWidth.left + innerBorderWidth.right + 1.5 * settings.frame.width + 'px'; } else { halfThumbWidth = (innerBorderWidth.left + innerBorderWidth.right + settings.frame.width) / 2; spriteDom.inner.style.height = innerBorderWidth.top + innerBorderWidth.bottom + settings.frame.height + 'px'; spriteDom.inner.style.width = innerBorderWidth.left + innerBorderWidth.right + settings.frame.width + 'px'; } spriteDom.inner.style.left = -1 * halfThumbWidth + 'px'; } var spriteDom = { wrap: document.createElement('div'), inner: document.createElement('div'), img: document.createElement('img'), timeDisplay: document.createElement('div'), timeDisplayInner: document.createElement('div'), }; var innerBorderWidth = { top: 0, left: 0, right: 0, bottom: 0, }; var progressControl = player.controlBar.childNameIndex_.ProgressControl; var progressControlElem; var seekBar = progressControl.childNameIndex_.SeekBar; var duration = player.duration(); var isFullscreen = player.isFullscreen(); var settings = extend({}, defaults, options); /*settings.frame.height = defaults.width / ( settings.frame.width / settings.frame.height ); settings.frame.width = defaults.width;*/ /*settings.frame.width = ( settings.frame.width / settings.frame.height ) * defaults.width; settings.frame.height = defaults.height;*/ /*settings.frame.height = 192 / ( settings.frame.width / settings.frame.height ); settings.frame.width = 192;*/ spriteDom.wrap.className = 'vjs-preview-thumb'; spriteDom.inner.className = 'vjs-preview-thumb-inner'; spriteDom.inner.style.backgroundImage = 'url(' + settings.url + ')'; spriteDom.timeDisplay.className = 'vjs-preview-thumb-time-display'; spriteDom.timeDisplayInner.innerHTML = '0:00'; var spriteHeight = 0; player.on('durationchange', function (e) { duration = player.duration(); }); // when the container is MP4. player.on('loadedmetadata', function (e) { duration = player.duration(); }); // when the container is HLS. player.on('fullscreenchange', function (e) { setTimeout(function () { isFullscreen = player.isFullscreen(); updateDimensions(); }, 100); }); player.one('playing', function (e) { // @note: Listener bind once. updateDimensions(); player.addClass('vjs-enabled-preview-thumb'); // @note: Enable preview functionality. spriteDom.img.onload = function () { var innerStyles = getAllComputedStyles(spriteDom.inner); if (void 0 !== innerStyles) { innerBorderWidth.top = parseFloat(innerStyles.borderTopWidth); innerBorderWidth.left = parseFloat(innerStyles.borderLeftWidth); innerBorderWidth.right = parseFloat(innerStyles.borderRightWidth); innerBorderWidth.bottom = parseFloat(innerStyles.borderBottomWidth); } spriteHeight = this.naturalHeight; spriteDom.img = void 0; // Unset image element. updateDimensions(); }; spriteDom.img.src = settings.url; }); function moveListener(event) { progressControlElem = progressControlElem || progressControl.el(); var progressControlClientRect = offsetParent(progressControlElem).getBoundingClientRect(); var pageXOffset = window.pageXOffset ? window.pageXOffset : document.documentElement.scrollLeft; var pageX = event.changedTouches ? event.changedTouches[0].pageX : event.pageX; var left = (pageX || event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft) - (progressControlClientRect.left + pageXOffset); var right = (progressControlClientRect.width || progressControlClientRect.right) + pageXOffset; var mouseTime = !spriteHeight ? 0 : Math.min( (spriteHeight / settings.frame.height) * settings.frame.seconds - 1, Math.floor(((left - progressControlElem.offsetLeft) / progressControl.width()) * duration) ); spriteDom.timeDisplayInner.innerHTML = videojs.formatTime(duration * (left / right)); if (left < halfThumbWidth) { left = halfThumbWidth; } else if (left > right - halfThumbWidth) { left = right - halfThumbWidth; } spriteDom.wrap.style.transform = 'translate(' + Math.min(right - halfThumbWidth, left) + 'px, 0px)'; spriteDom.inner.style.backgroundPositionY = (isFullscreen ? -1.5 : -1) * settings.frame.height * Math.floor(mouseTime / settings.frame.seconds) + 'px'; } progressControl.on('mouseover', moveListener); progressControl.on('mousemove', moveListener); spriteDom.timeDisplay.appendChild(spriteDom.timeDisplayInner); spriteDom.inner.appendChild(spriteDom.timeDisplay); spriteDom.wrap.appendChild(spriteDom.inner); progressControl.el_.appendChild(spriteDom.wrap); } /* ################################################## */ const VideojsPluginClass = videojs.getPlugin('plugin'); class MediaCmsVjsPlugin extends VideojsPluginClass { /** * Create a MediaCmsVjsPlugin plugin instance. * * @param {Player} player VideoJs Player instance. * @param {Object} options Optional plugin options value. * @param {Object} state Optional initial player state values. * @param {Function} stateUpdateCallback The function that will be triggered on state values change. * @return {void} */ constructor( player, domElem, options, state, resolutions, playbackSpeeds, stateUpdateCallback, nextButtonClickCallback, previousButtonClickCallback ) { super(player, options); if (!options.sources.length) { console.warn('Missing media source'); return; } options.enabledTouchControls = !!videojs.TOUCH_ENABLED ? true : options.enabledTouchControls; /** * Filter input state values. * * @param {Object} st Plugin state values. * @return {Object} Plugin state filtered/validated values. */ function filterState(st) { const ret = {}; if (st && st instanceof Object && Object.keys(st).length) { if (!isNaN(st.volume)) { ret.volume = Math.max(Math.min(st.volume, 1), 0); } if (isBoolean(st.soundMuted)) { ret.soundMuted = st.soundMuted; } if (isBoolean(st.theaterMode)) { ret.theaterMode = st.theaterMode; } } if (Object.keys(resolutions).length) { let resolutionKeys = Object.keys(resolutions); ret.theSelectedQuality = !st || void 0 === st.theSelectedQuality || void 0 === resolutions[st.theSelectedQuality] ? resolutionKeys[Math.floor(resolutionKeys.length / 2)] : st.theSelectedQuality; } if (Object.keys(playbackSpeeds).length) { if (!!st.theSelectedPlaybackSpeed) { let k; st.theSelectedPlaybackSpeed = st.theSelectedPlaybackSpeed.toString(); for (k in playbackSpeeds) { if (playbackSpeeds.hasOwnProperty(k)) { if (st.theSelectedPlaybackSpeed === playbackSpeeds[k].speed) { ret.theSelectedPlaybackSpeed = playbackSpeeds[k].speed; break; } } } } } else { ret.theSelectedPlaybackSpeed = '1'; } return ret; } this.videoHtmlElem = domElem; this.initedVideoPreviewThumb = false; this.videoPreviewThumb = null; if ( !!!videojs.TOUCH_ENABLED && !!options.videoPreviewThumb && void 0 !== options.videoPreviewThumb.url && void 0 !== options.videoPreviewThumb.frame && !isNaN(options.videoPreviewThumb.frame.width) && !isNaN(options.videoPreviewThumb.frame.height) && !isNaN(options.videoPreviewThumb.frame.seconds) ) { this.videoPreviewThumb = options.videoPreviewThumb; } this.enabledFullscreenToggle = options.controlBar.fullscreen; this.enabledTheaterMode = options.controlBar.theaterMode; this.playbackSpeeds = playbackSpeeds; this.videoResolutions = null; this.videoPlaybackSpeeds = null; this.timeoutSettingsPanelFocusout = null; this.timeoutSubtitlesPanelFocusout = null; this.timeoutResolutionsPanelFocusout = null; this.timeoutPlaybackSpeedsPanelFocusout = null; this.actionAnimationTimeout = null; this.seekingTimeout = null; this.updateTime = 0; this.pausedTime = -1; this.seeking = false; this.wasPlayingOnResolutionChange = false; this.hadStartedOnResolutionChange = false; this.isChangingResolution = false; this.videoNativeDimensions = options.nativeDimensions; // Filter state object values. this.setState(videojs.mergeOptions(this.state, filterState(state))); // Set state values update callback function. this.stateUpdateCallback = stateUpdateCallback instanceof Function ? stateUpdateCallback : null; this.nextButtonClickCallback = nextButtonClickCallback instanceof Function ? nextButtonClickCallback : null; this.previousButtonClickCallback = previousButtonClickCallback instanceof Function ? previousButtonClickCallback : null; // Set video resolutions info. if (this.state.theSelectedQuality) { this.videoResolutions = resolutions; this.videoFormat = extractSupportedAndUsedVideoFormat( this.player.src(), this.state.theSelectedQuality, this.videoResolutions ); this.state.theSelectedQuality = this.videoFormat.defaultResolution; this.videoFormat = { format: this.videoFormat.format, order: this.videoFormat.order }; options.resolutions = { default: this.state.theSelectedQuality, options: this.videoResolutions, }; } // Set video playback speed info. if (this.state.theSelectedPlaybackSpeed) { this.videoPlaybackSpeeds = playbackSpeeds; options.playbackSpeeds = { default: this.state.theSelectedPlaybackSpeed, options: this.videoPlaybackSpeeds, }; } // Set video subtitles info. if (void 0 !== state.theSelectedSubtitleOption && null !== state.theSelectedSubtitleOption) { this.state.theSelectedSubtitleOption = state.theSelectedSubtitleOption; } if ( !!!options.subtitles || !!!options.subtitles.languages || !!!options.subtitles.languages.length || !options.subtitles.languages.length ) { options.subtitles = null; } else { options.subtitles.languages.unshift({ label: 'Off', srclang: 'off', src: null }); } this.subtitles = options.subtitles; // Set player actions animations components. setActionsAnimationsComponents(this, options, player); // Replace LoadingSpinner component. replaceLoadingSpinnerComponent(this); // Set corner layers components. setCornerLayersComponents(this, options); if (options.enabledTouchControls) { // Set player touch actions components. setTouchControlComponents(this, options); } // Set control bar components. setControlBarComponents(this, options, player); // Initial... this.csstransforms = browserSupports('csstransforms'); player.addClass('vjs-loading-video'); if (this.videoNativeDimensions) { player.addClass('vjs-native-dimensions'); } if (options.enabledTouchControls) { player.addClass('vjs-enabled-touch-controls'); } this.progressBarLine = null; this.onBandwidthUpdate = null; this.onHlsRetryPlaylist = null; // Set events listeners. if (options.keyboardControls) { this.player.el_.onkeyup = this.onKeyUp.bind(this); this.player.el_.onkeydown = this.onKeyDown.bind(this); } this.onError = this.onError.bind(this); this.on(player, ['error'], this.onError); this.on(player, ['dispose'], this.onDispose); // @todo: Make improvements based on 'dispose' result. this.on(player, ['ended'], this.onEnded); this.on(player, ['volumechange'], this.onVolumeChange); this.on(player, ['playing', 'pause'], this.onPlayToggle); this.on(player, ['timeupdate'], this.onTimeUpdateChange); this.on(player, ['fullscreenchange'], this.onFullscreenChange); this.on(player, ['theatermodechange'], this.onTheaterModeChange); this.on(player, ['openSettingsPanel'], this.openSettingsOptions); this.on(player, ['closeSettingsPanel'], this.closeSettingsOptions); this.on(player, ['openSubtitlesPanel'], this.openSubtitlesOptions); this.on(player, ['closeSubtitlesPanel'], this.closeSubtitlesOptions); this.on(player, ['openQualityOptions'], this.openQualityOptions); this.on(player, ['closeQualityOptions'], this.closeQualityOptions); this.on(player, ['openPlaybackSpeedOptions'], this.openPlaybackSpeedOptions); this.on(player, ['closePlaybackSpeedOptions'], this.closePlaybackSpeedOptions); this.on(player, ['selectedQuality'], this.onQualitySelection); this.on(player, ['selectedSubtitleOption'], this.onSubtitleOptionSelection); this.on(player, ['selectedPlaybackSpeed'], this.onPlaybackSpeedSelection); this.on(player, ['focusoutSettingsPanel'], this.onFocusOutSettingsPanel); this.on(player, ['focusoutSubtitlesPanel'], this.onFocusOutSubtitlesPanel); this.on(player, ['focusoutResolutionsPanel'], this.onFocusOutResolutionsPanel); this.on(player, ['focusoutPlaybackSpeedsPanel'], this.onFocusOutPlaybackSpeedsPanel); this.on(player, ['moveforward'], this.onMoveForward); this.on(player, ['movebackward'], this.onMoveBackward); this.on(player, ['userinactive'], this.onUserInactive); this.on(player, ['seeked'], this.onSeeked); this.on(player, ['seeking'], this.onSeeking); this.on('statechanged', this.onStateChange); this.hasPrevious = !!options.controlBar.previous; this.hasNext = !!options.controlBar.next; if (this.hasPrevious /*&& 'function' === typeof onPrevButtonClick*/) { this.on(player, ['clicked_previous_button'], this.onPreviousButtonClick); } if (this.hasNext /*&& 'function' === typeof onNextButtonClick*/) { this.on(player, ['clicked_next_button'], this.onNextButtonClick); } this.onPlayerReady = this.onPlayerReady.bind(this); player.ready(this.onPlayerReady); initElementsFocus(player); } onPreviousButtonClick() { if (this.hasPrevious) { this.actionAnimation('play_previous'); if (this.previousButtonClickCallback) { this.previousButtonClickCallback(); } } } onNextButtonClick() { if (this.hasNext) { this.actionAnimation('play_next'); if (this.nextButtonClickCallback) { this.nextButtonClickCallback(); } } } actionAnimation(action) { if (!this.player.hasStarted_) { return; } this.actionAnimElem = this.actionAnimElem || this.player.el_.querySelector('.vjs-actions-anim'); if (!this.actionAnimElem) { return; } let cls; switch (action) { case 'play': if ( void 0 !== this.previousActionAnim && 'forward' !== this.previousActionAnim && 'backward' !== this.previousActionAnim ) { cls = 'started-playing'; } break; case 'pause': cls = 'just-paused'; break; case 'backward': cls = 'moving-backward'; break; case 'forward': cls = 'moving-forward'; break; case 'volume': if (this.player.muted() || 0.001 >= this.player.volume()) { cls = 'volume-mute'; } else if (0.33 >= this.player.volume()) { cls = 'volume-low'; } else if (0.69 >= this.player.volume()) { cls = 'volume-mid'; } else { cls = 'volume-high'; } break; case 'play_previous': cls = 'play_previous'; break; case 'play_next': cls = 'play_next'; break; } if (!cls) { return; } if (this.actionAnimationTimeout) { this.actionAnimElem.setAttribute('class', 'vjs-actions-anim'); } setTimeout( function () { this.previousActionAnim = action; cls += ' active-anim'; clearTimeout(this.actionAnimationTimeout); this.actionAnimElem.setAttribute('class', 'vjs-actions-anim ' + cls); this.actionAnimationTimeout = setTimeout( function (ins) { ins.actionAnimElem.setAttribute('class', 'vjs-actions-anim'); ins.actionAnimationTimeout = null; ins.previousActionAnim = null; }, 750, this ); }.bind(this), this.actionAnimationTimeout ? 20 : 0 ); } onMoveForward() { this.actionAnimation('forward'); } onMoveBackward() { this.actionAnimation('backward'); } onKeyDown(e) { if (this.player.ended()) { // @todo: Should be better to unbind listeners on ended ...? Maybe not ...? return; } const key = e.keyCode || e.charCode; let found = false; switch (key) { case 32: // Play/Pause [Space]. this.player[this.player.paused() ? 'play' : 'pause'](); found = true; break; case 37: // Move backward [Arrow Left]. this.player.currentTime(this.player.currentTime() - 5 * this.state.theSelectedPlaybackSpeed); this.player.trigger('movebackward'); found = true; break; case 38: // Volume Up [Arrow Up]. if (this.player.muted()) { this.player.muted(false); } else { this.player.volume(Math.min(1, this.player.volume() + 0.03)); } found = true; break; case 39: // Move forward [Arrow Right]. this.player.currentTime(this.player.currentTime() + 5 * this.state.theSelectedPlaybackSpeed); this.player.trigger('moveforward'); found = true; break; case 40: // Volume Down [Arrow Down]. this.player.volume(Math.max(0, this.player.volume() - 0.03)); found = true; break; } if (found) { e.preventDefault(); e.stopPropagation(); } } onKeyUp(e) { if (this.player.ended()) { // @todo: Should be better to unbind listeners on ended ...? Maybe not ...? return; } const key = e.keyCode || e.charCode; let found = false; if (e.shiftKey) { switch (key) { case 78: // Next media [ shift + n ]. this.onNextButtonClick(); break; case 80: // Previous media [ shift + p ]. this.onPreviousButtonClick(); break; } } else if ((48 <= key && 57 >= key) || (96 <= key && 105 >= key)) { // Numbers from 0 to 9. this.player.currentTime(0.1 * (57 < key ? key - 96 : key - 48) * this.player.duration()); this.player.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); } else { switch (key) { case 75: // Play/Pause [k]. this.player[this.player.paused() ? 'play' : 'pause'](); found = true; break; case 70: // Enter - exit fullscreen mode [f]. if (this.enabledFullscreenToggle) { if (this.player.isFullscreen()) { this.player.exitFullscreen(); } else { this.player.requestFullscreen(); } found = true; } break; case 77: // Mute - unmute sound [m]. this.player.muted(!this.player.muted()); found = true; break; case 84: // Enable - disable theater mode [t]. if (this.enabledTheaterMode) { if (this.player.isFullscreen()) { this.player.exitFullscreen(); } this.player.trigger('theatermodechange'); } break; } } if (found) { e.preventDefault(); e.stopPropagation(); } } onUserInactive() { if (this.state.isOpenQualityOptions || this.state.isOpenPlaybackSpeedOptions || this.state.isOpenSettingsOptions) { this.player.trigger('closeSettingsPanel'); } } onSeeked() { this.seekingTimeout = setTimeout( function (ins) { ins.seeking = false; }, 300, this ); } onSeeking() { // console.log( "1." ); clearTimeout(this.seekingTimeout); this.seeking = true; if (!!this.progressBarLine) { this.progressBarLine.style.width = ((100 * this.player.currentTime()) / this.player.duration()).toFixed(2) + '%'; } } initDomEvents() { this.onWindowResize = this.onWindowResize.bind(this); window.addEventListener('resize', this.onWindowResize); this.videoHtmlElem.onloadeddata = this.onVideoDataLoad.bind(this); // Video has already loaded. if (4 === this.videoHtmlElem.readyState) { this.onVideoDataLoad(); } } onVideoMetaDataLoad() {} onVideoDataLoad() { if (this.videoPreviewThumb && !this.initedVideoPreviewThumb) { this.initedVideoPreviewThumb = true; videoPreviewThumb(this.player, this.videoPreviewThumb); } this.player.removeClass('vjs-loading-video'); if ('Auto' === this.state.theSelectedQuality) { if (!!this.player.tech_.hls && null === this.onBandwidthUpdate) { this.onBandwidthUpdate = this.onBandwidthUpdateCallback.bind(this); this.player.tech_.on('bandwidthupdate', this.onBandwidthUpdate); this.onBandwidthUpdateCallback(); } } else { if (null !== this.onBandwidthUpdate) { this.player.tech_.off('bandwidthupdate', this.onBandwidthUpdate); this.onBandwidthUpdate = null; } if (!!this.player.tech_.hls && null === this.onHlsRetryPlaylist) { // @note: Catch invalid playlists when selected resolution is not "Auto". this.onHlsRetryPlaylist = this.onHlsRetryPlaylistCallback.bind(this); this.player.tech_.on('retryplaylist', this.onHlsRetryPlaylist); } } if (this.isChangingResolution) { if (this.hadStartedOnResolutionChange) { this.player.hasStarted(true); this.player.removeClass('vjs-changing-resolution'); this.hadStartedOnResolutionChange = false; } if (this.wasPlayingOnResolutionChange) { this.player.play(); this.wasPlayingOnResolutionChange = false; } else { this.player.pause(); } this.isChangingResolution = false; } this.updateVideoElementPosition(); } onBandwidthUpdateCallback(ev) { this.onAutoQualitySelection(this.player.tech_.hls.playlists.media_.attributes.RESOLUTION.height); } onHlsRetryPlaylistCallback(ev) { if ('Auto' !== this.state.theSelectedQuality && void 0 !== this.videoResolutions['Auto']) { this.setState({ theSelectedQuality: 'Auto', }); } } /** * The method that'll be called when player is ready. * */ onPlayerReady() { // console.log( this.player.textTracks(), this.subtitles ); if (null !== this.subtitles) { const subtitleLanguages = []; let i; let track; let tracks = this.player.textTracks(); for (i = 0; i < tracks.length; i++) { subtitleLanguages.push(tracks[i].language); } i = 1; // Exclude 'off' language option. while (i < this.subtitles.languages.length) { if (-1 === subtitleLanguages.indexOf(this.subtitles.languages[i].srclang)) { // console.log('-A-'); this.player.addRemoteTextTrack({ kind: 'subtitles', label: this.subtitles.languages[i].label, language: this.subtitles.languages[i].srclang, src: this.subtitles.languages[i].src, }); } i += 1; } } // console.log( this.player.textTracks() ); // console.log( this.player.remoteTextTracks() ); this.changeVideoSubtitle(); this.progressBarLine = this.player.el_.querySelector('.video-js .vjs-progress-holder .vjs-play-progress'); // Initialize events. this.initDomEvents(); // Apply player settings. this.player.volume(this.state.volume); this.player.muted(this.state.soundMuted); this.player.playbackRate(this.state.theSelectedPlaybackSpeed); // Apply classname in DOM elements. this.player.addClass('vjs-mediacms-plugin'); this.updateTheaterModeClassname(); // Trigger states changes, if need. setTimeout( function (ins) { ins.updateVideoPlayerRatios(); }, 100, this ); } changeVideoSubtitle() { // console.log( this.player.textTracks() ); // console.log( this.player.textTrackDisplay ); // console.log( this.player.textTrackSettings ); if ('off' !== this.state.theSelectedSubtitleOption) { this.player.removeClass('vjs-subtitles-off'); this.player.addClass('vjs-subtitles-on'); } else { this.player.removeClass('vjs-subtitles-on'); this.player.addClass('vjs-subtitles-off'); } const tracks = this.player.textTracks(); for (let i = 0; i < tracks.length; i++) { // console.log( tracks[i].kind, tracks[i].language, tracks[i].label ); if ('subtitles' === tracks[i].kind) { tracks[i].mode = this.state.theSelectedSubtitleOption === tracks[i].language ? 'showing' : 'hidden'; // console.log( tracks[i].mode ); } } } changeVideoResolution() { this.isChangingResolution = true; const sources = []; const currentTime = this.player.currentTime(); const duration = this.player.duration(); this.wasPlayingOnResolutionChange = !this.player.paused(); this.hadStartedOnResolutionChange = this.player.hasStarted(); if (this.hadStartedOnResolutionChange) { this.player.addClass('vjs-changing-resolution'); } /*if( this.wasPlayingOnResolutionChange ){ this.player.pause(); }*/ let i = 0; while (i < this.videoResolutions[this.state.theSelectedQuality].src.length) { sources.push({ src: this.videoResolutions[this.state.theSelectedQuality].src[i] }); i += 1; } this.player.src(sources); // @note: Load all sources (with provided order). this.player.techCall_('reset'); this.player.currentTime(currentTime); this.player.duration(duration); this.player.playbackRate(this.state.theSelectedPlaybackSpeed); } changePlaybackSpeed() { this.player.playbackRate(this.state.theSelectedPlaybackSpeed); } onStateChange(d) { if (d.changes.videoRatio || d.changes.playerRatio) { this.updateVideoElementPosition(); } if (d.changes.volume) { this.onPublicStateUpdate(); } if (d.changes.soundMuted) { this.onPublicStateUpdate(); } if (d.changes.theaterMode) { this.onPublicStateUpdate(); } if (d.changes.theaterMode) { this.updateTheaterModeClassname(); // @note: Need this delay to allow complete function 'updateTheaterModeClassname'. setTimeout( function (ins) { ins.updateVideoPlayerRatios(); }, 20, this ); } if (d.changes.isOpenSettingsOptions) { } if (d.changes.isOpenQualityOptions) { } if (d.changes.isOpenPlaybackSpeedOptions) { } if (d.changes.theSelectedSubtitleOption) { this.changeVideoSubtitle(); this.player.trigger('updatedSelectedSubtitleOption'); this.onPublicStateUpdate(); } if (d.changes.theSelectedQuality) { this.changeVideoResolution(); this.player.trigger('updatedSelectedQuality'); this.onPublicStateUpdate(); } if (d.changes.theSelectedPlaybackSpeed) { this.changePlaybackSpeed(); this.player.trigger('updatedSelectedPlaybackSpeed'); this.onPublicStateUpdate(); } if ( d.changes.isOpenSettingsOptions || d.changes.isOpenQualityOptions || d.changes.theSelectedQuality || d.changes.isOpenPlaybackSpeedOptions || d.changes.theSelectedPlaybackSpeed ) { this.player.trigger('updatedSettingsPanelsVisibility'); } if (d.changes.isOpenSubtitlesOptions) { this.player.trigger('updatedSubtitlesPanelsVisibility'); } if (d.changes.openSettings) { if (this.state.openSettings) { this.player.trigger('openedSettingsPanel', this.state.openSettingsFromKeyboard); } } if (d.changes.closeSettings) { if (this.state.closeSettings) { this.player.trigger('closedSettingsPanel', this.state.closeSettingsFromKeyboard); } } if (d.changes.openSubtitles) { if (this.state.openSubtitles) { this.player.trigger('openedSubtitlesPanel', this.state.openSubtitlesFromKeyboard); } } if (d.changes.closeSubtitles) { if (this.state.closeSubtitles) { this.player.trigger('closedSubtitlesPanel', this.state.closeSubtitlesFromKeyboard); } } if (d.changes.openQualities) { if (this.state.openQualities) { this.player.trigger('openedQualities', this.state.openQualitiesFromKeyboard); } } if (d.changes.closeQualities) { if (this.state.closeQualities) { this.player.trigger('closedQualities', this.state.closeQualitiesFromKeyboard); } } if (d.changes.openPlaybackSpeeds) { if (this.state.openPlaybackSpeeds) { this.player.trigger('openedPlaybackSpeeds', this.state.openPlaybackSpeedsFromKeyboard); } } if (d.changes.closePlaybackSpeeds) { if (this.state.closePlaybackSpeeds) { this.player.trigger('closedPlaybackSpeeds', this.state.closePlaybackSpeedsFromKeyboard); } } } onDispose() { window.removeEventListener('resize', this.onWindowResize); } onError(e) { if (!this.player.paused()) { this.player.pause(); } this.player.techCall_('reset'); } /** * The method that will be called on playback complete. * */ onEnded() { this.setState(this.state, { ended: !0, }); } /** * The method that will be called on player's volume change. * */ onVolumeChange() { this.setState({ volume: this.player.volume(), soundMuted: this.player.muted(), }); this.actionAnimation('volume'); } /** * The method that will be called on player's "playing" state change. * */ onPlayToggle(ev) { const playing = 'playing' === ev.type; if (!this.seeking && 1 > Math.abs(this.updateTimeDiff)) { this.actionAnimation(!playing ? 'pause' : 'play'); } this.setState({ playing: playing, }); } onTimeUpdateChange(ev) { const ct = this.player.currentTime(); this.updateTimeDiff = ct - this.updateTime; this.updateTime = ct; } /** * Appends in player's classname the class "vjs-fullscreen-change" for 0.1 second on changing fullscreen state. * */ onFullscreenChange() { this.player.addClass('vjs-fullscreen-change'); setTimeout( function (plr) { plr.removeClass('vjs-fullscreen-change'); }, 100, this.player ); this.updateVideoElementPosition(); } /** * The method that will be called on player's "theater mode" state change. * */ onTheaterModeChange() { this.setState({ theaterMode: !this.state.theaterMode, }); } openSettingsOptions(ev, triggeredFromKeyboard) { clearTimeout(this.timeoutSettingsPanelFocusout); this.setState({ openSettings: new Date(), openSettingsFromKeyboard: triggeredFromKeyboard ? new Date() : !1, isOpenSettingsOptions: !0, isOpenQualityOptions: !1, isOpenPlaybackSpeedOptions: !1, isOpenSubtitlesOptions: !1, }); } closeSettingsOptions(ev, triggeredFromKeyboard) { clearTimeout(this.timeoutSettingsPanelFocusout); this.setState({ closeSettings: new Date(), closeSettingsFromKeyboard: triggeredFromKeyboard ? new Date() : !1, isOpenSettingsOptions: !1, isOpenQualityOptions: !1, isOpenPlaybackSpeedOptions: !1, }); } openSubtitlesOptions(ev, triggeredFromKeyboard) { clearTimeout(this.timeoutSubtitlesPanelFocusout); this.setState({ openSubtitles: new Date(), openSubtitlesFromKeyboard: triggeredFromKeyboard ? new Date() : !1, isOpenSubtitlesOptions: !0, isOpenSettingsOptions: !1, isOpenQualityOptions: !1, isOpenPlaybackSpeedOptions: !1, }); } closeSubtitlesOptions(ev, triggeredFromKeyboard) { clearTimeout(this.timeoutSubtitlesPanelFocusout); this.setState({ closeSubtitles: new Date(), closeSubtitlesFromKeyboard: triggeredFromKeyboard ? new Date() : !1, isOpenSubtitlesOptions: !1, }); } openQualityOptions(ev, triggeredFromKeyboard) { clearTimeout(this.timeoutResolutionsPanelFocusout); this.setState({ openQualities: new Date(), openQualitiesFromKeyboard: triggeredFromKeyboard ? new Date() : !1, isOpenSettingsOptions: !1, isOpenQualityOptions: !0, }); } openPlaybackSpeedOptions(ev, triggeredFromKeyboard) { clearTimeout(this.timeoutPlaybackSpeedsPanelFocusout); this.setState({ openPlaybackSpeeds: new Date(), openPlaybackSpeedsFromKeyboard: triggeredFromKeyboard ? new Date() : !1, isOpenSettingsOptions: !1, isOpenPlaybackSpeedOptions: !0, }); } closeQualityOptions(ev, triggeredFromKeyboard) { clearTimeout(this.timeoutResolutionsPanelFocusout); this.setState({ closeQualities: new Date(), closeQualitiesFromKeyboard: triggeredFromKeyboard ? new Date() : !1, openSettings: new Date(), openSettingsFromKeyboard: triggeredFromKeyboard ? new Date() : !1, isOpenSettingsOptions: !0, isOpenQualityOptions: !1, }); } closePlaybackSpeedOptions(ev, triggeredFromKeyboard) { clearTimeout(this.timeoutPlaybackSpeedsPanelFocusout); this.setState({ closePlaybackSpeeds: new Date(), closePlaybackSpeedsFromKeyboard: triggeredFromKeyboard ? new Date() : !1, openSettings: new Date(), openSettingsFromKeyboard: triggeredFromKeyboard ? new Date() : !1, isOpenSettingsOptions: !0, isOpenPlaybackSpeedOptions: !1, }); } onQualitySelection(ev, newQuality) { this.setState({ isOpenSettingsOptions: !1, isOpenQualityOptions: !1, theSelectedQuality: newQuality, }); } onSubtitleOptionSelection(ev, newSelection) { this.setState({ isOpenSubtitlesOptions: !1, theSelectedSubtitleOption: newSelection, }); } onAutoQualitySelection(newAutoQuality) { if (newAutoQuality !== this.state.theSelectedAutoQuality) { this.setState({ theSelectedAutoQuality: newAutoQuality, }); this.player.trigger('updatedSelectedQuality'); } } onPlaybackSpeedSelection(ev, newPlaybackSpeed) { this.setState({ isOpenSettingsOptions: !1, isOpenPlaybackSpeedOptions: !1, theSelectedPlaybackSpeed: newPlaybackSpeed, }); } onFocusOutSubtitlesPanel() { if (this.timeoutSubtitlesPanelFocusout) { return; } this.player.focus(); // TODO: Remove all this kind of focus(es). Before removal, test the players in MediaCMS, while the window has scrolled down. this.timeoutSubtitlesPanelFocusout = setTimeout( function (ins) { ins.setState({ isOpenSubtitlesOptions: !1, }); ins.timeoutSubtitlesPanelFocusout = null; }, 100, this ); } onFocusOutSettingsPanel() { if (this.timeoutSettingsPanelFocusout) { return; } if (!this.state.isOpenQualityOptions && !this.state.isOpenPlaybackSpeedOptions) { this.player.focus(); } if (!this.state.isOpenQualityOptions) { this.timeoutSettingsPanelFocusout = setTimeout( function (ins) { if (ins.state.isOpenSettingsOptions && !ins.state.isOpenQualityOptions) { ins.setState({ isOpenSettingsOptions: !1, }); } ins.timeoutSettingsPanelFocusout = null; }, 100, this ); } else if (!this.state.isOpenPlaybackSpeedOptions) { this.timeoutSettingsPanelFocusout = setTimeout( function (ins) { if (ins.state.isOpenSettingsOptions && !ins.state.isOpenPlaybackSpeedOptions) { ins.setState({ isOpenSettingsOptions: !1, }); } ins.timeoutSettingsPanelFocusout = null; }, 100, this ); } } onFocusOutResolutionsPanel() { if (this.timeoutResolutionsPanelFocusout) { return; } if (!this.state.isOpenSettingsOptions && !this.state.isOpenPlaybackSpeedOptions) { this.player.focus(); } if (!this.state.isOpenSettingsOptions) { this.timeoutResolutionsPanelFocusout = setTimeout( function (ins) { if (ins.state.isOpenQualityOptions && !ins.state.isOpenSettingsOptions) { ins.setState({ isOpenQualityOptions: !1, }); } ins.timeoutResolutionsPanelFocusout = null; }, 100, this ); } } onFocusOutPlaybackSpeedsPanel() { if (this.timeoutPlaybackSpeedsPanelFocusout) { return; } if (!this.state.isOpenQualityOptions && !this.state.isOpenSettingsOptions) { this.player.focus(); } if (!this.state.isOpenSettingsOptions) { this.timeoutPlaybackSpeedsPanelFocusout = setTimeout( function (ins) { if (ins.state.isOpenPlaybackSpeedOptions && !ins.state.isOpenSettingsOptions) { ins.setState({ isOpenPlaybackSpeedOptions: !1, }); } ins.timeoutPlaybackSpeedsPanelFocusout = null; }, 100, this ); } } /** * The method that will be called on change one of public (accessible from plugin's instance) state values. * */ onPublicStateUpdate() { if (this.stateUpdateCallback) { this.stateUpdateCallback({ volume: this.state.volume, theaterMode: this.state.theaterMode, soundMuted: this.state.soundMuted, quality: this.state.theSelectedQuality, playbackSpeed: this.state.theSelectedPlaybackSpeed, subtitle: this.state.theSelectedSubtitleOption, }); } } onWindowResize() { this.updateVideoPlayerRatios(); } updateVideoPlayerRatios() { this.setState({ videoRatio: this.videoHtmlElem.offsetWidth / this.videoHtmlElem.offsetHeight, playerRatio: this.player.el_.offsetWidth / this.player.el_.offsetHeight, }); var settingsPanelInner = document.querySelectorAll('.vjs-settings-panel-inner'); if (settingsPanelInner.length) { var i = 0; while (i < settingsPanelInner.length) { settingsPanelInner[i].style.maxHeight = this.videoHtmlElem.offsetHeight - 120 + 'px'; i += 1; } } } /** * Updates player's class attribute value (in DOM), based on "theater mode" state value. * */ updateTheaterModeClassname() { this.player[this.state.theaterMode ? 'addClass' : 'removeClass']('vjs-theater-mode'); } updateVideoElementPosition() { if (this.videoHtmlElem) { if (this.videoNativeDimensions) { const newval = centralizeBoxPosition( this.videoHtmlElem.offsetWidth, this.videoHtmlElem.offsetHeight, this.state.videoRatio, this.player.el_.offsetWidth, this.player.el_.offsetHeight, this.state.playerRatio ); // @note: Don't need because we are set in CSS the properties "max-width:100%;" and "max-height:100%;" of