video/StreamPicker.js

import customEvent from '../utils/customEvent';

/**
 * StreamPicker - loads a new stream upon dropdown selection.
 *
 * @module StreamPicker
 * @prop {object} selectors - DOM query selectors
 * @prop {object} states - css classes representing states of the player and stream picker control
 * @prop {boolean} isOpened - whether or not the select dropdown is opened
 * @prop {HTMLElement} $player - the video player DOM element
 * @prop {HTMLElement} $control - the stream picker control DOM element
 */
const StreamPicker = {
	selectors: {
		control: '.l-videoHub__control',
		button: '.l-videoHub__button',
		ui: '.l-videoHub__selectionList, a',
		dropdown: '.l-videoHub__selectionList',
		videoPlayer: '#GNVideo_jwPlayerContainer',
		videoContainer: '.jwplayer-container',
	},

	states: {
		playing: 'jw-state-playing',
		inactive: 'jw-flag-user-inactive',
		fadeOut: 'is-faded-out',
		fadeIn: 'is-faded-in',
		animated: 'is-animated',
	},

	isOpened: false,

	$player: false,

	/**
	 * Bind change event to Stream picker dropdown,
	 * Show / hide the stream picker control with video player controls.
	 *
	 * @method init
	 */
	init() {
		const $controls = document.querySelectorAll( this.selectors.control );
		if ( $controls ) {
			[].forEach.call( $controls, ( $control ) => {
				const $picker = $control.querySelector( this.selectors.dropdown );
				const $ui = $control.querySelectorAll( this.selectors.ui );

				// Add change listener to dropdown.
				$picker.addEventListener( 'change', ( evt ) => {
					/* eslint-disable camelcase */
					/* global gn_analytics */
					if ( typeof ( gn_analytics ) !== 'undefined' && typeof ( gn_analytics.Analytics ) !== 'undefined' ) {
						gn_analytics.Analytics.track(['adobe'], {
							eventType: 'click',
							action: 'gnlive stream select',
							target: false,
						});
					}
					/* eslint-enable camelcase */

					// navigate to destination page on timeout to allow tracking call to go through.
					setTimeout( () => {
						window.location.href = evt.target.options[evt.target.selectedIndex].value;
					}, 500 );
				});

				// Show the contorl when picker is in focus.
				$picker.addEventListener( 'focus', () => {
					$control.dataset.focused = 'true'; // eslint-disable-line no-param-reassign
					this.show( $control );
				});

				// Show the picker when moused over.
				$control.addEventListener( 'mouseover', () => {
					this.show( $control );
				});

				// On mouseout, determine whether to show or hide the contorl based on player state.
				$control.addEventListener( 'mouseout', () => {
					this.showOrHide();
				});

				// Show the contorl when button / dropdown is in focus.
				[].forEach.call( $ui, ( $elem ) => {
					$elem.addEventListener( 'focus', () => {
						$control.dataset.focused = 'true'; // eslint-disable-line no-param-reassign
						this.show( $control );
					});
				});

				// Listen to click / blur events to show / hide the animated control.
				const isAnimated = $control.classList.contains( this.states.animated );
				$picker.addEventListener( 'click', () => {
					$control.dataset.opened = 'true' !== $control.dataset.opened; // eslint-disable-line no-param-reassign
					if ( 'true' !== $control.dataset.opened ) {
						if ( isAnimated ) {
							this.showOrHide();
						}
					}
				});

				// Show the contorl when button / dropdown is in focus.
				if ( isAnimated ) {
					[].forEach.call( $ui, ( $elem ) => {
						$elem.addEventListener( 'blur', () => {
							$control.dataset.opened = false; // eslint-disable-line no-param-reassign
							$control.dataset.focused = false; // eslint-disable-line no-param-reassign
							this.showOrHide();
						});
					});
				}

				// Listen to video player div attribute change when the video player is ready.
				window.addEventListener( customEvent.VIDEO_PLAYER_READY, () => {
					const observer = new MutationObserver( ( mutationsList ) => {
						// Show / hide stream picker control based on player state,
						// so that it shows / hides at the same time as other video player controls.
						mutationsList.forEach( () => {
							this.showOrHide();
						});
					});

					this.$player = document.querySelector( this.selectors.videoPlayer );

					observer.disconnect();
					observer.observe( this.$player, { attributes: true, childList: false, subtree: false });
				});
			});
		}
	},

	/**
	 * Show / hide the animated stream picker control based on the video player state.
	 *
	 * @method showOrHide
	 */
	showOrHide() {
		const $animatedControls = document.querySelectorAll( `${this.selectors.control}.${this.states.animated}` );
		[].forEach.call( $animatedControls, ( $control ) => {
			// Bail if the stream picker is currently active.
			if ( 'true' === $control.dataset.opened || 'true' === $control.dataset.focused ) {
				return;
			}

			if ( this.$player.classList && this.$player.classList.contains( this.states.playing )
				&& this.$player.classList.contains( this.states.inactive ) ) {
				this.hide( $control );
			} else {
				this.show( $control );
			}
		});
	},

	/**
	 * Show the animated stream picker control.
	 *
	 * @method hide
	 */
	hide( $control ) {
		$control.classList.add( this.states.fadeOut );
		$control.classList.remove( this.states.fadeIn );
	},

	/**
	 * Hide the animated stream picker control.
	 *
	 * @method show
	 */
	show( $control ) {
		$control.classList.add( this.states.fadeIn );
		$control.classList.remove( this.states.fadeOut );
	},
};

export default StreamPicker;