Astroport.ONE/templates/_sandbox/js/video-wall.js

1224 lines
60 KiB
JavaScript

/*jshint esversion: 6 */
/*jshint sub:true*/
/*globals jQuery, videojs, Mustache, Element*/
/**
* esversion:6
* @param {jQuery} $
* @returns {void}
*/
;
(function ($, window, document, undefined) {
if (jQuery)
(function ($) {
$.fn.extend({
/**
* The following optoins can be passed to the videoJS videowall plugin
* @param {wallOptions}, default: 'carousel', //carousel,thumb,playlist
* @param {slideshow}, default: false, // true,false depending on the video wall mode you selected to load
* @param {slideshowDelay},default: 2000, // slideshow delay
* @param {videoWallId}, default: "video-wall", //id of the video-wall container
* @param {videoWallContainer}: default :'video-wall-container', // class for the video wall container
* @param {containerId}, default: 'video-wall-slides', //slides container id
* @param {containerClass}, default : "slides-container", // slides container class
* @param {helpImproveVideoJS}, default : false,
* @param {thumbPageSize}, default : 12, default pagesize for thumbnail view
* @param {playlistPageSize}, default : 8, total playlist on a single page for playlist mode
* @param {videos}, default : [], videos list in the playlist to be loaded in the playlist mode
* @param {playlist}, default : [], playlists for loading in the playlist mode
* @param {loadSelectAssets}, default: true, to load the select2 assets internally by plugin or manual use false to load your own version
* @param {loadBootstrapAssets}, default : true, to load bootstrap assets internally by plugin itself, use false to provide your own files
* @param {bootstrapCssSource}, default : '//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css', source to be loaded
* by the plugin internally for the bootstrap css, you can provide you own custom version.
* @param {bootstrapJsSource}, default : '//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js', source to be loaded
* by the plugin internally for the bootstrap js, you can provide you own custom version.
* @param {select2CssSource}, default : '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/css/select2.min.css', source to be loaded
* by the plugin internally for the select2 plugin css, you can provide you own custom version.
* @param {select2JsSource}, default : '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/css/select2.min.css',source to be loaded
* by the plugin internally for the select2 plugin javascript, you can provide you own custom version.
* @param {openOnStart}, default : true, if the plugin should start with the wall opened
* @param {callback}, default : () => {}, the callback function to be called after the plugin has loaded completely
* @returns {void}
*/
idowsVideowall: function (params) {
"use strict";
let elemId, $this, playAll;
let loopList = {};
//merge defaults
let options = $.extend({}, $.fn.idowsVideowall.defaults, params);
/**
* @description DOM Element prototype for the library
* @param {attributes} , HTMLElement attributes to be set
*/
Element.prototype.setAttributes = function (attributes) {
for (var attributeName in attributes) {
let isHTML = attributeName === 'html';
if (isHTML) {
this.innerHTML = attributes[attributeName];
} else {
this.setAttribute(attributeName, attributes[attributeName]);
}
}
};
this.triggerEvent = (event, params) => {
$this.trigger(event, params);
};
/**
* @description ,main function that initializes the plugin depending on the selected options
* and loads the necessary css and js files if selected to be
* loaded internally by plugin configurations/options.
*/
this.init = () => {
//optimize video js
if (!options.helpImproveVideoJS)
window.HELP_IMPROVE_VIDEOJS = false;
let player = $this.dependencyCheck();
let walltypes = {
'carousel': () => {
//add carousel to videojs player
$this.addCarousel({
player: player,
videos: options.videos,
elem: elemId,
});
},
'thumb': () => {
$this.addThumbWall({
player: player,
videos: options.videos,
elem: elemId,
});
},
'playlist': () => {
$this.addPlaylist({
player: player,
playlists: options.playlists,
elem: elemId,
});
}
};
if (walltypes.hasOwnProperty(options.wallType))
walltypes[options.wallType].call(this);
//add video wall bar
$this.bindWallbarController({
player: player,
});
if (options.openOnStart)
$this.toggleWall({
player: player
});
//handle playback end event and play-all event for the playlist mode
player.on('ended', function (e) {
let isMorePlaylistItems = playAll && !$.isEmptyObject(loopList);
if (isMorePlaylistItems) {
let nextVideo = $.fn.findNextVideo(loopList);
if (nextVideo) {
loopList[nextVideo].isActive = true;
loopList[parseInt(nextVideo - 1)].isActive = false;
return $this.playVideo({
title: loopList[nextVideo].title,
player: player,
mime: loopList[nextVideo].mime,
src: loopList[nextVideo].src
});
} else {
$this.triggerEvent('onPlaylistEnd', {
playlist: loopList
});
}
}
player.exitFullscreen();
player.hasStarted(false);
$('#' + elemId + '-' + options.videoWallId).stop(true, true).slideToggle();
});
};
/**
* @description checks for pre-reqs and options required to run the plugin correctly
* @returns {VideoJs Element} player
*/
this.dependencyCheck = () => {
//check if pre-reqs are available
let player = videojs(elemId);
let isNotVideoJs = typeof player === 'undefined';
let isNotPlaylist = typeof options.playlists !== 'object';
if (isNotVideoJs) {
console.log('videojs object not initialized, you must include the script after the video js script and make sure the video js plugin is initialized');
return false;
}
if (options.wallType === 'playlist' && isNotPlaylist) {
throw new Error('You need to provide the playlist object to initialize the paylist.');
}
if (options.loadBootstrapAssets) {
let loadBootstrapCss = options.bootstrapCssSource !== false && !$.fn.AssetLoaded({
file: options.bootstrapCssSource,
type: 'link'
});
//load css file for bootstrap
if (loadBootstrapCss) {
//load css style sheet
let stylesheet = document.createElement('link');
$(stylesheet).attr({
rel: "stylesheet",
type: "text/css",
href: options.bootstrapCssSource,
integrity: "sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u",
crossorigin: "anonymous"
}).prependTo("head");
}
let loadBootstrapJs = options.bootstrapJsSource !== false && !$.fn.AssetLoaded({
file: options.bootstrapJsSource,
type: 'script'
});
//load js file for bootstrap
if (loadBootstrapJs) {
$.getScript(options.bootstrapJsSource, function (data, textStatus, jqxhr) {
let statusOk = jqxhr.status === 200;
//videojs.options.flash.swf = 'http://tinyii.my/js/tinymce/plugins/idowsfilemanager/js/video-js.swf';
if (!statusOk) {
throw new Error('Could not load bootstrap js source specified make sure the internet is connected if you are using default options for loading the sources or provide local source otherwise.');
}
});
}
}
let isThumbView = options.wallType === 'thumb' && options.loadSelectAssets;
//check if thuimbview called
if (isThumbView) {
let loadSelect2Css = options.select2CssSource !== false && !$.fn.AssetLoaded({
file: options.select2CssSource,
type: 'link'
});
//check if select2 css loaded
if (loadSelect2Css) {
let selectTheme = document.createElement('link');
$(selectTheme).attr({
rel: "stylesheet",
type: "text/css",
href: options.select2CssSource,
}).appendTo("head");
}
}
return player;
};
/**
* @description Create A New HTMLElement
* @param {elementType} params.elementType, the type of element to be created
* @param {attributes} params.attributes, the attributes for the HTMLElement to be created
* @returns {element}, HTMLElementObject
*/
this.createHtmlElement = (params) => {
let $d = document;
let element = $d.createElement(params.elementType);
element.setAttributes(params.attributes);
return element;
};
/**
* @description, Adds containers for the video wall
* @param {elem}, parent HTMLElement wrapper for the containers
*/
this.addContainers = (elem) => {
//video wall main container
$this.addMainContainer(elem);
//thumbs container
let videothumbContainer = $this.createHtmlElement({
elementType: 'div',
attributes: {
id: elemId + '-' + options.containerId,
class: options.containerClass
}
});
$('#' + elemId + '-' + options.videoWallId).append(videothumbContainer);
};
/**
* @description ,Adds main video wall container div element
* @param {elem} , Wrapper HTMLElement for the main container
*/
this.addMainContainer = (elem) => {
//video wall container
let wallContainer = $this.createHtmlElement({
elementType: 'div',
attributes: {
id: elemId + '-' + options.videoWallId,
class: options.videoWallContainer,
style: 'display:none;width:' + $($this).width() + 'px;height:' + $($this).height() + 'px'
}
});
$("#" + elem).append(wallContainer);
};
/**
* @description ,Add Slide Thumbs for the slider
* @param {counter} params.counter, the counter for the curernt page
* @param {poster} params.poster, the poster of the video for the wall (Carousel Mode)
* @returns {HTMLElementObject}
*/
this.addWallSlideThumb = (params) => {
return $this.createHtmlElement({
elementType: 'div',
attributes: {
id: elemId + '-slide-' + params.counter,
class: 'wall-slide mode-' + options.wallType + ' ' + ((params.counter === 0) ? 'active' : ''),
style: 'background:url(' + params.poster + '); background-size:cover; background-repeat:no-repeat;top:0'
},
});
};
/**
* @description , binds the play button functionality
* @param {wrapper} params.wrapper, the wrapper HTMLElement to bind the click function
* @param {videoParams} params.videoParams, the video params to be loaded into the videoJS tag
*/
this.bindPlayVideo = (params) => {
//load video on play
$(params.wrapper).on('click', function (e) {
loopList = {};
playAll = 0;
$this.playVideo(params.videoParams);
});
};
/**
* @description , Plays the video passed to the function
* @param {player} params.player , player object videoJS
* @param {mime} params.mime, mime type for the video
* @param {poster} params.poster, the poster image to be loaded in the videoJS player
*/
this.playVideo = (params) => {
let player = params.player;
//trigger before playback event
$this.triggerEvent('onBeforePlayback', {
title: params.title,
mime: params.mime,
player: params.player,
src: params.src
});
$('#' + elemId + '-' + options.videoWallId).stop(true, true).slideUp('slow', function () {
$('#' + elemId).hide();
player.pause();
player.src({
type: params.mime,
src: params.src
});
// load the new sources
player.load();
$('#' + elemId).show();
player.play();
});
//trigger before playback event
$this.triggerEvent('onAfterPlayback', {
title: params.title,
mime: params.mime,
player: params.player,
src: params.src
});
};
/**
* @description ,Slides a slide to right
* @returns {void}
*/
this.slideRight = () => {
$('#' + elemId + '-' + options.containerId + '.' + options.containerClass).find('div.active').removeClass('active').next().addClass('active');
$("#" + elemId + '-' + options.containerId + " > .wall-slide").stop(true, true, true).animate({
right: '+=' + $('#' + elemId).width()
}, 500, 'linear');
};
/**
* @description ,Slides a slide to left
* @returns {void}
*/
this.slideLeft = () => {
$('#' + elemId + '-' + options.containerId + '.' + options.containerClass).find('div.active').removeClass('active').prev().addClass('active');
$("#" + elemId + "-" + options.containerId + ">.wall-slide").stop(true, true, true).animate({
right: '-=' + $('#' + elemId).width()
}, 500, 'linear');
};
/**
* @description , Create Navigation for the video wall
* to navigate between the pages left and right
* @returns {void}
*/
this.addNavigation = () => {
let arrowRight = $this.createHtmlElement({
elementType: "a",
attributes: {
id: elemId + '-arrow-right',
class: 'fa fa-chevron-circle-right'
}
});
//bind slide right on click arrow right
$(arrowRight).on('click', function (e) {
e.preventDefault();
let curSlide = $('#' + elemId + '-' + options.containerId + '.' + options.containerClass).find('div.active');
let nextSlide = curSlide.next();
let hasNextSlide = nextSlide.length;
if (hasNextSlide) {
$this.triggerEvent('onBeforeNext', {
nextSlide: nextSlide,
currentSlide: curSlide
});
$this.slideRight();
$this.triggerEvent('onAfterNext', {
previousSlide: curSlide,
currentSlide: nextSlide
});
}
}).appendTo('#' + elemId + '-' + options.videoWallId);
//add navigation arrow left
let arrowLeft = $this.createHtmlElement({
elementType: "a",
attributes: {
id: elemId + '-arrow-left',
class: 'fa fa-chevron-circle-left'
}
});
//bind slide right on click arrow left
$(arrowLeft).on('click', function (e) {
e.preventDefault();
let curSlide = $('#' + elemId + '-' + options.containerId + '.' + options.containerClass).find('div.active');
let prevSlide = curSlide.prev();
let hasPrevSlide = prevSlide.length;
if (hasPrevSlide) {
$this.triggerEvent('onBeforePrev', {
nextSlide: prevSlide,
currentSlide: curSlide
});
$this.slideLeft();
$this.triggerEvent('onAfterPrev', {
currentSlide: prevSlide,
previousSlide: curSlide
});
}
}).appendTo('#' + elemId + '-' + options.videoWallId);
};
/**
* @description , Adds Keyboard bindings for the left right keys
* @returns {void}
*/
this.addKeyboardNavigation = () => {
let keyboardBindings = {
ArrowLeft: (e) => {
let curSlide = $('#' + elemId + '-' + options.containerId + '.' + options.containerClass).find('div.active');
let prevSlide = curSlide.prev();
let hasPrevSlide = prevSlide.length;
if (hasPrevSlide) {
$this.triggerEvent('onBeforePrev', {
nextSlide: prevSlide,
currentSlide: curSlide
});
$this.slideLeft();
$this.triggerEvent('onAfterPrev', {
currentSlide: prevSlide,
previousSlide: curSlide
});
}
},
ArrowRight: (e) => {
let curSlide = $('#' + elemId + '-' + options.containerId + '.' + options.containerClass).find('div.active');
let nextSlide = curSlide.next();
let hasNextSlide = $('#' + elemId + '-' + options.containerId + '.' + options.containerClass).find('div.active').next().length;
if (hasNextSlide) {
$this.triggerEvent('onBeforeNext', {
nextSlide: nextSlide,
currentSlide: curSlide
});
$this.slideRight();
$this.triggerEvent('onAfterNext', {
previousSlide: curSlide,
currentSlide: nextSlide
});
}
},
Enter: (e) => {
$('#' + elemId + '-' + options.containerId + ' > .wall-slide.active>.play-wrapper>i').trigger('click');
}
};
//bind mouseover element for binding keyboard navigation to active wall only
$('#' + elemId + '-' + options.videoWallId).on('mouseover', function (e) {
document.onkeydown = function (e) {
let wallVisible = $('#' + elemId + '-' + options.videoWallId + ":visible").length;
if (wallVisible) {
if (keyboardBindings.hasOwnProperty(e.key))
keyboardBindings[e.key].call(this, e);
}
};
});
//Firefox
$('#' + elemId + '-' + options.videoWallId).bind('DOMMouseScroll', function (e) {
let wallVisible = $('#' + elemId + '-' + options.videoWallId + ":visible").length;
let scrollEnabled = !!$(this).find('.card').filter(function () {
return $(this).is(":hover");
}).length;
if (wallVisible && !scrollEnabled) {
e.preventDefault();
if (e.detail > 0) {
//scroll down
if (keyboardBindings.hasOwnProperty('ArrowRight'))
keyboardBindings.ArrowRight.call(this, e);
} else {
//scroll up
if (keyboardBindings.hasOwnProperty('ArrowLeft'))
keyboardBindings.ArrowLeft.call(this, e);
}
}
});
// Detect IE version
var iev = 0;
var ieold = (/MSIE (\d+\.\d+);/.test(navigator.userAgent));
var trident = !!navigator.userAgent.match(/Trident\/7.0/);
var rv = navigator.userAgent.indexOf("rv:11.0");
if (ieold)
iev = new Number(RegExp.$1);
if (navigator.appVersion.indexOf("MSIE 10") != -1)
iev = 10;
if (trident && rv != -1)
iev = 11;
// IE 11
let isIE11 = typeof InstallTrigger !== 'undefined' || iev == 11;
if (isIE11) {
var lastScrollTop = 0;
$('#' + elemId + '-' + options.videoWallId).on('scroll', function (e) {
let scrollEnabled = !!$(this).find('.card').filter(function () {
return $(this).is(":hover");
}).length;
let wallVisible = $('#' + elemId + '-' + options.videoWallId + ":visible").length;
let st = $(this).scrollTop();
if (wallVisible && !scrollEnabled) {
e.preventDefault();
if (st < lastScrollTop) {
if (keyboardBindings.hasOwnProperty('ArrowLeft'))
keyboardBindings['ArrowLeft'].call(this, e);
} else if (st > lastScrollTop) {
if (keyboardBindings.hasOwnProperty('ArrowRight'))
keyboardBindings['ArrowRight'].call(this, e);
}
}
lastScrollTop = st;
});
}
// Chrome
else {
$('#' + elemId + '-' + options.videoWallId).on('mousewheel', function (e) {
let wallVisible = $('#' + elemId + '-' + options.videoWallId + ":visible").length;
let scrollEnabled = !!$(this).find('.card').filter(function () {
return $(this).is(":hover");
}).length;
if (wallVisible && !scrollEnabled) {
e.preventDefault();
if (e.originalEvent.wheelDelta > 0) {
if (keyboardBindings.hasOwnProperty('ArrowLeft'))
keyboardBindings['ArrowLeft'].call(this, e);
} else if (e.originalEvent.wheelDelta < 0) {
if (keyboardBindings.hasOwnProperty('ArrowRight'))
keyboardBindings['ArrowRight'].call(this, e);
}
}
});
}
};
/**
* @description ,Creates the playlist view for the player
* @param {elem} params.elem, HTMLElement wrapper element to inject the containers
* @param {playlists} params.playlists, the playlists to be loaded inside the videowall
* @param {player} params.player, VideoJS player object
*/
this.addPlaylist = (params) => {
//add containers
$this.addContainers(params.elem);
//create document fragment
let fragment = document.createDocumentFragment();
let playlists = params.playlists;
//calculate total slides
let totalSlides = Math.ceil(playlists.length / options.playlistPageSize);
//scope the local functions for use inside the loop
let addThumbFunc = $this.addWallSlideThumb;
let addElementFunc = $this.createHtmlElement;
let bindPlayAllFunc = $this.bindPlayAll;
let bindPlayFunc = $this.bindPlayVideo;
//end scope the local functions for use inside the loop
for (var i = 0; i < totalSlides; i++) {
//create wall thumb slide
let wallThumbSlide = addThumbFunc({
poster: '',
counter: i
});
//iterate the playlists and create pages depending on the pagesize for the playlist mode
for (var key = options.playlistPageSize * i;
(key < options.playlistPageSize * (i + 1) && key < playlists.length); key++) {
let playlistCardId = elemId + '-playlist-card-' + key;
let playlistHeaderId = elemId + '-playlist-header-' + key;
let playlistTemplate = $.fn.getTemplate('playlist');
//playlist params
let playlistName = playlists[key].name;
let totalVideos = playlists[key].videos.length;
let cover = playlists[key].cover;
let videos = playlists[key].videos;
//atributes for the card HTMLElement
let attributes = {
playlistHeaderId: playlistHeaderId,
playlistName: playlistName,
videoCount: totalVideos,
cover: cover
};
//creates a playlistcard element
let playlistCard = addElementFunc({
elementType: 'div',
attributes: {
class: 'card playlist-card',
id: playlistCardId,
}
});
//add playlist template
playlistCard.innerHTML = Mustache.render(playlistTemplate, attributes);
//append the playlist card to the current selected slide / page
wallThumbSlide.appendChild(playlistCard);
//append to the document fragment
fragment.appendChild(wallThumbSlide);
//get the playlist body and header objects from document fragment
let playlistBody = fragment.querySelector('#' + playlistCardId + ' .playlist-body');
let playlistHeader = fragment.querySelector('#' + playlistCardId + ' .playlist-header');
//bind the playall function for the playlist
bindPlayAllFunc({
button: playlistHeader.querySelector('button'),
playlist: playlists[key].videos,
playlistId: key,
player: params.player
});
//loop through the videos and add them to the current playlist card
for (var video in videos) {
if (videos.hasOwnProperty(video)) {
//get the video params
let src = videos[video].src;
let poster = videos[video].poster;
let mime = videos[video].mime;
let title = videos[video].title;
//get the template for the songlist
let songlist = $.fn.getTemplate('songlist');
//prepare song list data to be parsed
let songData = {
playlistSongId: playlistCardId + '-song-list-' + video,
poster: poster,
songTitle: title
};
//get the rendered html from the template for the songlist
let songlistHtml = Mustache.render(songlist, songData);
//the songlist wrapper element
let songWrapper = addElementFunc({
elementType: 'div'
});
//insert the songlist to the wrapper
songWrapper.innerHTML = songlistHtml;
//append as child to the playlistBody
playlistBody.appendChild(songWrapper.firstChild);
//get the play button object
let playButton = playlistBody.querySelector('#' + playlistCardId + '-song-list-' + video + '>.control>.play-wrapper-playlist');
//bind the play button with the play functionality
bindPlayFunc({
wrapper: playButton,
videoParams: {
player: params.player,
mime: mime,
src: src
}
});
}
}
}
}
if (totalSlides > 1) {
//add navigation arrow right
$this.addNavigation();
//bind arrow key left and right to the slide show
$this.addKeyboardNavigation();
}
//append the thumbnails to the wall container
document.querySelector('#' + elemId + '-' + options.containerId).appendChild(fragment);
};
/**
* @description , the playAll functionality for the "playlist" mode
* @param {button} params.button, the button object to bind the playall functionality
* @param {playlist} params.playlist , the videos list in the playlist to be played
* @param {player} params.player, the VideoJS player object
*/
this.bindPlayAll = (params) => {
$(params.button).on('click', function (e) {
playAll = 1;
loopList = params.playlist.map(function (video, index) {
var videos = Object.assign({}, video);
videos.isActive = !index ? true : false;
return videos;
});
$this.triggerEvent('onPlaylistStart', {
playlist: loopList
});
$this.playVideo({
title: params.playlist[0].title,
player: params.player,
mime: params.playlist[0].mime,
src: params.playlist[0].src
});
});
};
/**
* @description Adds the carousel for the video wall
* @param {elem} params.elem , HTMLElement wrapper element to inject the containers
* @param {videos} params.videos, the playlists to be loaded inside the videowall
* @param {player} params.player, VideoJS player object
*/
this.addCarousel = (params) => {
//add containers
$this.addContainers(params.elem);
//create document fragment
let fragment = document.createDocumentFragment();
//local scope functions
let addElementFunc = $this.createHtmlElement;
let MustacheRenderFunc = Mustache.render;
//create wall thumbs slider
for (var key in params.videos) {
if (params.videos.hasOwnProperty(key)) {
let src = params.videos[key].src;
let poster = params.videos[key].poster;
let mime = params.videos[key].mime;
let title = params.videos[key].title;
let carouselTemplate = $.fn.getTemplate('carousel');
let attributes = {
slide_id: elemId + '-slide-' + parseInt(key),
mode: options.wallType,
status: ((parseInt(key) === 0) ? 'active' : ''),
poster: poster,
title: title
};
let temp = addElementFunc({
elementType: 'div',
attributes: {
html: MustacheRenderFunc(carouselTemplate, attributes)
}
});
fragment.appendChild(temp.firstChild);
}
}
//appends the document fragment as a child to the document container
document.querySelector('#' + elemId + '-' + options.containerId).appendChild(fragment);
//add navigation arrow right
$this.addNavigation();
//bind arrow key left and right to the slide show
$this.addKeyboardNavigation();
};
/**
* @description creates a thumbnail wall for the videos
* @param {elem} params.elem, HTMLElement wrapper element to inject the containers
* @param {videos} params.videos, the videos to be loaded inside the video wall
* @param {player} params.player, VideoJS player object
*
*/
this.addThumbWall = (params) => {
//add contianer divs
$this.addContainers(params.elem);
//create document fragment to create and attach elements on runtime
let fragment = document.createDocumentFragment();
//add filter input to search available videos
$this.createFilterInput();
//calculate total slides
let totalSlides = Math.ceil(params.videos.length / options.thumbPageSize);
//local scope functions for sue in loop
let addSlideFunc = $this.addWallSlideThumb;
let getTemplateFunc = $.fn.getTemplate;
let addElementFunc = $this.createHtmlElement;
let bindPlayVideo = $this.bindPlayVideo;
let MustacheRenderFunc = Mustache.render;
for (var i = 0; i < totalSlides; i++) {
//create wall thumb slide
let wallThumbSlide = addSlideFunc({
poster: '',
counter: parseInt(i)
});
//append slide to fragment
fragment.appendChild(wallThumbSlide);
//iterate videos list and create thumbnails
for (var key = options.thumbPageSize * i;
(key < options.thumbPageSize * (i + 1) && key < params.videos.length); key++) {
let src = params.videos[key].src;
let poster = params.videos[key].poster;
let mime = params.videos[key].mime;
let title = params.videos[key].title;
let thumbnailTemplate = getTemplateFunc('thumbnail');
let attributes = {
thumb_id: elemId + '-video-thumb-' + key,
poster: poster,
video_title: title,
data_title: title,
};
//add playlist template
let temp = $this.createHtmlElement({
elementType: 'div',
attributes: {
html: MustacheRenderFunc(thumbnailTemplate, attributes)
}
});
fragment.querySelector('#' + elemId + '-slide-' + i).appendChild(temp.firstChild);
bindPlayVideo({
wrapper: fragment.querySelector('#' + attributes.thumb_id + '> .play-wrapper-thumbnail'),
videoParams: {
title: title,
player: params.player,
src: src,
mime: mime
}
});
}
}
if (totalSlides > 1) {
//add navigation arrow right
$this.addNavigation();
//bind arrow key left and right to the slide show
$this.addKeyboardNavigation();
}
//append the thumbnails to the wall container
document.querySelector('#' + elemId + '-' + options.containerId).appendChild(fragment);
};
/**
* @description ,Adds Wall controller bar
* @param {player} params.player , the VideoJS player Object
* @returns {void}
*/
this.bindWallbarController = (params) => {
let wallbar = $this.createWallBar();
wallbar.on('click', function () {
$this.toggleWall(params);
});
};
/**
* @description ,slideToggle the video wall
* @param {player} params.player , the VideoJS player Object
*/
this.toggleWall = (params) => {
$('#' + elemId + '-' + options.videoWallId).stop(true, true).slideToggle('slow');
params.player.pause();
};
/**
* @description ,Creates a Wall Bar controller element
* @returns {HTMLElementObject} wallbar
*/
this.createWallBar = () => {
let wallbar = $this.createHtmlElement({
elementType: 'div',
attributes: {
id: elemId + '-wall-control',
class: 'wall-bar',
html: '<i class="fa fa-list"></i>',
style: 'width:' + $($this).width() + 'px;'
}
});
return $(wallbar).insertAfter("#" + elemId);
};
/**
* @description creates a filter input for the video search
*/
this.createFilterInput = () => {
(options.select2JsSource !== false && options.loadSelectAssets) ?
//load script file
$.getScript(options.select2JsSource, function (data, textStatus, jqxhr) {
let statusOk = jqxhr.status === 200;
(statusOk) && $this.bindSelect2Sources();
}): $this.bindSelect2Sources();
};
/**
* @description creates the select2 input for the search filter video.
* @returns {undefined}
*/
this.bindSelect2Sources = () => {
let html = '<div class="filter-videos" style="margin:10px auto;font-size:initial;">' +
'<select class="js-example-basic-single" name="' + elemId + '-filter" id="' + elemId + '-filter">' +
'</select>' +
'</div>';
let range = document.createElement('div');
range.innerHTML = html;
document.querySelector('#' + elemId + '-' + options.videoWallId).insertBefore(range.firstChild, document.querySelector('#' + elemId + '-' + options.containerId));
$("#" + elemId + "-filter").select2({
"allowClear": true,
// "closeOnSelect": false,
"theme": "default",
"width": "100%",
"placeholder": "Search Videos",
'minimumInputLength': 2,
"dropdownCssClass": 'bigdrop',
"templateResult": function (video) {
if (!video.id) {
return video.text;
}
var $video = $(
'<span class="video-list-thumb"><p>' + video.text + '<small>Select to play the file</small><img src="' + decodeURIComponent(video.element.dataset.src) + '" class="img-video-select" /></p></span>'
);
return $video;
},
"templateSelection": function (video) {
if (!video.id) {
return video.text;
}
var $video = $(
'<span class="video-select-thumb"><p><i class="fa fa-play-circle-o" aria-hidden="true"></i>&nbsp; Playing Now&nbsp;' + video.text + '</p></span>'
);
return $video;
}
}).on('select2:select', function (e) {
e.preventDefault();
var data = e.params.data;
$('#' + data.id + ' >.play-wrapper-thumbnail').trigger('click');
});
//populate select2 data
$("#" + elemId + "-filter").refreshFilterResults($this.filteredData());
};
/**
* @description Formats files list as Select2 Data
* @returns {data} JSON
*/
this.filteredData = () => {
let filterableFiles = $('#' + elemId + '-' + options.videoWallId + ' div.thumb-title');
let data = [{
"id": '',
"text": 'Search Files',
"href": '',
"cover": ''
}];
for (var i = 0; i < filterableFiles.length; i++) {
let elementRef = $(filterableFiles[i]);
let filename = elementRef.data('title');
let cover = elementRef.parent().css('background-image');
let bi = cover.slice(4, -1);
let elementId = elementRef.parent().prop('id');
// For IE we need to remove quotes to the proper url
bi = cover.slice(4, -1).replace(/"/g, "");
data.push({
"id": elementId,
"text": filename,
"cover": bi,
"href": elementId
});
}
return data;
};
elemId = $(this).prop('id');
$this = this;
$this.init();
options.callback.call(this);
return $this;
}
});
//set default options
$.fn.idowsVideowall.defaults = {
wallOptions: 'carousel', //slide,thumb,playlist
slideshowDelay: 2000, // slideshow delay
videoWallId: "video-wall", //id of the video-wall container
videoWallContainer: 'video-wall-container', // class for the video wall container
containerId: 'video-wall-slides', //slides container id
containerClass: "slides-container", // slides container class
helpImproveVideoJS: false,
thumbPageSize: 15,
playlistPageSize: 8,
videos: [],
playlists: [],
loadSelectAssets: true,
loadBootstrapAssets: true,
bootstrapCssSource: '//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css',
bootstrapJsSource: '//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js',
select2CssSource: '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/css/select2.min.css',
select2JsSource: '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/js/select2.full.min.js',
openOnStart: true,
callback: () => {},
};
/**
* @description ,Returns template for the selected templateSelection
* @param {template} , the name of the template to be retrieved
*/
$.fn.getTemplate = (template) => {
let templateSelection = {
playlist: () => {
return [
'<!--Background color-->',
'<div class="playlist-header aqua-gradient text-left" id="{{playlistHeaderId}}" style="background-image:url(\'{{cover}}\'); background-size:cover;background-repeat:no-repeat;background-position:center;">',
'<!--Name-->',
'<span class="playlist-title">{{playlistName}}</span>',
'<div class="controls">',
'<button name="playall">Play All&nbsp;',
'<i class="fa fa-play" aria-hidden="true"></i>',
'</button>',
'</div>',
'<span class="playlist-count badge badge-pill purple-gradient">{{videoCount}} <i class="fa fa-video-camera" aria-hidden="true"></i></span>',
'</div>',
'<!--Avatar-->',
'<div>',
'<div class="avatar">',
'<img src="{{cover}}" class="rounded-circle img-responsive">',
'</div>',
'</div>',
'<div class="playlist-body">',
'</div>',
].join("\n");
},
songlist: () => {
return [
'<div class="song-list" id="{{playlistSongId}}" style="background-image:linear-gradient(rgba(0, 0, 0, 0.35),rgba(88, 88, 88, 0.82)),url({{poster}});">',
'<span class="control">',
'<span class="play-wrapper-playlist">',
'<i class="fa fa-play" aria-hidden="true"></i>',
'</span>',
'</span>',
'<span class="songTitle badge indigo lighten-1 blue-gradient">{{songTitle}}</span>',
'</div>',
].join("\n");
},
thumbnail: () => {
return [
'<div id="{{thumb_id}}" class="video-thumb" style="background:url({{poster}}); background-size:cover; background-repeat:no-repeat;background-position:center center !important">',
'<div class="thumb-title" data-title="{{data_title}}">{{video_title}}</div>',
'<div class="play-wrapper-thumbnail">',
'<i class="fa fa-play play-control"></i>',
'</div>',
'</div>',
].join("\n");
},
carousel: () => {
return [
'<div id="{{slide_id}}" class="wall-slide mode-{{model}} {{status}}" style="background: url(&quot;{{poster}}&quot;) 0% 0% / cover no-repeat; top: 0px; right: 0px;">',
'<div class="video-title">{{title}}</div>',
'<div class="play-wrapper">',
'<i class="fa fa-play play-control"></i>',
'</div>',
'</div>'
].join("\n");
}
};
if (templateSelection.hasOwnProperty(template)) {
return templateSelection[template].call(this);
}
};
/**
*@description determines if the script or css files were actually loaded
*@param {file},the file path to be loaded could be loacal or live cdn
*@param {type}, the type of file script or css
*@returns {true|false}, returns true or false if loaded or loaded
*/
$.fn.AssetLoaded = (params) => {
if (params.type === 'script') {
var scripts = document.getElementsByTagName("script");
for (let i = 0; i < scripts.length; i++) {
if (scripts[i].src.substr(-params.file.length) == params.file)
return true;
}
} else {
var links = document.getElementsByTagName("link");
for (let i = 0; i < links.length; i++) {
if (links[i].href.substr(-params.file.length) == params.file)
return true;
}
}
return false;
};
/**
* @description finds the next video to be played in the playlist
* @param loopList an object for the select playlist with the list of videos
* @returns {object|false} returns next video object or false depending on if there is a next video to be played
*/
$.fn.findNextVideo = (loopList) => {
for (let video in loopList) {
if (loopList[video].isActive && parseInt(video) < parseInt(Object.keys(loopList).length - 1)) {
return parseInt(video) + 1;
}
}
return false;
};
/**
* @description refreshes the select2 with new data to be replaced with current
* @param {data} JSON , the json data to be mapped to the selecte2
*/
$.fn.refreshFilterResults = function (data) {
this.select2('data', data);
// Update options
var $select = $(this[0]);
var options = data.map(function (item) {
return '<option value="' + item.id + '" data-href="' + item.href + '" data-src="' + encodeURIComponent(item.cover) + '">' + item.text + '</option>';
});
$select.html(options.join('')).change();
};
})(jQuery);
})(jQuery, window, document);