diff --git a/src/core/default-modules.ts b/src/core/default-modules.ts index 0657d2b5..245d1795 100644 --- a/src/core/default-modules.ts +++ b/src/core/default-modules.ts @@ -21,6 +21,7 @@ import KeyboardControls from '../modules/keyboard-control/keyboard-control'; import DebugPanel from '../modules/ui/debug-panel/debug-panel'; import Screen, { IScreenAPI } from '../modules/ui/screen/screen'; +import FocusScreen from '../modules/ui/focus-screen/focus-screen'; import InteractionIndicator from '../modules/ui/interaction-indicator/interaction-indicator'; import Overlay, { IOverlayAPI } from '../modules/ui/overlay/overlay'; @@ -99,6 +100,7 @@ export const modules: { [id: string]: any } = { DebugPanel, Screen, + FocusScreen, InteractionIndicator, Overlay, diff --git a/src/modules/keyboard-control/keyboard-control.ts b/src/modules/keyboard-control/keyboard-control.ts index cf4b6ca8..1c794220 100644 --- a/src/modules/keyboard-control/keyboard-control.ts +++ b/src/modules/keyboard-control/keyboard-control.ts @@ -14,15 +14,15 @@ import { IEventEmitter } from '../event-emitter/types'; import { IPlaybackEngine } from '../playback-engine/types'; import { IPlayerConfig } from '../../core/config'; import { IKeyboardControl } from './types'; -import { IRootContainer } from '../root-container/types'; import { ListenerFn } from 'eventemitter3'; +import { IFocusScreen } from '../ui/focus-screen/types'; export const AMOUNT_TO_SKIP_SECONDS = 5; export const AMOUNT_TO_CHANGE_VOLUME = 10; export default class KeyboardControl implements IKeyboardControl { static moduleName = 'keyboardControl'; - static dependencies = ['engine', 'eventEmitter', 'rootContainer', 'config']; + static dependencies = ['engine', 'eventEmitter', 'focusScreen', 'config']; private _isEnabled: boolean; private _eventEmitter: IEventEmitter; @@ -32,12 +32,12 @@ export default class KeyboardControl implements IKeyboardControl { constructor({ config, eventEmitter, - rootContainer, + focusScreen, engine, }: { config: IPlayerConfig; eventEmitter: IEventEmitter; - rootContainer: IRootContainer; + focusScreen: IFocusScreen; engine: IPlaybackEngine; }) { this._eventEmitter = eventEmitter; @@ -49,7 +49,7 @@ export default class KeyboardControl implements IKeyboardControl { this._isEnabled = config.disableControlWithKeyboard !== false; } - this._initInterceptor(rootContainer.getElement()); + this._initInterceptor(focusScreen.getElement()); } private _initInterceptor(rootElement: HTMLElement) { diff --git a/src/modules/root-container/templates/container.dot b/src/modules/root-container/templates/container.dot index f2462f50..352443d7 100644 --- a/src/modules/root-container/templates/container.dot +++ b/src/modules/root-container/templates/container.dot @@ -2,6 +2,5 @@ data-playable-hook="player-container" dir="ltr" data-playable-dir="${props.direction}" - tabindex="0" class="${props.styles.container}"> diff --git a/src/modules/ui/focus-screen/focus-screen.scss b/src/modules/ui/focus-screen/focus-screen.scss new file mode 100644 index 00000000..b3e1fc9f --- /dev/null +++ b/src/modules/ui/focus-screen/focus-screen.scss @@ -0,0 +1,25 @@ +@import '../shared'; + +.focusScreen { + position: absolute; + z-index: 51; + top: 0; + right: 0; + bottom: 0; + left: 0; + + display: flex; + flex-direction: column; + + width: 100%; + height: 100%; + + opacity: 1; + + justify-content: center; + align-items: center; + + &.hiddenCursor { + cursor: none; + } +} diff --git a/src/modules/ui/focus-screen/focus-screen.spec.ts b/src/modules/ui/focus-screen/focus-screen.spec.ts new file mode 100644 index 00000000..4bfffc5d --- /dev/null +++ b/src/modules/ui/focus-screen/focus-screen.spec.ts @@ -0,0 +1,118 @@ +import 'jsdom-global/register'; +import { expect } from 'chai'; +import * as sinon from 'sinon'; + +import { EngineState } from '../../../constants'; + +import createPlayerTestkit from '../../../testkit'; + +import FocusScreen from './focus-screen'; +class FullScreenManagerMock { + enterFullScreen = (_: any) => _; + exitFullScreen = (_: any) => _; + isInFullScreen = false; + isEnabled = true; + _config = {}; +} + +describe('Loader', () => { + let testkit: any; + let screen: any; + let engine: any; + let fullScreenManager: any; + + beforeEach(() => { + testkit = createPlayerTestkit(); + testkit.registerModuleAsSingleton( + 'fullScreenManager', + FullScreenManagerMock, + ); + testkit.registerModule('focus-screen', FocusScreen); + engine = testkit.getModule('engine'); + fullScreenManager = testkit.getModule('fullScreenManager'); + screen = testkit.getModule('focus-screen'); + }); + + describe('constructor', () => { + it('should create instance ', () => { + expect(screen).to.exist; + expect(screen.view).to.exist; + }); + }); + + describe('instance callbacks', () => { + it('should trigger _toggleVideoPlayback on node click', () => { + const processClickSpy = sinon.spy(screen, '_processClick'); + screen._bindCallbacks(); + screen._initUI(); + + screen.view.getElement().dispatchEvent(new Event('click')); + expect(processClickSpy.called).to.be.true; + }); + + it('should remove timeout of delayed playback change on _processClick and call _toggleFullScreen on _processDblClick', () => { + const timeoutClearSpy = sinon.spy( + window, + 'clearTimeout', + ); + const toggleFullScreenSpy = sinon.spy(screen, '_toggleFullScreen'); + const id = window.setTimeout(() => {}, 0); + screen._delayedToggleVideoPlaybackTimeout = id; + + screen._processClick(); + expect(timeoutClearSpy.calledWith(id)).to.be.true; + screen._processDblClick(); + expect(toggleFullScreenSpy.called).to.be.true; + + timeoutClearSpy.restore(); + }); + + it('should add native controls if config passed', () => { + testkit.setConfig({ + nativeBrowserControls: true, + }); + + const video: any = document.createElement('video'); + + video.setAttribute = sinon.spy(); + + engine.getElement = () => video; + + screen = testkit.getModule('screen'); + + expect(video.setAttribute.calledWith('controls', 'true')).to.be.true; + }); + + it('should emit ui event on enter full screen', () => { + const spy = sinon.spy(fullScreenManager, 'enterFullScreen'); + fullScreenManager.isInFullScreen = false; + + screen._toggleFullScreen(); + + expect(spy.called).to.be.true; + fullScreenManager.enterFullScreen.restore(); + }); + + it('should emit ui event on exit full screen', () => { + const spy = sinon.spy(fullScreenManager, 'exitFullScreen'); + fullScreenManager.isInFullScreen = true; + + screen._toggleFullScreen(); + + expect(spy.called).to.be.true; + fullScreenManager.exitFullScreen.restore(); + }); + + it('should have method for toggling playback', () => { + const playSpy = sinon.spy(); + const pauseSpy = sinon.spy(); + screen._engine = { + getCurrentState: () => EngineState.PLAYING, + play: playSpy, + pause: pauseSpy, + }; + screen._toggleVideoPlayback(); + expect(pauseSpy.called).to.be.true; + }); + }); +}); diff --git a/src/modules/ui/focus-screen/focus-screen.ts b/src/modules/ui/focus-screen/focus-screen.ts new file mode 100644 index 00000000..68d3d014 --- /dev/null +++ b/src/modules/ui/focus-screen/focus-screen.ts @@ -0,0 +1,223 @@ +import { UIEvent, EngineState } from '../../../constants'; + +import View from './focus-screen.view'; + +import { IEventEmitter } from '../../event-emitter/types'; +import { IFullScreenManager } from '../../full-screen-manager/types'; +import { IPlaybackEngine } from '../../playback-engine/types'; +import { IInteractionIndicator } from '../interaction-indicator/types'; +import { IPlayerConfig } from '../../../core/config'; +import { IRootContainer } from '../../root-container/types'; +import { IFocusScreen, IFocusScreenViewConfig } from './types'; + +const PLAYBACK_CHANGE_TIMEOUT = 300; + +class FocusScreen implements IFocusScreen { + static moduleName = 'focusScreen'; + static View = View; + static dependencies = [ + 'engine', + 'eventEmitter', + 'config', + 'fullScreenManager', + 'interactionIndicator', + 'rootContainer', + ]; + + private _eventEmitter: IEventEmitter; + private _engine: IPlaybackEngine; + private _fullScreenManager: IFullScreenManager; + private _interactionIndicator: IInteractionIndicator; + + private _delayedToggleVideoPlaybackTimeout: number; + + private _isClickProcessingDisabled: boolean; + + private _unbindEvents: () => void; + + view: View; + isHidden: boolean; + + constructor({ + config, + eventEmitter, + engine, + fullScreenManager, + interactionIndicator, + rootContainer, + }: { + config: IPlayerConfig; + eventEmitter: IEventEmitter; + engine: IPlaybackEngine; + fullScreenManager: IFullScreenManager; + interactionIndicator: IInteractionIndicator; + rootContainer: IRootContainer; + }) { + this._eventEmitter = eventEmitter; + this._engine = engine; + this._fullScreenManager = fullScreenManager; + this._interactionIndicator = interactionIndicator; + + this.isHidden = false; + + this._delayedToggleVideoPlaybackTimeout = null; + + this._isClickProcessingDisabled = Boolean( + config.disableControlWithClickOnPlayer, + ); + + this._bindCallbacks(); + this._initUI(); + this._bindEvents(); + + rootContainer.appendComponentElement(this.getElement()); + } + + getElement() { + return this.view.getElement(); + } + + private _bindCallbacks() { + this._processClick = this._processClick.bind(this); + this._processDblClick = this._processDblClick.bind(this); + this._toggleVideoPlayback = this._toggleVideoPlayback.bind(this); + } + + private _initUI() { + const config: IFocusScreenViewConfig = { + callbacks: { + onWrapperMouseClick: this._processClick, + onWrapperMouseDblClick: this._processDblClick, + }, + }; + + this.view = new View(config); + } + + private _bindEvents() { + this._unbindEvents = this._eventEmitter.bindEvents( + [[UIEvent.PLAY_OVERLAY_CLICK, this.view.focusOnNode, this.view]], + this, + ); + } + + showCursor() { + this.view.showCursor(); + } + + hideCursor() { + this.view.hideCursor(); + } + + private _processClick() { + if (this._isClickProcessingDisabled) { + return; + } + + this._showPlaybackChangeIndicator(); + + if (!this._fullScreenManager.isEnabled) { + this._toggleVideoPlayback(); + } else { + this._setDelayedPlaybackToggle(); + } + } + + private _processDblClick() { + if (this._isClickProcessingDisabled) { + return; + } + + if (this._fullScreenManager.isEnabled) { + if (this._isDelayedPlaybackToggleExist) { + this._clearDelayedPlaybackToggle(); + this._hideDelayedPlaybackChangeIndicator(); + } + + this._toggleFullScreen(); + } + } + + private _showPlaybackChangeIndicator() { + const state = this._engine.getCurrentState(); + + if (state === EngineState.PLAY_REQUESTED || state === EngineState.PLAYING) { + this._interactionIndicator.showPause(); + } else { + this._interactionIndicator.showPlay(); + } + } + + private _hideDelayedPlaybackChangeIndicator() { + this._interactionIndicator.hideIcons(); + } + + private _setDelayedPlaybackToggle() { + this._clearDelayedPlaybackToggle(); + + this._delayedToggleVideoPlaybackTimeout = window.setTimeout( + this._toggleVideoPlayback, + PLAYBACK_CHANGE_TIMEOUT, + ); + } + + private _clearDelayedPlaybackToggle() { + window.clearTimeout(this._delayedToggleVideoPlaybackTimeout); + this._delayedToggleVideoPlaybackTimeout = null; + } + + private get _isDelayedPlaybackToggleExist() { + return Boolean(this._delayedToggleVideoPlaybackTimeout); + } + + private _toggleVideoPlayback() { + this._clearDelayedPlaybackToggle(); + + const state = this._engine.getCurrentState(); + + if (state === EngineState.PLAY_REQUESTED || state === EngineState.PLAYING) { + this._engine.pause(); + this._eventEmitter.emitAsync(UIEvent.PAUSE_WITH_SCREEN_CLICK); + } else { + this._engine.play(); + this._eventEmitter.emitAsync(UIEvent.PLAY_WITH_SCREEN_CLICK); + } + } + + private _toggleFullScreen() { + if (this._fullScreenManager.isInFullScreen) { + this._fullScreenManager.exitFullScreen(); + this._eventEmitter.emitAsync(UIEvent.EXIT_FULL_SCREEN_WITH_SCREEN_CLICK); + } else { + this._fullScreenManager.enterFullScreen(); + this._eventEmitter.emitAsync(UIEvent.ENTER_FULL_SCREEN_WITH_SCREEN_CLICK); + } + } + + hide() { + if (!this.isHidden) { + this.view.hide(); + this.isHidden = true; + } + } + + show() { + if (this.isHidden) { + this.view.show(); + this.isHidden = false; + } + } + + focus() { + this.view.focusOnNode(); + } + + destroy() { + this._unbindEvents(); + + this._clearDelayedPlaybackToggle(); + this.view.destroy(); + } +} + +export default FocusScreen; diff --git a/src/modules/ui/focus-screen/focus-screen.view.ts b/src/modules/ui/focus-screen/focus-screen.view.ts new file mode 100644 index 00000000..fc4812b3 --- /dev/null +++ b/src/modules/ui/focus-screen/focus-screen.view.ts @@ -0,0 +1,99 @@ +import View from '../core/view'; +import { IView } from '../core/types'; + +import { focusScreenTemplate } from './templates'; + +import htmlToElement from '../core/htmlToElement'; +import toggleElementClass from '../core/toggleElementClass'; + +import { + IFocusScreenViewStyles, + IFocusScreenViewCallbacks, + IFocusScreenViewConfig, +} from './types'; + +import styles from './focus-screen.scss'; + +class ScreenView extends View + implements IView { + private _callbacks: IFocusScreenViewCallbacks; + + private _$rootElement: HTMLElement; + + constructor(config: IFocusScreenViewConfig) { + super(); + const { callbacks } = config; + + this._callbacks = callbacks; + + this._initDOM(); + this._bindEvents(); + } + + private _initDOM() { + this._$rootElement = htmlToElement( + focusScreenTemplate({ + styles: this.styleNames, + }), + ); + } + + private _bindEvents() { + this._$rootElement.addEventListener( + 'click', + this._callbacks.onWrapperMouseClick, + ); + this._$rootElement.addEventListener( + 'dblclick', + this._callbacks.onWrapperMouseDblClick, + ); + } + + private _unbindEvents() { + this._$rootElement.removeEventListener( + 'click', + this._callbacks.onWrapperMouseClick, + ); + this._$rootElement.removeEventListener( + 'dblclick', + this._callbacks.onWrapperMouseDblClick, + ); + } + + focusOnNode() { + this._$rootElement.focus(); + } + + show() { + toggleElementClass(this._$rootElement, this.styleNames.hidden, false); + } + + hide() { + toggleElementClass(this._$rootElement, this.styleNames.hidden, true); + } + + getElement() { + return this._$rootElement; + } + + hideCursor() { + toggleElementClass(this._$rootElement, this.styleNames.hiddenCursor, true); + } + + showCursor() { + toggleElementClass(this._$rootElement, this.styleNames.hiddenCursor, false); + } + + destroy() { + this._unbindEvents(); + if (this._$rootElement.parentNode) { + this._$rootElement.parentNode.removeChild(this._$rootElement); + } + + this._$rootElement = null; + } +} + +ScreenView.extendStyleNames(styles); + +export default ScreenView; diff --git a/src/modules/ui/focus-screen/templates/focus-screen.dot b/src/modules/ui/focus-screen/templates/focus-screen.dot new file mode 100644 index 00000000..665269c9 --- /dev/null +++ b/src/modules/ui/focus-screen/templates/focus-screen.dot @@ -0,0 +1,6 @@ +
+
diff --git a/src/modules/ui/focus-screen/templates/index.ts b/src/modules/ui/focus-screen/templates/index.ts new file mode 100644 index 00000000..e509e8fe --- /dev/null +++ b/src/modules/ui/focus-screen/templates/index.ts @@ -0,0 +1,3 @@ +import template from './focus-screen.dot'; +const focusScreenTemplate = template.default ? template.default : template; +export { focusScreenTemplate }; diff --git a/src/modules/ui/focus-screen/types.ts b/src/modules/ui/focus-screen/types.ts new file mode 100644 index 00000000..7a8ef659 --- /dev/null +++ b/src/modules/ui/focus-screen/types.ts @@ -0,0 +1,34 @@ +type IFocusScreenViewStyles = { + focusScreen: string; + hiddenCursor: string; + hidden: string; +}; + +type IFocusScreenViewCallbacks = { + onWrapperMouseClick: EventListenerOrEventListenerObject; + onWrapperMouseDblClick: EventListenerOrEventListenerObject; +}; + +type IFocusScreenViewConfig = { + callbacks: IFocusScreenViewCallbacks; +}; + +interface IFocusScreen { + getElement(): HTMLElement; + showCursor(): void; + hideCursor(): void; + + show(): void; + hide(): void; + + focus(): void; + + destroy(): void; +} + +export { + IFocusScreen, + IFocusScreenViewStyles, + IFocusScreenViewCallbacks, + IFocusScreenViewConfig, +}; diff --git a/src/modules/ui/main-ui-block/main-ui-block.ts b/src/modules/ui/main-ui-block/main-ui-block.ts index 2d087456..270b7e05 100644 --- a/src/modules/ui/main-ui-block/main-ui-block.ts +++ b/src/modules/ui/main-ui-block/main-ui-block.ts @@ -11,10 +11,10 @@ import { import { IEventEmitter } from '../../event-emitter/types'; import { IBottomBlock } from '../bottom-block/types'; import { ITopBlock } from '../top-block/types'; -import { IScreen } from '../screen/types'; import { IPlayerConfig } from '../../../core/config'; import { IRootContainer } from '../../root-container/types'; import { ITooltipService } from '../core/tooltip/tooltip-service'; +import { IFocusScreen } from '../focus-screen/types'; const HIDE_BLOCK_TIMEOUT = 2000; @@ -23,7 +23,7 @@ class MainUIBlock implements IMainUIBlock { static View = MainUIBlockView; static dependencies = [ 'config', - 'screen', + 'focusScreen', 'rootContainer', 'tooltipService', 'eventEmitter', @@ -34,7 +34,7 @@ class MainUIBlock implements IMainUIBlock { private _eventEmitter: IEventEmitter; private _bottomBlock: IBottomBlock; private _topBlock: ITopBlock; - private _screen: IScreen; + private _focusScreen: IFocusScreen; private _tooltipService: ITooltipService; private _hideTimeout: number = null; @@ -59,7 +59,7 @@ class MainUIBlock implements IMainUIBlock { tooltipService: ITooltipService; topBlock: ITopBlock; bottomBlock: IBottomBlock; - screen: IScreen; + focusScreen: IFocusScreen; }) { const { config, @@ -68,15 +68,15 @@ class MainUIBlock implements IMainUIBlock { tooltipService, topBlock, bottomBlock, - screen, + focusScreen, } = dependencies; this._config = config; this._eventEmitter = eventEmitter; this._topBlock = topBlock; this._bottomBlock = bottomBlock; - this._screen = screen; this._tooltipService = tooltipService; + this._focusScreen = focusScreen; this.isHidden = false; @@ -191,7 +191,7 @@ class MainUIBlock implements IMainUIBlock { } private _showContent() { - this._screen.showCursor(); + this._focusScreen.showCursor(); if (this.isHidden || this._isContentShown) { return; @@ -216,7 +216,7 @@ class MainUIBlock implements IMainUIBlock { private _hideContent() { if (this._isContentShowingEnabled) { - this._screen.hideCursor(); + this._focusScreen.hideCursor(); } if (this.isHidden || !this._isContentShown) { @@ -253,6 +253,7 @@ class MainUIBlock implements IMainUIBlock { this.isHidden = true; this._topBlock.hide(); this._bottomBlock.hide(); + this._focusScreen.hide(); } /** @@ -278,6 +279,7 @@ class MainUIBlock implements IMainUIBlock { this.isHidden = false; this._topBlock.show(); this._bottomBlock.show(); + this._focusScreen.show(); } /** diff --git a/src/modules/ui/overlay/overlay.ts b/src/modules/ui/overlay/overlay.ts index 89b7b0e7..15c0c0b8 100644 --- a/src/modules/ui/overlay/overlay.ts +++ b/src/modules/ui/overlay/overlay.ts @@ -11,6 +11,7 @@ import { IRootContainer } from '../../root-container/types'; import { IPlayerConfig } from '../../../core/config'; import { IMainUIBlock } from '../main-ui-block/types'; import { ILoader } from '../loader/types'; +import { IFocusScreen } from '../focus-screen/types'; class Overlay implements IOverlay { static moduleName = 'overlay'; @@ -22,6 +23,7 @@ class Overlay implements IOverlay { 'theme', 'config', 'mainUIBlock', + 'focusScreen', 'loader', ]; @@ -29,10 +31,11 @@ class Overlay implements IOverlay { private _engine: IPlaybackEngine; private _theme: IThemeService; private _loader: ILoader; + private _mainUIBlock: IMainUIBlock; + private _focusScreen: IFocusScreen; private _unbindEvents: () => void; - private _mainUIBlock: IMainUIBlock; view: View; isHidden: boolean = false; @@ -44,6 +47,7 @@ class Overlay implements IOverlay { config, mainUIBlock, loader, + focusScreen, }: { eventEmitter: IEventEmitter; engine: IPlaybackEngine; @@ -52,12 +56,14 @@ class Overlay implements IOverlay { config: IPlayerConfig; mainUIBlock: IMainUIBlock; loader: ILoader; + focusScreen: IFocusScreen; }) { this._eventEmitter = eventEmitter; this._engine = engine; this._theme = theme; this._mainUIBlock = mainUIBlock; this._loader = loader; + this._focusScreen = focusScreen; this._bindEvents(); this._initUI(); @@ -133,13 +139,14 @@ class Overlay implements IOverlay { private _hideContent() { this.view.hideContent(); this._loader.show(); - this._mainUIBlock.enableShowingContent(); + this._mainUIBlock.show(); + this._focusScreen.focus(); } private _showContent() { this.view.showContent(); this._loader.hide(); - this._mainUIBlock.disableShowingContent(); + this._mainUIBlock.hide(); } /** diff --git a/src/modules/ui/screen/screen.scss b/src/modules/ui/screen/screen.scss index bd64490b..61e1ed00 100644 --- a/src/modules/ui/screen/screen.scss +++ b/src/modules/ui/screen/screen.scss @@ -54,10 +54,6 @@ box-shadow: 0 0 20px rgba(0, 0, 0, .2); } - - &.hiddenCursor { - cursor: none; - } } .backgroundCanvas { diff --git a/src/modules/ui/screen/screen.ts b/src/modules/ui/screen/screen.ts index 92334e1c..c3e6f568 100644 --- a/src/modules/ui/screen/screen.ts +++ b/src/modules/ui/screen/screen.ts @@ -5,35 +5,18 @@ import View from './screen.view'; import playerAPI from '../../../core/player-api-decorator'; import { IEventEmitter } from '../../event-emitter/types'; -import { IFullScreenManager } from '../../full-screen-manager/types'; import { IPlaybackEngine } from '../../playback-engine/types'; -import { IInteractionIndicator } from '../interaction-indicator/types'; import { IPlayerConfig } from '../../../core/config'; import { IRootContainer } from '../../root-container/types'; import { IScreenAPI, IScreen, VideoViewMode, IScreenViewConfig } from './types'; -const PLAYBACK_CHANGE_TIMEOUT = 300; - class Screen implements IScreen { static moduleName = 'screen'; static View = View; - static dependencies = [ - 'engine', - 'eventEmitter', - 'config', - 'fullScreenManager', - 'interactionIndicator', - 'rootContainer', - ]; + static dependencies = ['engine', 'eventEmitter', 'config', 'rootContainer']; private _eventEmitter: IEventEmitter; private _engine: IPlaybackEngine; - private _fullScreenManager: IFullScreenManager; - private _interactionIndicator: IInteractionIndicator; - - private _delayedToggleVideoPlaybackTimeout: number; - - private _isClickProcessingDisabled: boolean; private _unbindEvents: () => void; @@ -44,31 +27,18 @@ class Screen implements IScreen { config, eventEmitter, engine, - fullScreenManager, - interactionIndicator, rootContainer, }: { config: IPlayerConfig; eventEmitter: IEventEmitter; engine: IPlaybackEngine; - fullScreenManager: IFullScreenManager; - interactionIndicator: IInteractionIndicator; rootContainer: IRootContainer; }) { this._eventEmitter = eventEmitter; this._engine = engine; - this._fullScreenManager = fullScreenManager; - this._interactionIndicator = interactionIndicator; this.isHidden = false; - this._delayedToggleVideoPlaybackTimeout = null; - - this._isClickProcessingDisabled = Boolean( - config.disableControlWithClickOnPlayer, - ); - - this._bindCallbacks(); this._initUI(config.nativeBrowserControls); this._bindEvents(); @@ -79,19 +49,9 @@ class Screen implements IScreen { return this.view.getElement(); } - private _bindCallbacks() { - this._processClick = this._processClick.bind(this); - this._processDblClick = this._processDblClick.bind(this); - this._toggleVideoPlayback = this._toggleVideoPlayback.bind(this); - } - private _initUI(isNativeControls: boolean) { const config: IScreenViewConfig = { nativeControls: isNativeControls, - callbacks: { - onWrapperMouseClick: this._processClick, - onWrapperMouseDblClick: this._processDblClick, - }, playbackViewElement: this._engine.getElement(), }; @@ -101,7 +61,6 @@ class Screen implements IScreen { private _bindEvents() { this._unbindEvents = this._eventEmitter.bindEvents( [ - [UIEvent.PLAY_OVERLAY_CLICK, this.view.focusOnNode, this.view], [UIEvent.RESIZE, this._updateSizes], [EngineState.SRC_SET, this.view.resetBackground, this.view], [EngineState.METADATA_LOADED, this.view.resetAspectRatio, this.view], @@ -115,99 +74,6 @@ class Screen implements IScreen { this.view.resetAspectRatio(); } - showCursor() { - this.view.showCursor(); - } - - hideCursor() { - this.view.hideCursor(); - } - - private _processClick() { - if (this._isClickProcessingDisabled) { - return; - } - - this._showPlaybackChangeIndicator(); - - if (!this._fullScreenManager.isEnabled) { - this._toggleVideoPlayback(); - } else { - this._setDelayedPlaybackToggle(); - } - } - - private _processDblClick() { - if (this._isClickProcessingDisabled) { - return; - } - - if (this._fullScreenManager.isEnabled) { - if (this._isDelayedPlaybackToggleExist) { - this._clearDelayedPlaybackToggle(); - this._hideDelayedPlaybackChangeIndicator(); - } - - this._toggleFullScreen(); - } - } - - private _showPlaybackChangeIndicator() { - const state = this._engine.getCurrentState(); - - if (state === EngineState.PLAY_REQUESTED || state === EngineState.PLAYING) { - this._interactionIndicator.showPause(); - } else { - this._interactionIndicator.showPlay(); - } - } - - private _hideDelayedPlaybackChangeIndicator() { - this._interactionIndicator.hideIcons(); - } - - private _setDelayedPlaybackToggle() { - this._clearDelayedPlaybackToggle(); - - this._delayedToggleVideoPlaybackTimeout = window.setTimeout( - this._toggleVideoPlayback, - PLAYBACK_CHANGE_TIMEOUT, - ); - } - - private _clearDelayedPlaybackToggle() { - window.clearTimeout(this._delayedToggleVideoPlaybackTimeout); - this._delayedToggleVideoPlaybackTimeout = null; - } - - private get _isDelayedPlaybackToggleExist() { - return Boolean(this._delayedToggleVideoPlaybackTimeout); - } - - private _toggleVideoPlayback() { - this._clearDelayedPlaybackToggle(); - - const state = this._engine.getCurrentState(); - - if (state === EngineState.PLAY_REQUESTED || state === EngineState.PLAYING) { - this._engine.pause(); - this._eventEmitter.emitAsync(UIEvent.PAUSE_WITH_SCREEN_CLICK); - } else { - this._engine.play(); - this._eventEmitter.emitAsync(UIEvent.PLAY_WITH_SCREEN_CLICK); - } - } - - private _toggleFullScreen() { - if (this._fullScreenManager.isInFullScreen) { - this._fullScreenManager.exitFullScreen(); - this._eventEmitter.emitAsync(UIEvent.EXIT_FULL_SCREEN_WITH_SCREEN_CLICK); - } else { - this._fullScreenManager.enterFullScreen(); - this._eventEmitter.emitAsync(UIEvent.ENTER_FULL_SCREEN_WITH_SCREEN_CLICK); - } - } - hide() { if (!this.isHidden) { this.view.hide(); @@ -239,7 +105,6 @@ class Screen implements IScreen { destroy() { this._unbindEvents(); - this._clearDelayedPlaybackToggle(); this.view.destroy(); } } diff --git a/src/modules/ui/screen/screen.view.ts b/src/modules/ui/screen/screen.view.ts index 8500007e..507df152 100644 --- a/src/modules/ui/screen/screen.view.ts +++ b/src/modules/ui/screen/screen.view.ts @@ -7,19 +7,12 @@ import htmlToElement from '../core/htmlToElement'; import getElementByHook from '../core/getElementByHook'; import toggleElementClass from '../core/toggleElementClass'; -import { - VideoViewMode, - IScreenViewStyles, - IScreenViewCallbacks, - IScreenViewConfig, -} from './types'; +import { VideoViewMode, IScreenViewStyles, IScreenViewConfig } from './types'; import styles from './screen.scss'; class ScreenView extends View implements IView { - private _callbacks: IScreenViewCallbacks; - private _$rootElement: HTMLElement; private _$canvas: HTMLCanvasElement; private _$playbackElement: HTMLVideoElement; @@ -34,9 +27,7 @@ class ScreenView extends View constructor(config: IScreenViewConfig) { super(); - const { callbacks, nativeControls, playbackViewElement } = config; - - this._callbacks = callbacks; + const { nativeControls, playbackViewElement } = config; this._styleNamesByViewMode = { [VideoViewMode.REGULAR]: this.styleNames.regularMode, @@ -51,7 +42,6 @@ class ScreenView extends View } this._initDOM(playbackViewElement); - this._bindEvents(); this.setViewMode(VideoViewMode.REGULAR); } @@ -75,32 +65,6 @@ class ScreenView extends View ) as HTMLCanvasElement; } - private _bindEvents() { - this._$rootElement.addEventListener( - 'click', - this._callbacks.onWrapperMouseClick, - ); - this._$rootElement.addEventListener( - 'dblclick', - this._callbacks.onWrapperMouseDblClick, - ); - } - - private _unbindEvents() { - this._$rootElement.removeEventListener( - 'click', - this._callbacks.onWrapperMouseClick, - ); - this._$rootElement.removeEventListener( - 'dblclick', - this._callbacks.onWrapperMouseDblClick, - ); - } - - focusOnNode() { - this._$rootElement.focus(); - } - show() { toggleElementClass(this._$rootElement, this.styleNames.hidden, false); } @@ -113,14 +77,6 @@ class ScreenView extends View return this._$rootElement; } - hideCursor() { - toggleElementClass(this._$rootElement, this.styleNames.hiddenCursor, true); - } - - showCursor() { - toggleElementClass(this._$rootElement, this.styleNames.hiddenCursor, false); - } - setViewMode(viewMode: VideoViewMode) { if (this._styleNamesByViewMode[viewMode]) { this.resetBackground(); @@ -279,7 +235,6 @@ class ScreenView extends View destroy() { this._stopUpdatingBackground(); - this._unbindEvents(); if (this._$rootElement.parentNode) { this._$rootElement.parentNode.removeChild(this._$rootElement); } diff --git a/src/modules/ui/screen/types.ts b/src/modules/ui/screen/types.ts index 3d51e026..1f110743 100644 --- a/src/modules/ui/screen/types.ts +++ b/src/modules/ui/screen/types.ts @@ -4,7 +4,6 @@ type IScreenViewStyles = { screenBottomBackground: string; hidden: string; visible: string; - hiddenCursor: string; horizontalStripes: string; verticalStripes: string; fillMode: string; @@ -12,13 +11,7 @@ type IScreenViewStyles = { regularMode: string; }; -type IScreenViewCallbacks = { - onWrapperMouseClick: EventListenerOrEventListenerObject; - onWrapperMouseDblClick: EventListenerOrEventListenerObject; -}; - type IScreenViewConfig = { - callbacks: IScreenViewCallbacks; playbackViewElement: HTMLElement; nativeControls: boolean; }; @@ -31,8 +24,6 @@ enum VideoViewMode { interface IScreen { getElement(): HTMLElement; - showCursor(): void; - hideCursor(): void; show(): void; hide(): void; @@ -51,6 +42,5 @@ export { IScreen, VideoViewMode, IScreenViewStyles, - IScreenViewCallbacks, IScreenViewConfig, };