123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- /*! @name videojs-playlist-ui @version 3.5.2 @license Apache-2.0 */
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('global/document'), require('video.js')) :
- typeof define === 'function' && define.amd ? define(['global/document', 'video.js'], factory) :
- (global.videojsPlaylistUi = factory(global.document,global.videojs));
- }(this, (function (document,videojs) { 'use strict';
- document = document && document.hasOwnProperty('default') ? document['default'] : document;
- videojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs;
- function _inheritsLoose(subClass, superClass) {
- subClass.prototype = Object.create(superClass.prototype);
- subClass.prototype.constructor = subClass;
- subClass.__proto__ = superClass;
- }
- var version = "3.5.2";
- var dom = videojs.dom || videojs;
- var registerPlugin = videojs.registerPlugin || videojs.plugin; // Array#indexOf analog for IE8
- var indexOf = function indexOf(array, target) {
- for (var i = 0, length = array.length; i < length; i++) {
- if (array[i] === target) {
- return i;
- }
- }
- return -1;
- }; // see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/css/pointerevents.js
- var supportsCssPointerEvents = function () {
- var element = document.createElement('x');
- element.style.cssText = 'pointer-events:auto';
- return element.style.pointerEvents === 'auto';
- }();
- var defaults = {
- className: 'vjs-playlist',
- playOnSelect: false,
- supportsCssPointerEvents: supportsCssPointerEvents
- }; // we don't add `vjs-playlist-now-playing` in addSelectedClass
- // so it won't conflict with `vjs-icon-play
- // since it'll get added when we mouse out
- var addSelectedClass = function addSelectedClass(el) {
- el.addClass('vjs-selected');
- };
- var removeSelectedClass = function removeSelectedClass(el) {
- el.removeClass('vjs-selected');
- if (el.thumbnail) {
- dom.removeClass(el.thumbnail, 'vjs-playlist-now-playing');
- }
- };
- var upNext = function upNext(el) {
- el.addClass('vjs-up-next');
- };
- var notUpNext = function notUpNext(el) {
- el.removeClass('vjs-up-next');
- };
- var createThumbnail = function createThumbnail(thumbnail) {
- if (!thumbnail) {
- var placeholder = document.createElement('div');
- placeholder.className = 'vjs-playlist-thumbnail vjs-playlist-thumbnail-placeholder';
- return placeholder;
- }
- var picture = document.createElement('picture');
- picture.className = 'vjs-playlist-thumbnail';
- if (typeof thumbnail === 'string') {
- // simple thumbnails
- var img = document.createElement('img');
- img.src = thumbnail;
- img.alt = '';
- picture.appendChild(img);
- } else {
- // responsive thumbnails
- // additional variations of a <picture> are specified as
- // <source> elements
- for (var i = 0; i < thumbnail.length - 1; i++) {
- var _variant = thumbnail[i];
- var source = document.createElement('source'); // transfer the properties of each variant onto a <source>
- for (var prop in _variant) {
- source[prop] = _variant[prop];
- }
- picture.appendChild(source);
- } // the default version of a <picture> is specified by an <img>
- var variant = thumbnail[thumbnail.length - 1];
- var _img = document.createElement('img');
- _img.alt = '';
- for (var _prop in variant) {
- _img[_prop] = variant[_prop];
- }
- picture.appendChild(_img);
- }
- return picture;
- };
- var Component = videojs.getComponent('Component');
- var PlaylistMenuItem =
- /*#__PURE__*/
- function (_Component) {
- _inheritsLoose(PlaylistMenuItem, _Component);
- function PlaylistMenuItem(player, playlistItem, settings) {
- var _this;
- if (!playlistItem.item) {
- throw new Error('Cannot construct a PlaylistMenuItem without an item option');
- }
- _this = _Component.call(this, player, playlistItem) || this;
- _this.item = playlistItem.item;
- _this.playOnSelect = settings.playOnSelect;
- _this.emitTapEvents();
- _this.on(['click', 'tap'], _this.switchPlaylistItem_);
- _this.on('keydown', _this.handleKeyDown_);
- return _this;
- }
- var _proto = PlaylistMenuItem.prototype;
- _proto.handleKeyDown_ = function handleKeyDown_(event) {
- // keycode 13 is <Enter>
- // keycode 32 is <Space>
- if (event.which === 13 || event.which === 32) {
- this.switchPlaylistItem_();
- }
- };
- _proto.switchPlaylistItem_ = function switchPlaylistItem_(event) {
- this.player_.playlist.currentItem(indexOf(this.player_.playlist(), this.item));
- if (this.playOnSelect) {
- this.player_.play();
- }
- };
- _proto.createEl = function createEl() {
- var li = document.createElement('li');
- var item = this.options_.item;
- if (typeof item.data === 'object') {
- var dataKeys = Object.keys(item.data);
- dataKeys.forEach(function (key) {
- var value = item.data[key];
- li.dataset[key] = value;
- });
- }
- li.className = 'vjs-playlist-item';
- li.setAttribute('tabIndex', 0); // Thumbnail image
- this.thumbnail = createThumbnail(item.thumbnail);
- li.appendChild(this.thumbnail); // Duration
- if (item.duration) {
- var duration = document.createElement('time');
- var time = videojs.formatTime(item.duration);
- duration.className = 'vjs-playlist-duration';
- duration.setAttribute('datetime', 'PT0H0M' + item.duration + 'S');
- duration.appendChild(document.createTextNode(time));
- li.appendChild(duration);
- } // Now playing
- var nowPlayingEl = document.createElement('span');
- var nowPlayingText = this.localize('');
- nowPlayingEl.className = 'vjs-playlist-now-playing-text';
- nowPlayingEl.appendChild(document.createTextNode(nowPlayingText));
- nowPlayingEl.setAttribute('title', nowPlayingText);
- this.thumbnail.appendChild(nowPlayingEl); // Title container contains title and "up next"
- var titleContainerEl = document.createElement('div');
- titleContainerEl.className = 'vjs-playlist-title-container';
- this.thumbnail.appendChild(titleContainerEl); // Up next
- var upNextEl = document.createElement('span');
- var upNextText = this.localize('Up Next');
- upNextEl.className = 'vjs-up-next-text';
- upNextEl.appendChild(document.createTextNode(upNextText));
- upNextEl.setAttribute('title', upNextText);
- titleContainerEl.appendChild(upNextEl); // Video title
- var titleEl = document.createElement('cite');
- var titleText = item.name || this.localize('Untitled Video');
- titleEl.className = 'vjs-playlist-name';
- titleEl.appendChild(document.createTextNode(titleText));
- titleEl.setAttribute('title', titleText);
- titleContainerEl.appendChild(titleEl);
- return li;
- };
- return PlaylistMenuItem;
- }(Component);
- var PlaylistMenu =
- /*#__PURE__*/
- function (_Component2) {
- _inheritsLoose(PlaylistMenu, _Component2);
- function PlaylistMenu(player, options) {
- var _this2;
- if (!player.playlist) {
- throw new Error('videojs-playlist is required for the playlist component');
- }
- _this2 = _Component2.call(this, player, options) || this;
- _this2.items = [];
- if (options.horizontal) {
- _this2.addClass('vjs-playlist-horizontal');
- } else {
- _this2.addClass('vjs-playlist-vertical');
- } // If CSS pointer events aren't supported, we have to prevent
- // clicking on playlist items during ads with slightly more
- // invasive techniques. Details in the stylesheet.
- if (options.supportsCssPointerEvents) {
- _this2.addClass('vjs-csspointerevents');
- }
- _this2.createPlaylist_();
- if (!videojs.browser.TOUCH_ENABLED) {
- _this2.addClass('vjs-mouse');
- }
- _this2.on(player, ['loadstart', 'playlistchange', 'playlistsorted'], function (event) {
- _this2.update();
- }); // Keep track of whether an ad is playing so that the menu
- // appearance can be adapted appropriately
- _this2.on(player, 'adstart', function () {
- _this2.addClass('vjs-ad-playing');
- });
- _this2.on(player, 'adend', function () {
- _this2.removeClass('vjs-ad-playing');
- });
- _this2.on('dispose', function () {
- _this2.empty_();
- player.playlistMenu = null;
- });
- _this2.on(player, 'dispose', function () {
- _this2.dispose();
- });
- return _this2;
- }
- var _proto2 = PlaylistMenu.prototype;
- _proto2.createEl = function createEl() {
- return dom.createEl('div', {
- className: this.options_.className
- });
- };
- _proto2.empty_ = function empty_() {
- if (this.items && this.items.length) {
- this.items.forEach(function (i) {
- return i.dispose();
- });
- this.items.length = 0;
- }
- };
- _proto2.createPlaylist_ = function createPlaylist_() {
- var playlist = this.player_.playlist() || [];
- var list = this.el_.querySelector('.vjs-playlist-item-list');
- var overlay = this.el_.querySelector('.vjs-playlist-ad-overlay');
- if (!list) {
- list = document.createElement('ol');
- list.className = 'vjs-playlist-item-list';
- this.el_.appendChild(list);
- }
- this.empty_(); // create new items
- for (var i = 0; i < playlist.length; i++) {
- var item = new PlaylistMenuItem(this.player_, {
- item: playlist[i]
- }, this.options_);
- this.items.push(item);
- list.appendChild(item.el_);
- } // Inject the ad overlay. IE<11 doesn't support "pointer-events:
- // none" so we use this element to block clicks during ad
- // playback.
- if (!overlay) {
- overlay = document.createElement('li');
- overlay.className = 'vjs-playlist-ad-overlay';
- list.appendChild(overlay);
- } else {
- // Move overlay to end of list
- list.appendChild(overlay);
- } // select the current playlist item
- var selectedIndex = this.player_.playlist.currentItem();
- if (this.items.length && selectedIndex >= 0) {
- addSelectedClass(this.items[selectedIndex]);
- var thumbnail = this.items[selectedIndex].$('.vjs-playlist-thumbnail');
- if (thumbnail) {
- dom.addClass(thumbnail, 'vjs-playlist-now-playing');
- }
- }
- };
- _proto2.update = function update() {
- // replace the playlist items being displayed, if necessary
- var playlist = this.player_.playlist();
- if (this.items.length !== playlist.length) {
- // if the menu is currently empty or the state is obviously out
- // of date, rebuild everything.
- this.createPlaylist_();
- return;
- }
- for (var i = 0; i < this.items.length; i++) {
- if (this.items[i].item !== playlist[i]) {
- // if any of the playlist items have changed, rebuild the
- // entire playlist
- this.createPlaylist_();
- return;
- }
- } // the playlist itself is unchanged so just update the selection
- var currentItem = this.player_.playlist.currentItem();
- for (var _i = 0; _i < this.items.length; _i++) {
- var item = this.items[_i];
- if (_i === currentItem) {
- addSelectedClass(item);
- if (document.activeElement !== item.el()) {
- dom.addClass(item.thumbnail, 'vjs-playlist-now-playing');
- }
- notUpNext(item);
- } else if (_i === currentItem + 1) {
- removeSelectedClass(item);
- upNext(item);
- } else {
- removeSelectedClass(item);
- notUpNext(item);
- }
- }
- };
- return PlaylistMenu;
- }(Component);
- /**
- * Returns a boolean indicating whether an element has child elements.
- *
- * Note that this is distinct from whether it has child _nodes_.
- *
- * @param {HTMLElement} el
- * A DOM element.
- *
- * @return {boolean}
- * Whether the element has child elements.
- */
- var hasChildEls = function hasChildEls(el) {
- for (var i = 0; i < el.childNodes.length; i++) {
- if (dom.isEl(el.childNodes[i])) {
- return true;
- }
- }
- return false;
- };
- /**
- * Finds the first empty root element.
- *
- * @param {string} className
- * An HTML class name to search for.
- *
- * @return {HTMLElement}
- * A DOM element to use as the root for a playlist.
- */
- var findRoot = function findRoot(className) {
- var all = document.querySelectorAll('.' + className);
- var el;
- for (var i = 0; i < all.length; i++) {
- if (!hasChildEls(all[i])) {
- el = all[i];
- break;
- }
- }
- return el;
- };
- /**
- * Initialize the plugin on a player.
- *
- * @param {Object} [options]
- * An options object.
- *
- * @param {HTMLElement} [options.el]
- * A DOM element to use as a root node for the playlist.
- *
- * @param {string} [options.className]
- * An HTML class name to use to find a root node for the playlist.
- *
- * @param {boolean} [options.playOnSelect = false]
- * If true, will attempt to begin playback upon selecting a new
- * playlist item in the UI.
- */
- var playlistUi = function playlistUi(options) {
- var player = this;
- if (!player.playlist) {
- throw new Error('videojs-playlist plugin is required by the videojs-playlist-ui plugin');
- }
- if (dom.isEl(options)) {
- videojs.log.warn('videojs-playlist-ui: Passing an element directly to playlistUi() is deprecated, use the "el" option instead!');
- options = {
- el: options
- };
- }
- options = videojs.mergeOptions(defaults, options); // If the player is already using this plugin, remove the pre-existing
- // PlaylistMenu, but retain the element and its location in the DOM because
- // it will be re-used.
- if (player.playlistMenu) {
- var el = player.playlistMenu.el(); // Catch cases where the menu may have been disposed elsewhere or the
- // element removed from the DOM.
- if (el) {
- var parentNode = el.parentNode;
- var nextSibling = el.nextSibling; // Disposing the menu will remove `el` from the DOM, but we need to
- // empty it ourselves to be sure.
- player.playlistMenu.dispose();
- dom.emptyEl(el); // Put the element back in its place.
- if (nextSibling) {
- parentNode.insertBefore(el, nextSibling);
- } else {
- parentNode.appendChild(el);
- }
- options.el = el;
- }
- }
- if (!dom.isEl(options.el)) {
- options.el = findRoot(options.className);
- }
- player.playlistMenu = new PlaylistMenu(player, options);
- }; // register components
- videojs.registerComponent('PlaylistMenu', PlaylistMenu);
- videojs.registerComponent('PlaylistMenuItem', PlaylistMenuItem); // register the plugin
- registerPlugin('playlistUi', playlistUi);
- playlistUi.VERSION = version;
- return playlistUi;
- })));
|