Commit 9967b75eef7c8466cf7e62217026bc3c013ff8a9

Authored by Evandro Junior
1 parent 4f216c98

falta escolher qual galeria apresentar no bloco

plugins/video/lib/ext/article.rb
@@ -2,6 +2,8 @@ require_dependency 'article' @@ -2,6 +2,8 @@ require_dependency 'article'
2 2
3 class Article 3 class Article
4 4
  5 + scope :video_gallery, :conditions => ["articles.type == 'VideoGallery'"]
  6 +
5 #FIXME This should be done via hotspot 7 #FIXME This should be done via hotspot
6 def self.folder_types_with_video 8 def self.folder_types_with_video
7 self.folder_types_without_video << 'VideoPlugin::VideoGallery' 9 self.folder_types_without_video << 'VideoPlugin::VideoGallery'
@@ -11,5 +13,35 @@ class Article @@ -11,5 +13,35 @@ class Article
11 class << self 13 class << self
12 alias_method_chain :folder_types, :video 14 alias_method_chain :folder_types, :video
13 end 15 end
  16 +
14 17
  18 +# def self.articles_columns
  19 +# Article.column_names.map {|c| "articles.#{c}"} .join(",")
  20 +# end
  21 +#
  22 +# def self.most_accessed(owner, limit = nil)
  23 +# conditions = owner.kind_of?(Environment) ? ["hits > 0"] : ["profile_id = ? and hits > 0", owner.id]
  24 +# result = Article.relevant_content.find(
  25 +# :all,
  26 +# :order => 'hits desc',
  27 +# :limit => limit,
  28 +# :conditions => conditions)
  29 +# result.paginate({:page => 1, :per_page => limit})
  30 +# end
  31 +
  32 + def self.can_be_listed
  33 + conditions = owner.kind_of?(Environment) ? ["hits > 0"] : ["profile_id = ? and hits > 0", owner.id]
  34 + result = Article.video_gallery.find(
  35 + :all,
  36 + :order => 'hits desc',
  37 + :conditions => conditions)
  38 + end
  39 +
  40 +
15 end 41 end
  42 +
  43 +
  44 +
  45 +
  46 +
  47 +
plugins/video/lib/video_plugin.rb
@@ -9,9 +9,7 @@ class VideoPlugin &lt; Noosfero::Plugin @@ -9,9 +9,7 @@ class VideoPlugin &lt; Noosfero::Plugin
9 end 9 end
10 10
11 def self.extra_blocks 11 def self.extra_blocks
12 - {  
13 - VideoPlugin::VideoBlock => {}  
14 - } 12 + { VideoPlugin::VideoBlock => {}, VideoPlugin::VideoGalleryBlock => {} }
15 end 13 end
16 14
17 def stylesheet? 15 def stylesheet?
plugins/video/lib/video_plugin/video_gallery_helper.rb
@@ -6,7 +6,7 @@ module VideoPlugin::VideoGalleryHelper @@ -6,7 +6,7 @@ module VideoPlugin::VideoGalleryHelper
6 if !configure[:contents].blank? 6 if !configure[:contents].blank?
7 configure[:contents] = configure[:contents].paginate( 7 configure[:contents] = configure[:contents].paginate(
8 :order => "updated_at DESC", 8 :order => "updated_at DESC",
9 - :per_page => 16, 9 + :per_page => 17,
10 :page => params[:npage] 10 :page => params[:npage]
11 ) 11 )
12 render :file => 'shared/video_list', :locals => configure 12 render :file => 'shared/video_list', :locals => configure
plugins/video/public/javascripts/videojs/vjs.youtube.js
1 -!function(){function addEventListener(element,event,cb){element.addEventListener?element.addEventListener(event,cb,!0):element.attachEvent(event,cb)}function setInnerText(element,text){if("undefined"==typeof element)return!1;var textProperty="innerText"in element?"innerText":"textContent";try{element[textProperty]=text}catch(anException){element.setAttribute("innerText",text)}}videojs.Youtube=videojs.MediaTechController.extend({init:function(player,options,ready){if(this.features.progressEvents=!1,this.features.timeupdateEvents=!1,videojs.MediaTechController.call(this,player,options,ready),this.isIos=/(iPad|iPhone|iPod)/g.test(navigator.userAgent),this.isAndroid=/(Android)/g.test(navigator.userAgent),this.playVideoIsAllowed=!(this.isIos||this.isAndroid),"undefined"!=typeof options.source)for(var key in options.source)options.source.hasOwnProperty(key)&&(player.options()[key]=options.source[key]);this.userQuality=videojs.Youtube.convertQualityName(player.options().quality),this.player_=player,this.playerEl_=document.getElementById(player.id()),this.playerEl_.className+=" vjs-youtube",this.qualityButton=document.createElement("div"),this.qualityButton.setAttribute("class","vjs-quality-button vjs-menu-button vjs-control"),this.qualityButton.setAttribute("tabindex",0);var qualityContent=document.createElement("div");this.qualityButton.appendChild(qualityContent),this.qualityTitle=document.createElement("span"),qualityContent.appendChild(this.qualityTitle),"undefined"!==player.options().quality&&setInnerText(this.qualityTitle,player.options().quality||"auto");var qualityMenu=document.createElement("div");if(qualityMenu.setAttribute("class","vjs-menu"),this.qualityButton.appendChild(qualityMenu),this.qualityMenuContent=document.createElement("ul"),this.qualityMenuContent.setAttribute("class","vjs-menu-content"),qualityMenu.appendChild(this.qualityMenuContent),this.id_=this.player_.id()+"_youtube_api",this.el_=videojs.Component.prototype.createEl("iframe",{id:this.id_,className:"vjs-tech",scrolling:"no",marginWidth:0,marginHeight:0,frameBorder:0}),this.el_.setAttribute("allowFullScreen",""),this.playerEl_.insertBefore(this.el_,this.playerEl_.firstChild),/MSIE (\d+\.\d+);/.test(navigator.userAgent)){var ieVersion=Number(RegExp.$1);this.addIframeBlocker(ieVersion)}else/(iPad|iPhone|iPod|android)/g.test(navigator.userAgent)||(this.el_.className+=" onDesktop",this.addIframeBlocker());this.parseSrc(player.options().src),this.playOnReady=this.player_.options().autoplay||!1,this.forceSSL=!("undefined"!=typeof this.player_.options().forceSSL&&this.player_.options().forceSSL!==!0),this.forceHTML5=!("undefined"!=typeof this.player_.options().forceHTML5&&this.player_.options().forceHTML5!==!0),this.updateIframeSrc();var self=this;player.ready(function(){var controlBar=self.playerEl_.querySelectorAll(".vjs-control-bar")[0];controlBar.appendChild(self.qualityButton),self.playOnReady&&!self.player_.options().ytcontrols&&("undefined"!=typeof self.player_.loadingSpinner&&self.player_.loadingSpinner.show(),"undefined"!=typeof self.player_.bigPlayButton&&self.player_.bigPlayButton.hide()),player.trigger("loadstart")}),this.on("dispose",function(){this.ytplayer&&this.ytplayer.destroy(),this.player_.options().ytcontrols||this.player_.off("waiting",this.bindedWaiting),this.playerEl_.querySelectorAll(".vjs-poster")[0].style.backgroundImage="none",this.el_.parentNode&&this.el_.parentNode.removeChild(this.el_),this.qualityButton.parentNode&&this.qualityButton.parentNode.removeChild(this.qualityButton),"undefined"!=typeof this.player_.loadingSpinner&&this.player_.loadingSpinner.hide(),"undefined"!=typeof this.player_.bigPlayButton&&this.player_.bigPlayButton.hide(),this.iframeblocker&&this.playerEl_.removeChild(this.iframeblocker)})}}),videojs.Youtube.prototype.updateIframeSrc=function(){var params={enablejsapi:1,iv_load_policy:3,playerapiid:this.id(),disablekb:1,wmode:"transparent",controls:this.player_.options().ytcontrols?1:0,html5:this.player_.options().forceHTML5?1:null,playsinline:this.player_.options().playsInline?1:0,showinfo:0,modestbranding:1,rel:0,autoplay:this.playOnReady?1:0,loop:this.player_.options().loop?1:0,list:this.playlistId,vq:this.userQuality,origin:window.location.protocol+"//"+window.location.host};"file:"===window.location.protocol&&delete params.origin;for(var prop in params)!params.hasOwnProperty(prop)||"undefined"!=typeof params[prop]&&null!==params[prop]||delete params[prop];var self=this;if(null===this.videoId)this.el_.src="about:blank",setTimeout(function(){self.triggerReady()},500);else if(this.el_.src=(this.forceSSL||"file:"===window.location.protocol?"https:":window.location.protocol)+"//www.youtube.com/embed/"+this.videoId+"?"+videojs.Youtube.makeQueryString(params),this.player_.options().ytcontrols?this.player_.controls(!1):"undefined"==typeof this.player_.poster()&&setTimeout(function(){var posterEl=self.playerEl_.querySelectorAll(".vjs-poster")[0];posterEl.style.backgroundImage="url(https://img.youtube.com/vi/"+self.videoId+"/0.jpg)",posterEl.style.display=""},100),this.bindedWaiting=function(){self.onWaiting()},this.player_.on("waiting",this.bindedWaiting),videojs.Youtube.apiReady)this.loadYoutube();else if(videojs.Youtube.loadingQueue.push(this),!videojs.Youtube.apiLoading){var tag=document.createElement("script");tag.onerror=function(e){self.onError(e)},tag.src=this.forceSSL||"file:"===window.location.protocol?"https://www.youtube.com/iframe_api":"//www.youtube.com/iframe_api";var firstScriptTag=document.getElementsByTagName("script")[0];firstScriptTag.parentNode.insertBefore(tag,firstScriptTag),videojs.Youtube.apiLoading=!0}},videojs.Youtube.prototype.onWaiting=function(){this.player_.bigPlayButton.hide()},videojs.Youtube.prototype.addIframeBlocker=function(ieVersion){this.iframeblocker=videojs.Component.prototype.createEl("div"),this.iframeblocker.className="iframeblocker",this.iframeblocker.style.position="absolute",this.iframeblocker.style.left=0,this.iframeblocker.style.right=0,this.iframeblocker.style.top=0,this.iframeblocker.style.bottom=0,this.iframeblocker.style.zIndex=9999,ieVersion&&9>ieVersion?this.iframeblocker.style.opacity=.01:this.iframeblocker.style.background="rgba(255, 255, 255, 0.01)";var self=this;addEventListener(this.iframeblocker,"mousemove",function(e){self.player_.userActive()||self.player_.userActive(!0),e.stopPropagation(),e.preventDefault()}),addEventListener(this.iframeblocker,"click",function(){self.paused()?self.play():self.pause()}),this.playerEl_.insertBefore(this.iframeblocker,this.el_.nextSibling)},videojs.Youtube.prototype.parseSrc=function(src){if(this.srcVal=src,src){var regId=/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/,match=src.match(regId);this.videoId=match&&11===match[2].length?match[2]:null;var regPlaylist=/[?&]list=([^#\&\?]+)/;match=src.match(regPlaylist),null!==match&&match.length>1?this.playlistId=match[1]:this.playlistId&&delete this.playlistId;var regVideoQuality=/[?&]vq=([^#\&\?]+)/;match=src.match(regVideoQuality),null!==match&&match.length>1&&(this.userQuality=match[1],setInnerText(this.qualityTitle,videojs.Youtube.parseQualityName(this.userQuality)))}},videojs.Youtube.prototype.src=function(src){if("undefined"!=typeof src){if(this.parseSrc(src),"about:blank"===this.el_.src)return void this.updateIframeSrc();delete this.defaultQuality,null!==this.videoId&&(this.player_.options().autoplay&&this.playVideoIsAllowed?this.ytplayer.loadVideoById({videoId:this.videoId,suggestedQuality:this.userQuality}):this.ytplayer.cueVideoById({videoId:this.videoId,suggestedQuality:this.userQuality}),this.playerEl_.querySelectorAll(".vjs-poster")[0].style.backgroundImage="url(https://img.youtube.com/vi/"+this.videoId+"/0.jpg)",this.player_.poster("https://img.youtube.com/vi/"+this.videoId+"/0.jpg"))}return this.srcVal},videojs.Youtube.prototype.load=function(){},videojs.Youtube.prototype.play=function(){null!==this.videoId&&(this.player_.options().ytcontrols||this.player_.trigger("waiting"),this.isReady_?(this.ytplayer.setVolume(100*this.player_.volume()),this.volumeVal>0?this.ytplayer.unMute():this.ytplayer.mute(),this.playVideoIsAllowed&&this.ytplayer.playVideo()):this.playOnReady=!0)},videojs.Youtube.prototype.pause=function(){this.ytplayer.pauseVideo()},videojs.Youtube.prototype.paused=function(){return this.ytplayer?this.lastState!==YT.PlayerState.PLAYING&&this.lastState!==YT.PlayerState.BUFFERING:!0},videojs.Youtube.prototype.currentTime=function(){return this.ytplayer&&this.ytplayer.getCurrentTime?this.ytplayer.getCurrentTime():0},videojs.Youtube.prototype.setCurrentTime=function(seconds){this.ytplayer.seekTo(seconds,!0),this.player_.trigger("timeupdate")},videojs.Youtube.prototype.duration=function(){return this.ytplayer&&this.ytplayer.getDuration?this.ytplayer.getDuration():0},videojs.Youtube.prototype.currentSrc=function(){return this.srcVal},videojs.Youtube.prototype.volume=function(){return this.ytplayer&&isNaN(this.volumeVal)&&(this.volumeVal=this.ytplayer.getVolume()/100,this.player_.volume(this.volumeVal)),this.volumeVal},videojs.Youtube.prototype.setVolume=function(percentAsDecimal){"undefined"!=typeof percentAsDecimal&&percentAsDecimal!==this.volumeVal&&(this.ytplayer.setVolume(100*percentAsDecimal),this.volumeVal=percentAsDecimal,this.player_.trigger("volumechange"))},videojs.Youtube.prototype.muted=function(){return this.mutedVal},videojs.Youtube.prototype.setMuted=function(muted){muted?(this.ytplayer.mute(),this.player_.volume(0)):(this.ytplayer.unMute(),this.player_.volume(this.volumeVal)),this.mutedVal=muted,this.player_.trigger("volumechange")},videojs.Youtube.prototype.buffered=function(){if(this.ytplayer&&this.ytplayer.getVideoBytesLoaded){var loadedBytes=this.ytplayer.getVideoBytesLoaded(),totalBytes=this.ytplayer.getVideoBytesTotal();if(!loadedBytes||!totalBytes)return 0;var duration=this.ytplayer.getDuration(),secondsBuffered=loadedBytes/totalBytes*duration,secondsOffset=this.ytplayer.getVideoStartBytes()/totalBytes*duration;return videojs.createTimeRange(secondsOffset,secondsOffset+secondsBuffered)}return videojs.createTimeRange(0,0)},videojs.Youtube.prototype.supportsFullScreen=function(){return!0},videojs.Youtube.isSupported=function(){return!0},videojs.Youtube.canPlaySource=function(srcObj){return"video/youtube"===srcObj.type},videojs.Youtube.canControlVolume=function(){return!0},videojs.Youtube.loadingQueue=[],videojs.Youtube.prototype.loadYoutube=function(){this.ytplayer=new YT.Player(this.id_,{events:{onReady:function(e){e.target.vjsTech.onReady()},onStateChange:function(e){e.target.vjsTech.onStateChange(e.data)},onPlaybackQualityChange:function(e){e.target.vjsTech.onPlaybackQualityChange(e.data)},onError:function(e){e.target.vjsTech.onError(e.data)}}}),this.ytplayer.vjsTech=this},videojs.Youtube.makeQueryString=function(args){var array=[];for(var key in args)args.hasOwnProperty(key)&&array.push(key+"="+args[key]);return array.join("&")},window.onYouTubeIframeAPIReady=function(){for(var yt;yt=videojs.Youtube.loadingQueue.shift();)yt.loadYoutube();videojs.Youtube.loadingQueue=[],videojs.Youtube.apiReady=!0},videojs.Youtube.prototype.onReady=function(){this.isReady_=!0,this.triggerReady(),this.player_.trigger("loadedmetadata"),this.player_.trigger("durationchange"),this.player_.trigger("timeupdate"),"undefined"!=typeof this.player_.loadingSpinner&&this.player_.loadingSpinner.hide(),this.player_.options().muted&&this.setMuted(!0),this.playOnReady&&(this.playOnReady=!1,this.play())},videojs.Youtube.prototype.updateQualities=function(){function setupEventListener(el){addEventListener(el,"click",function(){var quality=this.getAttribute("data-val");self.ytplayer.setPlaybackQuality(quality),self.userQuality=quality,setInnerText(self.qualityTitle,videojs.Youtube.parseQualityName(quality));var selected=self.qualityMenuContent.querySelector(".vjs-selected");selected&&videojs.Youtube.removeClass(selected,"vjs-selected"),videojs.Youtube.addClass(this,"vjs-selected")})}var qualities=this.ytplayer.getAvailableQualityLevels(),self=this;if(qualities.indexOf(this.userQuality)<0&&setInnerText(self.qualityTitle,videojs.Youtube.parseQualityName(this.defaultQuality)),0===qualities.length)this.qualityButton.style.display="none";else{for(this.qualityButton.style.display="";this.qualityMenuContent.hasChildNodes();)this.qualityMenuContent.removeChild(this.qualityMenuContent.lastChild);for(var i=0;i<qualities.length;++i){var el=document.createElement("li");el.setAttribute("class","vjs-menu-item"),setInnerText(el,videojs.Youtube.parseQualityName(qualities[i])),el.setAttribute("data-val",qualities[i]),qualities[i]===this.quality&&videojs.Youtube.addClass(el,"vjs-selected"),setupEventListener(el),this.qualityMenuContent.appendChild(el)}}},videojs.Youtube.prototype.onStateChange=function(state){if(state!==this.lastState){switch(state){case-1:this.player_.trigger("durationchange");break;case YT.PlayerState.ENDED:this.player_.options().ytcontrols||(this.playerEl_.querySelectorAll(".vjs-poster")[0].style.display="block","undefined"!=typeof this.player_.bigPlayButton&&this.player_.bigPlayButton.show()),this.player_.trigger("ended");break;case YT.PlayerState.PLAYING:this.playVideoIsAllowed=!0,this.updateQualities(),this.player_.trigger("timeupdate"),this.player_.trigger("durationchange"),this.player_.trigger("playing"),this.player_.trigger("play");break;case YT.PlayerState.PAUSED:this.player_.trigger("pause");break;case YT.PlayerState.BUFFERING:this.player_.trigger("timeupdate"),this.player_.options().ytcontrols||this.player_.trigger("waiting");break;case YT.PlayerState.CUED:}this.lastState=state}},videojs.Youtube.convertQualityName=function(name){switch(name){case"144p":return"tiny";case"240p":return"small";case"360p":return"medium";case"480p":return"large";case"720p":return"hd720";case"1080p":return"hd1080"}return"auto"},videojs.Youtube.parseQualityName=function(name){switch(name){case"tiny":return"144p";case"small":return"240p";case"medium":return"360p";case"large":return"480p";case"hd720":return"720p";case"hd1080":return"1080p"}return"auto"},videojs.Youtube.prototype.onPlaybackQualityChange=function(quality){if("undefined"!=typeof this.defaultQuality||(this.defaultQuality=quality,"undefined"==typeof this.userQuality)){switch(this.quality=quality,setInnerText(this.qualityTitle,videojs.Youtube.parseQualityName(quality)),quality){case"medium":this.player_.videoWidth=480,this.player_.videoHeight=360;break;case"large":this.player_.videoWidth=640,this.player_.videoHeight=480;break;case"hd720":this.player_.videoWidth=960,this.player_.videoHeight=720;break;case"hd1080":this.player_.videoWidth=1440,this.player_.videoHeight=1080;break;case"highres":this.player_.videoWidth=1920,this.player_.videoHeight=1080;break;case"small":this.player_.videoWidth=320,this.player_.videoHeight=240;break;case"tiny":this.player_.videoWidth=144,this.player_.videoHeight=108;break;default:this.player_.videoWidth=0,this.player_.videoHeight=0}this.player_.trigger("ratechange")}},videojs.Youtube.prototype.onError=function(error){this.player_.error(error),(100===error||101===error||150===error)&&(this.player_.bigPlayButton.hide(),this.player_.loadingSpinner.hide(),this.player_.posterImage.hide())},videojs.Youtube.addClass=function(element,classToAdd){-1===(" "+element.className+" ").indexOf(" "+classToAdd+" ")&&(element.className=""===element.className?classToAdd:element.className+" "+classToAdd)},videojs.Youtube.removeClass=function(element,classToRemove){var classNames,i;if(-1!==element.className.indexOf(classToRemove)){for(classNames=element.className.split(" "),i=classNames.length-1;i>=0;i--)classNames[i]===classToRemove&&classNames.splice(i,1);element.className=classNames.join(" ")}};var style=document.createElement("style"),def=" .vjs-youtube .vjs-poster { background-size: 100%!important; }.vjs-youtube .vjs-poster, .vjs-youtube .vjs-loading-spinner, .vjs-youtube .vjs-text-track-display{ pointer-events: none !important; }.vjs-youtube.vjs-user-active .iframeblocker { display: none; }.vjs-youtube.vjs-user-inactive .vjs-tech.onDesktop { pointer-events: none; }.vjs-quality-button > div:first-child > span:first-child { position:relative;top:7px }";style.setAttribute("type","text/css"),document.getElementsByTagName("head")[0].appendChild(style),style.styleSheet?style.styleSheet.cssText=def:style.appendChild(document.createTextNode(def)),Array.prototype.indexOf||(Array.prototype.indexOf=function(elt){var len=this.length>>>0,from=Number(arguments[1])||0;for(from=0>from?Math.ceil(from):Math.floor(from),0>from&&(from+=len);len>from;from++)if(from in this&&this[from]===elt)return from;return-1})}();  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +/* global videojs, YT */
  3 +/* jshint browser: true */
  4 +
  5 +(function() {
  6 + /**
  7 + * @fileoverview YouTube Media Controller - Wrapper for YouTube Media API
  8 + */
  9 +
  10 + /**
  11 + * YouTube Media Controller - Wrapper for YouTube Media API
  12 + * @param {videojs.Player|Object} player
  13 + * @param {Object=} options
  14 + * @param {Function=} ready
  15 + * @constructor
  16 + */
  17 +
  18 + function addEventListener(element, event, cb) {
  19 + if(!element.addEventListener) {
  20 + element.attachEvent(event, cb);
  21 + } else {
  22 + element.addEventListener(event, cb, true);
  23 + }
  24 + }
  25 +
  26 + videojs.Youtube = videojs.MediaTechController.extend({
  27 + /** @constructor */
  28 + init: function(player, options, ready) {
  29 + // Save this for internal usage
  30 + this.player_ = player;
  31 +
  32 + // No event is triggering this for YouTube
  33 + this['featuresProgressEvents'] = false;
  34 + this['featuresTimeupdateEvents'] = false;
  35 + // Enable rate changes
  36 + this['featuresPlaybackRate'] = true;
  37 +
  38 + videojs.MediaTechController.call(this, player, options, ready);
  39 +
  40 + this.isIos = /(iPad|iPhone|iPod)/g.test( navigator.userAgent );
  41 + this.isAndroid = /(Android)/g.test( navigator.userAgent );
  42 + //used to prevent play events on IOS7 and Android > 4.2 until the user has clicked the player
  43 + this.playVideoIsAllowed = !(this.isIos || this.isAndroid);
  44 +
  45 + // autoplay is disabled for mobile
  46 + if (this.isIos || this.isAndroid) {
  47 + this.player_.options()['autoplay'] = false;
  48 + }
  49 +
  50 + // Copy the JavaScript options if they exists
  51 + if(typeof options['source'] !== 'undefined') {
  52 + for(var key in options['source']) {
  53 + if(options['source'].hasOwnProperty(key)) {
  54 + player.options()[key] = options['source'][key];
  55 + }
  56 + }
  57 + }
  58 +
  59 + this.userQuality = videojs.Youtube.convertQualityName(player.options()['quality']);
  60 +
  61 + this.playerEl_ = document.getElementById(player.id());
  62 + this.playerEl_.className += ' vjs-youtube';
  63 +
  64 + // Create the Quality button
  65 + this.qualityButton = document.createElement('div');
  66 + this.qualityButton.setAttribute('class', 'vjs-quality-button vjs-menu-button vjs-control');
  67 + this.qualityButton.setAttribute('tabindex', 0);
  68 +
  69 + var qualityContent = document.createElement('div');
  70 + qualityContent.setAttribute('class', 'vjs-control-content');
  71 + this.qualityButton.appendChild(qualityContent);
  72 +
  73 + this.qualityTitle = document.createElement('span');
  74 + this.qualityTitle.setAttribute('class', 'vjs-control-text');
  75 + qualityContent.appendChild(this.qualityTitle);
  76 +
  77 + if(player.options()['quality'] !== 'undefined') {
  78 + setInnerText(this.qualityTitle, player.options()['quality'] || 'auto');
  79 + }
  80 +
  81 + var qualityMenu = document.createElement('div');
  82 + qualityMenu.setAttribute('class', 'vjs-menu');
  83 + qualityContent.appendChild(qualityMenu);
  84 +
  85 + this.qualityMenuContent = document.createElement('ul');
  86 + this.qualityMenuContent.setAttribute('class', 'vjs-menu-content');
  87 + qualityMenu.appendChild(this.qualityMenuContent);
  88 +
  89 + this.id_ = this.player_.id() + '_youtube_api';
  90 +
  91 + this.el_ = videojs.Component.prototype.createEl('iframe', {
  92 + id: this.id_,
  93 + className: 'vjs-tech',
  94 + scrolling: 'no',
  95 + marginWidth: 0,
  96 + marginHeight: 0,
  97 + frameBorder: 0
  98 + });
  99 +
  100 + this.el_.setAttribute('allowFullScreen', '');
  101 +
  102 + this.playerEl_.insertBefore(this.el_, this.playerEl_.firstChild);
  103 +
  104 + if(/MSIE (\d+\.\d+);/.test(navigator.userAgent)) {
  105 + var ieVersion = Number(RegExp.$1);
  106 + this.addIframeBlocker(ieVersion);
  107 + } else if(!/(iPad|iPhone|iPod|Android)/g.test(navigator.userAgent)) {
  108 + // the pointer-events: none block the mobile player
  109 + this.el_.className += ' onDesktop';
  110 + this.addIframeBlocker();
  111 + }
  112 +
  113 + this.parseSrc(player.options()['src']);
  114 +
  115 + this.playOnReady = this.player_.options()['autoplay'] && this.playVideoIsAllowed;
  116 + this.forceSSL = !!(
  117 + typeof this.player_.options()['forceSSL'] === 'undefined' ||
  118 + this.player_.options()['forceSSL'] === true
  119 + );
  120 + this.forceHTML5 = !!(
  121 + typeof this.player_.options()['forceHTML5'] === 'undefined' ||
  122 + this.player_.options()['forceHTML5'] === true
  123 + );
  124 +
  125 + this.updateIframeSrc();
  126 +
  127 + var self = this;
  128 +
  129 + player.ready(function() {
  130 + if (self.player_.options()['controls']) {
  131 + var controlBar = self.playerEl_.querySelectorAll('.vjs-control-bar')[0];
  132 + if (controlBar) {
  133 + controlBar.appendChild(self.qualityButton);
  134 + }
  135 + }
  136 +
  137 + if(self.playOnReady && !self.player_.options()['ytcontrols']) {
  138 + if(typeof self.player_.loadingSpinner !== 'undefined') {
  139 + self.player_.loadingSpinner.show();
  140 + }
  141 + if(typeof self.player_.bigPlayButton !== 'undefined') {
  142 + self.player_.bigPlayButton.hide();
  143 + }
  144 + }
  145 +
  146 + player.trigger('loadstart');
  147 + });
  148 +
  149 + this.on('dispose', function() {
  150 + if(this.ytplayer) {
  151 + this.ytplayer.destroy();
  152 + }
  153 +
  154 + if(!this.player_.options()['ytcontrols']) {
  155 + this.player_.off('waiting', this.bindedWaiting);
  156 + }
  157 +
  158 + // Remove the poster
  159 + this.playerEl_.querySelectorAll('.vjs-poster')[0].style.backgroundImage = 'none';
  160 +
  161 + // If still connected to the DOM, remove it.
  162 + if(this.el_.parentNode) {
  163 + this.el_.parentNode.removeChild(this.el_);
  164 + }
  165 +
  166 + // Get rid of the created DOM elements
  167 + if (this.qualityButton.parentNode) {
  168 + this.qualityButton.parentNode.removeChild(this.qualityButton);
  169 + }
  170 +
  171 + if(typeof this.player_.loadingSpinner !== 'undefined') {
  172 + this.player_.loadingSpinner.hide();
  173 + }
  174 + if(typeof this.player_.bigPlayButton !== 'undefined') {
  175 + this.player_.bigPlayButton.hide();
  176 + }
  177 +
  178 + if(this.iframeblocker) {
  179 + this.playerEl_.removeChild(this.iframeblocker);
  180 + }
  181 + });
  182 + }
  183 + });
  184 +
  185 + videojs.Youtube.prototype.updateIframeSrc = function() {
  186 + var params = {
  187 + enablejsapi: 1,
  188 + /*jshint -W106 */
  189 + iv_load_policy: 3,
  190 + /*jshint +W106 */
  191 + playerapiid: this.id(),
  192 + disablekb: 1,
  193 + wmode: 'transparent',
  194 + controls: (this.player_.options()['ytcontrols']) ? 1 : 0,
  195 + html5: (this.player_.options()['forceHTML5']) ? 1 : null,
  196 + playsinline: (this.player_.options()['playsInline']) ? 1 : 0,
  197 + showinfo: 0,
  198 + rel: 0,
  199 + autoplay: (this.playOnReady) ? 1 : 0,
  200 + loop: (this.player_.options()['loop']) ? 1 : 0,
  201 + list: this.playlistId,
  202 + vq: this.userQuality,
  203 + origin: window.location.protocol + '//' + window.location.host
  204 + };
  205 +
  206 + // When running with no Web server, we can't specify the origin or it will break the YouTube API messages
  207 + if(window.location.protocol === 'file:') {
  208 + delete params.origin;
  209 + }
  210 +
  211 + // Delete unset properties
  212 + for(var prop in params) {
  213 + if(params.hasOwnProperty(prop) &&
  214 + ( typeof params[ prop ] === 'undefined' || params[ prop ] === null )
  215 + ) {
  216 + delete params[ prop ];
  217 + }
  218 + }
  219 + var self = this;
  220 +
  221 + if(!this.videoId) {
  222 + this.el_.src = 'about:blank';
  223 + setTimeout(function() {
  224 + self.triggerReady();
  225 + }, 500);
  226 + } else {
  227 + this.el_.src = (
  228 + (this.forceSSL || window.location.protocol === 'file:') ?
  229 + 'https:'
  230 + : window.location.protocol
  231 + ) + '//www.youtube.com/embed/' + this.videoId + '?' + videojs.Youtube.makeQueryString(params);
  232 +
  233 + if(this.player_.options()['ytcontrols']) {
  234 + // Disable the video.js controls if we use the YouTube controls
  235 + this.player_.controls(false);
  236 + } else if(typeof this.player_.poster() === 'undefined' || this.player_.poster().length === 0) {
  237 + // Wait here because the tech is still null in constructor
  238 + setTimeout(function() {
  239 + self.player_.poster('https://img.youtube.com/vi/' + self.videoId + '/0.jpg');
  240 + }, 100);
  241 + }
  242 +
  243 + this.bindedWaiting = function() {
  244 + self.onWaiting();
  245 + };
  246 +
  247 + this.player_.on('waiting', this.bindedWaiting);
  248 +
  249 + if(videojs.Youtube.apiReady) {
  250 + this.loadYoutube();
  251 + } else {
  252 + // Add to the queue because the YouTube API is not ready
  253 + videojs.Youtube.loadingQueue.push(this);
  254 +
  255 + // Load the YouTube API if it is the first YouTube video
  256 + if(!videojs.Youtube.apiLoading) {
  257 + var tag = document.createElement('script');
  258 + tag.onerror = function(e) {
  259 + self.onError(e);
  260 + };
  261 + tag.src = ( !this.forceSSL && window.location.protocol !== 'file:' ) ?
  262 + '//www.youtube.com/iframe_api'
  263 + : 'https://www.youtube.com/iframe_api';
  264 + var firstScriptTag = document.getElementsByTagName('script')[0];
  265 + firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  266 + videojs.Youtube.apiLoading = true;
  267 + }
  268 + }
  269 + }
  270 + };
  271 +
  272 + videojs.Youtube.prototype.onWaiting = function(/*e*/) {
  273 + // Make sure to hide the play button while the spinner is there
  274 + if(typeof this.player_.bigPlayButton !== 'undefined') {
  275 + this.player_.bigPlayButton.hide();
  276 + }
  277 + };
  278 +
  279 + videojs.Youtube.prototype.addIframeBlocker = function(ieVersion) {
  280 + this.iframeblocker = videojs.Component.prototype.createEl('div');
  281 +
  282 + this.iframeblocker.className = 'iframeblocker';
  283 +
  284 + this.iframeblocker.style.position = 'absolute';
  285 + this.iframeblocker.style.left = 0;
  286 + this.iframeblocker.style.right = 0;
  287 + this.iframeblocker.style.top = 0;
  288 + this.iframeblocker.style.bottom = 0;
  289 +
  290 + // Odd quirk for IE8 (doesn't support rgba)
  291 + if(ieVersion && ieVersion < 9) {
  292 + this.iframeblocker.style.opacity = 0.01;
  293 + } else {
  294 + this.iframeblocker.style.background = 'rgba(255, 255, 255, 0.01)';
  295 + }
  296 +
  297 + var self = this;
  298 + addEventListener(this.iframeblocker, 'mousemove', function(e) {
  299 + if(!self.player_.userActive()) {
  300 + self.player_.userActive(true);
  301 + }
  302 +
  303 + e.stopPropagation();
  304 + e.preventDefault();
  305 + });
  306 +
  307 + addEventListener(this.iframeblocker, 'click', function(/*e*/) {
  308 + if(self.paused()) {
  309 + self.play();
  310 + } else {
  311 + self.pause();
  312 + }
  313 + });
  314 +
  315 + this.playerEl_.insertBefore(this.iframeblocker, this.el_.nextSibling);
  316 + };
  317 +
  318 + videojs.Youtube.prototype.parseSrc = function(src) {
  319 + this.srcVal = src;
  320 +
  321 + if(src) {
  322 + // Regex to parse the video ID
  323 + var regId = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
  324 + var match = src.match(regId);
  325 +
  326 + if(match && match[2].length === 11) {
  327 + this.videoId = match[2];
  328 + } else {
  329 + this.videoId = null;
  330 + }
  331 +
  332 + // Regex to parse the playlist ID
  333 + var regPlaylist = /[?&]list=([^#\&\?]+)/;
  334 + match = src.match(regPlaylist);
  335 +
  336 + if(match !== null && match.length > 1) {
  337 + this.playlistId = match[1];
  338 + } else {
  339 + // Make sure their is no playlist
  340 + if(this.playlistId) {
  341 + delete this.playlistId;
  342 + }
  343 + }
  344 +
  345 + // Parse video quality option
  346 + var regVideoQuality = /[?&]vq=([^#\&\?]+)/;
  347 + match = src.match(regVideoQuality);
  348 +
  349 + if(match !== null && match.length > 1) {
  350 + this.userQuality = match[1];
  351 + setInnerText(this.qualityTitle, videojs.Youtube.parseQualityName(this.userQuality));
  352 + }
  353 + }
  354 + };
  355 +
  356 + videojs.Youtube.prototype.src = function(src) {
  357 + if(typeof src !== 'undefined') {
  358 + this.parseSrc(src);
  359 +
  360 + if(this.el_.src === 'about:blank') {
  361 + this.updateIframeSrc();
  362 + return;
  363 + }
  364 +
  365 + delete this.defaultQuality;
  366 +
  367 + if(this.videoId !== null) {
  368 + if(this.player_.options()['autoplay'] && this.playVideoIsAllowed) {
  369 + this.ytplayer.loadVideoById({
  370 + videoId: this.videoId,
  371 + suggestedQuality: this.userQuality
  372 + });
  373 + } else {
  374 + this.ytplayer.cueVideoById({
  375 + videoId: this.videoId,
  376 + suggestedQuality: this.userQuality
  377 + });
  378 + }
  379 +
  380 + // Update the poster
  381 + this.playerEl_.querySelectorAll('.vjs-poster')[0].style.backgroundImage =
  382 + 'url(https://img.youtube.com/vi/' + this.videoId + '/0.jpg)';
  383 + this.player_.poster('https://img.youtube.com/vi/' + this.videoId + '/0.jpg');
  384 + }
  385 + /* else Invalid URL */
  386 + }
  387 +
  388 + return this.srcVal;
  389 + };
  390 +
  391 + videojs.Youtube.prototype.load = function() {
  392 + };
  393 +
  394 + videojs.Youtube.prototype.play = function() {
  395 + if(this.videoId !== null) {
  396 +
  397 + // Make sure to not display the spinner for mobile
  398 + if(!this.player_.options()['ytcontrols']) {
  399 + // Display the spinner until the video is playing by YouTube
  400 + this.player_.trigger('waiting');
  401 + }
  402 +
  403 + if(this.isReady_) {
  404 + // Sync the player volume with YouTube
  405 + this.ytplayer.setVolume(this.player_.volume() * 100);
  406 +
  407 + if(this.volumeVal > 0) {
  408 + this.ytplayer.unMute();
  409 + } else {
  410 + this.ytplayer.mute();
  411 + }
  412 +
  413 + if(this.playVideoIsAllowed) {
  414 + this.ytplayer.playVideo();
  415 + }
  416 + } else {
  417 + this.playOnReady = true;
  418 + }
  419 + }
  420 + };
  421 +
  422 + videojs.Youtube.prototype.pause = function() {
  423 + this.ytplayer.pauseVideo();
  424 + };
  425 + videojs.Youtube.prototype.paused = function() {
  426 + return (this.ytplayer) ?
  427 + (this.lastState !== YT.PlayerState.PLAYING && this.lastState !== YT.PlayerState.BUFFERING)
  428 + : true;
  429 + };
  430 + videojs.Youtube.prototype.currentTime = function() {
  431 + return (this.ytplayer && this.ytplayer.getCurrentTime) ? this.ytplayer.getCurrentTime() : 0;
  432 + };
  433 + videojs.Youtube.prototype.setCurrentTime = function(seconds) {
  434 + this.ytplayer.seekTo(seconds, true);
  435 + this.player_.trigger('timeupdate');
  436 + this.player_.trigger('seeking');
  437 + this.isSeeking = true;
  438 + };
  439 + videojs.Youtube.prototype.playbackRate = function() {
  440 + return (this.ytplayer && this.ytplayer.getPlaybackRate) ? this.ytplayer.getPlaybackRate() : 1.0;
  441 + };
  442 + videojs.Youtube.prototype.setPlaybackRate = function(suggestedRate) {
  443 + if (this.ytplayer && this.ytplayer.setPlaybackRate) {
  444 + this.ytplayer.setPlaybackRate(suggestedRate);
  445 + this.player_.trigger('ratechange');
  446 + }
  447 + };
  448 + videojs.Youtube.prototype.duration = function() {
  449 + return (this.ytplayer && this.ytplayer.getDuration) ? this.ytplayer.getDuration() : 0;
  450 + };
  451 + videojs.Youtube.prototype.currentSrc = function() {
  452 + return this.srcVal;
  453 + };
  454 + videojs.Youtube.prototype.ended = function() {
  455 + return (this.ytplayer) ? (this.lastState === YT.PlayerState.ENDED) : false;
  456 + };
  457 +
  458 + videojs.Youtube.prototype.volume = function() {
  459 + if(this.ytplayer && isNaN(this.volumeVal)) {
  460 + this.volumeVal = this.ytplayer.getVolume() / 100.0;
  461 + this.player_.volume(this.volumeVal);
  462 + }
  463 +
  464 + return this.volumeVal;
  465 + };
  466 +
  467 + videojs.Youtube.prototype.setVolume = function(percentAsDecimal) {
  468 + if(typeof(percentAsDecimal) !== 'undefined' && percentAsDecimal !== this.volumeVal) {
  469 + this.ytplayer.setVolume(percentAsDecimal * 100.0);
  470 + this.volumeVal = percentAsDecimal;
  471 + this.player_.trigger('volumechange');
  472 + }
  473 + };
  474 +
  475 + videojs.Youtube.prototype.muted = function() {
  476 + return this.mutedVal;
  477 + };
  478 + videojs.Youtube.prototype.setMuted = function(muted) {
  479 + if(muted) {
  480 + this.storedVolume = this.volumeVal;
  481 + this.ytplayer.mute();
  482 + this.player_.volume(0);
  483 + } else {
  484 + this.ytplayer.unMute();
  485 + this.player_.volume(this.storedVolume);
  486 + }
  487 +
  488 + this.mutedVal = muted;
  489 +
  490 + this.player_.trigger('volumechange');
  491 + };
  492 +
  493 + videojs.Youtube.prototype.buffered = function() {
  494 + if(this.ytplayer && this.ytplayer.getVideoBytesLoaded) {
  495 + var loadedBytes = this.ytplayer.getVideoBytesLoaded();
  496 + var totalBytes = this.ytplayer.getVideoBytesTotal();
  497 + if(!loadedBytes || !totalBytes) {
  498 + return 0;
  499 + }
  500 +
  501 + var duration = this.ytplayer.getDuration();
  502 + var secondsBuffered = (loadedBytes / totalBytes) * duration;
  503 + var secondsOffset = (this.ytplayer.getVideoStartBytes() / totalBytes) * duration;
  504 +
  505 + return videojs.createTimeRange(secondsOffset, secondsOffset + secondsBuffered);
  506 + } else {
  507 + return videojs.createTimeRange(0, 0);
  508 + }
  509 + };
  510 +
  511 + videojs.Youtube.prototype.supportsFullScreen = function() {
  512 + if (typeof this.el_.webkitEnterFullScreen === 'function') {
  513 +
  514 + // Seems to be broken in Chromium/Chrome && Safari in Leopard
  515 + if (/Android/.test(videojs.USER_AGENT) || !/Chrome|Mac OS X 10.5/.test(videojs.USER_AGENT)) {
  516 + return true;
  517 + }
  518 + }
  519 + return false;
  520 + };
  521 +
  522 + // YouTube is supported on all platforms
  523 + videojs.Youtube.isSupported = function() {
  524 + return true;
  525 + };
  526 +
  527 + // You can use video/youtube as a media in your HTML5 video to specify the source
  528 + videojs.Youtube.canPlaySource = function(srcObj) {
  529 + return (srcObj.type === 'video/youtube');
  530 + };
  531 +
  532 + // Always can control the volume
  533 + videojs.Youtube.canControlVolume = function() {
  534 + return true;
  535 + };
  536 +
  537 + ////////////////////////////// YouTube specific functions //////////////////////////////
  538 +
  539 + // All videos created before YouTube API is loaded
  540 + videojs.Youtube.loadingQueue = [];
  541 +
  542 + // Create the YouTube player
  543 + videojs.Youtube.prototype.loadYoutube = function() {
  544 + this.ytplayer = new YT.Player(this.id_, {
  545 + events: {
  546 + onReady: function(e) {
  547 + e.target.vjsTech.onReady();
  548 + },
  549 + onStateChange: function(e) {
  550 + e.target.vjsTech.onStateChange(e.data);
  551 + },
  552 + onPlaybackQualityChange: function(e) {
  553 + e.target.vjsTech.onPlaybackQualityChange(e.data);
  554 + },
  555 + onError: function(e) {
  556 + e.target.vjsTech.onError(e.data);
  557 + }
  558 + }
  559 + });
  560 +
  561 + this.ytplayer.vjsTech = this;
  562 + };
  563 +
  564 + // Transform a JavaScript object into URL params
  565 + videojs.Youtube.makeQueryString = function(args) {
  566 + var array = ['modestbranding=1'];
  567 + for(var key in args) {
  568 + if(args.hasOwnProperty(key)) {
  569 + array.push(key + '=' + args[key]);
  570 + }
  571 + }
  572 +
  573 + return array.join('&');
  574 + };
  575 +
  576 + // Called when YouTube API is ready to be used
  577 + window.onYouTubeIframeAPIReady = function() {
  578 + var yt;
  579 + while((yt = videojs.Youtube.loadingQueue.shift())) {
  580 + yt.loadYoutube();
  581 + }
  582 + videojs.Youtube.loadingQueue = [];
  583 + videojs.Youtube.apiReady = true;
  584 + };
  585 +
  586 + videojs.Youtube.prototype.onReady = function() {
  587 + this.isReady_ = true;
  588 + this.triggerReady();
  589 +
  590 + this.player_.trigger('loadedmetadata');
  591 +
  592 + // The duration is loaded so we might as well fire off the timeupdate and duration events
  593 + // this allows for the duration of the video (timeremaining) to be displayed if styled
  594 + // to show the control bar initially. This gives the user the ability to see how long the video
  595 + // is before clicking play
  596 + this.player_.trigger('durationchange');
  597 + this.player_.trigger('timeupdate');
  598 +
  599 + // Let the player take care of itself as soon as the YouTube is ready
  600 + // The loading spinner while waiting for the tech would be impossible otherwise
  601 + if (typeof this.player_.loadingSpinner !== 'undefined' && !this.isIos && !this.isAndroid) {
  602 + this.player_.loadingSpinner.hide();
  603 + }
  604 +
  605 + if(this.player_.options()['muted']) {
  606 + this.setMuted(true);
  607 + }
  608 +
  609 + // Play ASAP if they clicked play before it's ready
  610 + if(this.playOnReady) {
  611 + this.playOnReady = false;
  612 + this.play();
  613 + }
  614 + };
  615 +
  616 + videojs.Youtube.prototype.updateQualities = function() {
  617 +
  618 + function setupEventListener(el) {
  619 + addEventListener(el, 'click', function() {
  620 + var quality = this.getAttribute('data-val');
  621 + self.ytplayer.setPlaybackQuality(quality);
  622 +
  623 + self.userQuality = quality;
  624 + setInnerText(self.qualityTitle, videojs.Youtube.parseQualityName(quality));
  625 +
  626 + var selected = self.qualityMenuContent.querySelector('.vjs-selected');
  627 + if(selected) {
  628 + videojs.Youtube.removeClass(selected, 'vjs-selected');
  629 + }
  630 +
  631 + videojs.Youtube.addClass(this, 'vjs-selected');
  632 + });
  633 + }
  634 +
  635 + var qualities = this.ytplayer.getAvailableQualityLevels();
  636 + var self = this;
  637 +
  638 + if(qualities.indexOf(this.userQuality) < 0) {
  639 + setInnerText(self.qualityTitle, videojs.Youtube.parseQualityName(this.defaultQuality));
  640 + }
  641 +
  642 + if(qualities.length === 0) {
  643 + this.qualityButton.style.display = 'none';
  644 + } else {
  645 + this.qualityButton.style.display = '';
  646 +
  647 + while(this.qualityMenuContent.hasChildNodes()) {
  648 + this.qualityMenuContent.removeChild(this.qualityMenuContent.lastChild);
  649 + }
  650 +
  651 + for(var i = 0; i < qualities.length; ++i) {
  652 + var el = document.createElement('li');
  653 + el.setAttribute('class', 'vjs-menu-item');
  654 + setInnerText(el, videojs.Youtube.parseQualityName(qualities[i]));
  655 + el.setAttribute('data-val', qualities[i]);
  656 + if(qualities[i] === this.quality) {
  657 + videojs.Youtube.addClass(el, 'vjs-selected');
  658 + }
  659 + setupEventListener(el);
  660 +
  661 +
  662 + this.qualityMenuContent.appendChild(el);
  663 + }
  664 + }
  665 + };
  666 +
  667 + videojs.Youtube.prototype.onStateChange = function(state) {
  668 + if(state !== this.lastState) {
  669 + switch(state) {
  670 + case -1:
  671 + this.player_.trigger('durationchange');
  672 + break;
  673 +
  674 + case YT.PlayerState.ENDED:
  675 + // Replace YouTube play button by our own
  676 + if(!this.player_.options()['ytcontrols']) {
  677 + this.playerEl_.querySelectorAll('.vjs-poster')[0].style.display = 'block';
  678 + if(typeof this.player_.bigPlayButton !== 'undefined') {
  679 + this.player_.bigPlayButton.show();
  680 + }
  681 + }
  682 +
  683 + this.player_.trigger('ended');
  684 + break;
  685 +
  686 + case YT.PlayerState.PLAYING:
  687 + this.playerEl_.querySelectorAll('.vjs-poster')[0].style.display = '';
  688 +
  689 + this.playVideoIsAllowed = true;
  690 + this.updateQualities();
  691 + this.player_.trigger('timeupdate');
  692 + this.player_.trigger('durationchange');
  693 + this.player_.trigger('playing');
  694 + this.player_.trigger('play');
  695 +
  696 + if (this.isSeeking) {
  697 + this.player_.trigger('seeked');
  698 + this.isSeeking = false;
  699 + }
  700 + break;
  701 +
  702 + case YT.PlayerState.PAUSED:
  703 + this.player_.trigger('pause');
  704 + break;
  705 +
  706 + case YT.PlayerState.BUFFERING:
  707 + this.player_.trigger('timeupdate');
  708 +
  709 + // Make sure to not display the spinner for mobile
  710 + if(!this.player_.options()['ytcontrols']) {
  711 + this.player_.trigger('waiting');
  712 + }
  713 + break;
  714 +
  715 + case YT.PlayerState.CUED:
  716 + break;
  717 + }
  718 +
  719 + this.lastState = state;
  720 + }
  721 + };
  722 +
  723 + videojs.Youtube.convertQualityName = function(name) {
  724 + switch(name) {
  725 + case '144p':
  726 + return 'tiny';
  727 +
  728 + case '240p':
  729 + return 'small';
  730 +
  731 + case '360p':
  732 + return 'medium';
  733 +
  734 + case '480p':
  735 + return 'large';
  736 +
  737 + case '720p':
  738 + return 'hd720';
  739 +
  740 + case '1080p':
  741 + return 'hd1080';
  742 + }
  743 +
  744 + return 'auto';
  745 + };
  746 +
  747 + videojs.Youtube.parseQualityName = function(name) {
  748 + switch(name) {
  749 + case 'tiny':
  750 + return '144p';
  751 +
  752 + case 'small':
  753 + return '240p';
  754 +
  755 + case 'medium':
  756 + return '360p';
  757 +
  758 + case 'large':
  759 + return '480p';
  760 +
  761 + case 'hd720':
  762 + return '720p';
  763 +
  764 + case 'hd1080':
  765 + return '1080p';
  766 + }
  767 +
  768 + return 'auto';
  769 + };
  770 +
  771 + videojs.Youtube.prototype.onPlaybackQualityChange = function(quality) {
  772 + if(typeof this.defaultQuality === 'undefined') {
  773 + this.defaultQuality = quality;
  774 +
  775 + if(typeof this.userQuality !== 'undefined') {
  776 + return;
  777 + }
  778 + }
  779 +
  780 + this.quality = quality;
  781 + setInnerText(this.qualityTitle, videojs.Youtube.parseQualityName(quality));
  782 +
  783 + switch(quality) {
  784 + case 'medium':
  785 + this.player_.videoWidth = 480;
  786 + this.player_.videoHeight = 360;
  787 + break;
  788 +
  789 + case 'large':
  790 + this.player_.videoWidth = 640;
  791 + this.player_.videoHeight = 480;
  792 + break;
  793 +
  794 + case 'hd720':
  795 + this.player_.videoWidth = 960;
  796 + this.player_.videoHeight = 720;
  797 + break;
  798 +
  799 + case 'hd1080':
  800 + this.player_.videoWidth = 1440;
  801 + this.player_.videoHeight = 1080;
  802 + break;
  803 +
  804 + case 'highres':
  805 + this.player_.videoWidth = 1920;
  806 + this.player_.videoHeight = 1080;
  807 + break;
  808 +
  809 + case 'small':
  810 + this.player_.videoWidth = 320;
  811 + this.player_.videoHeight = 240;
  812 + break;
  813 +
  814 + case 'tiny':
  815 + this.player_.videoWidth = 144;
  816 + this.player_.videoHeight = 108;
  817 + break;
  818 +
  819 + default:
  820 + this.player_.videoWidth = 0;
  821 + this.player_.videoHeight = 0;
  822 + break;
  823 + }
  824 +
  825 + this.player_.trigger('ratechange');
  826 + };
  827 +
  828 + videojs.Youtube.prototype.onError = function(error) {
  829 + this.player_.error(error);
  830 +
  831 + if(error === 100 || error === 101 || error === 150) {
  832 + this.player_.bigPlayButton.hide();
  833 + this.player_.loadingSpinner.hide();
  834 + this.player_.posterImage.hide();
  835 + }
  836 + };
  837 +
  838 + /**
  839 + * Add a CSS class name to an element
  840 + * @param {Element} element Element to add class name to
  841 + * @param {String} classToAdd Classname to add
  842 + */
  843 + videojs.Youtube.addClass = function(element, classToAdd) {
  844 + if((' ' + element.className + ' ').indexOf(' ' + classToAdd + ' ') === -1) {
  845 + element.className = element.className === '' ? classToAdd : element.className + ' ' + classToAdd;
  846 + }
  847 + };
  848 +
  849 + /**
  850 + * Remove a CSS class name from an element
  851 + * @param {Element} element Element to remove from class name
  852 + * @param {String} classToRemove Classname to remove
  853 + */
  854 + videojs.Youtube.removeClass = function(element, classToRemove) {
  855 + var classNames, i;
  856 +
  857 + if(element.className.indexOf(classToRemove) === -1) {
  858 + return;
  859 + }
  860 +
  861 + classNames = element.className.split(' ');
  862 +
  863 + // no arr.indexOf in ie8, and we don't want to add a big shim
  864 + for(i = classNames.length - 1; i >= 0; i--) {
  865 + if(classNames[i] === classToRemove) {
  866 + classNames.splice(i, 1);
  867 + }
  868 + }
  869 +
  870 + element.className = classNames.join(' ');
  871 + };
  872 +
  873 + // Cross-browsers support (IE8 wink wink)
  874 + function setInnerText(element, text) {
  875 + if(typeof element === 'undefined') {
  876 + return false;
  877 + }
  878 +
  879 + var textProperty = ('innerText' in element) ? 'innerText' : 'textContent';
  880 +
  881 + try {
  882 + element[textProperty] = text;
  883 + } catch(anException) {
  884 + //IE<9 FIX
  885 + element.setAttribute('innerText', text);
  886 + }
  887 + }
  888 +
  889 +
  890 +// Stretch the YouTube poster
  891 + var style = document.createElement('style');
  892 + var def = ' ' +
  893 + '.vjs-youtube .vjs-poster { background-size: 100%!important; }' +
  894 + '.vjs-youtube .vjs-poster, ' +
  895 + '.vjs-youtube .vjs-loading-spinner, ' +
  896 + '.vjs-youtube .vjs-big-play-button, .vjs-youtube .vjs-text-track-display{ pointer-events: none !important; }' +
  897 + '.vjs-youtube.vjs-user-active .iframeblocker { display: none; }' +
  898 + '.vjs-youtube.vjs-user-inactive .vjs-tech.onDesktop { pointer-events: none; }' +
  899 + '.vjs-quality-button > div:first-child > span:first-child { position:relative;top:7px }';
  900 +
  901 + style.setAttribute('type', 'text/css');
  902 + document.getElementsByTagName('head')[0].appendChild(style);
  903 +
  904 + if(style.styleSheet) {
  905 + style.styleSheet.cssText = def;
  906 + } else {
  907 + style.appendChild(document.createTextNode(def));
  908 + }
  909 +
  910 + // IE8 fix for indexOf
  911 + if(!Array.prototype.indexOf) {
  912 + Array.prototype.indexOf = function(elt /*, from*/) {
  913 + var len = this.length >>> 0; // jshint ignore:line
  914 +
  915 + var from = Number(arguments[1]) || 0;
  916 + from = (from < 0) ?
  917 + Math.ceil(from)
  918 + : Math.floor(from);
  919 + if(from < 0) {
  920 + from += len;
  921 + }
  922 +
  923 + for(; from < len; from++) {
  924 + if(from in this && this[from] === elt) {
  925 + return from;
  926 + }
  927 + }
  928 + return -1;
  929 + };
  930 + }
  931 +})();
plugins/video/public/style.css
@@ -38,5 +38,23 @@ @@ -38,5 +38,23 @@
38 } 38 }
39 39
40 .video-gallery-thumbnail:hover div{ 40 .video-gallery-thumbnail:hover div{
41 - display: inline-block; 41 + display: inline-block;
  42 +}
  43 +
  44 +.video-gallery-table-big{
  45 + width: 100%;
  46 + overflow: hidden;
  47 +}
  48 +
  49 +.video-gallery-left-column-big{
  50 + width: 350px;
  51 + float: left;
  52 +}
  53 +
  54 +.video-gallery-right-column-big{
  55 + margin-left: 370px;
  56 +}
  57 +
  58 +.video-title-big{
  59 + font-size: 2em;
42 } 60 }
43 \ No newline at end of file 61 \ No newline at end of file
plugins/video/views/content_viewer/video_plugin/_video.html.erb
1 <div align="center"> 1 <div align="center">
2 <%if @page.video_provider=='youtube' %> 2 <%if @page.video_provider=='youtube' %>
3 <link type="text/css" rel="stylesheet" href="/plugins/video/css/video-js-4.5.1.css" /> 3 <link type="text/css" rel="stylesheet" href="/plugins/video/css/video-js-4.5.1.css" />
4 - <video id="embedded_video" src="" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto" 4 + <video id="embedded_video<%= rand %>" src="" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto"
5 width="<%= @page.fitted_width %>" height="<%= @page.fitted_height %>" 5 width="<%= @page.fitted_width %>" height="<%= @page.fitted_height %>"
6 data-setup='<%=CGI::escapeHTML("{ \"techOrder\": [\"youtube\"], \"src\": \"#{@page.video_url}\" }") %>'> 6 data-setup='<%=CGI::escapeHTML("{ \"techOrder\": [\"youtube\"], \"src\": \"#{@page.video_url}\" }") %>'>
7 <%= @page.no_browser_support_message %> 7 <%= @page.no_browser_support_message %>
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 <script src="/plugins/video/javascripts/videojs/vjs.youtube.js"></script> 10 <script src="/plugins/video/javascripts/videojs/vjs.youtube.js"></script>
11 <% elsif @page.video_provider=='vimeo' %> 11 <% elsif @page.video_provider=='vimeo' %>
12 <link type="text/css" rel="stylesheet" href="/plugins/video/css/video-js-4.5.1.css" /> 12 <link type="text/css" rel="stylesheet" href="/plugins/video/css/video-js-4.5.1.css" />
13 - <video id="embedded_video" src="" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto" 13 + <video id="embedded_video<%= rand %>" src="" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto"
14 width="<%= @page.fitted_width %>" height="<%= @page.fitted_height %>" 14 width="<%= @page.fitted_width %>" height="<%= @page.fitted_height %>"
15 data-setup='<%=CGI::escapeHTML("{ \"techOrder\": [\"vimeo\"], \"src\": \"#{@page.video_url}\", \"loop\": true, \"autoplay\": false }") %>'> 15 data-setup='<%=CGI::escapeHTML("{ \"techOrder\": [\"vimeo\"], \"src\": \"#{@page.video_url}\", \"loop\": true, \"autoplay\": false }") %>'>
16 <%= @page.no_browser_support_message %> 16 <%= @page.no_browser_support_message %>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <% elsif @page.video_provider=='file' %> 20 <% elsif @page.video_provider=='file' %>
21 <link href="/plugins/video/css/video-js-4.8.5.css" rel="stylesheet"> 21 <link href="/plugins/video/css/video-js-4.8.5.css" rel="stylesheet">
22 <script src="/plugins/video/javascripts/videojs/video-4.8.5.js"></script> 22 <script src="/plugins/video/javascripts/videojs/video-4.8.5.js"></script>
23 - <video id="embedded_video" class="video-js vjs-default-skin vjs-big-play-centered" 23 + <video id="embedded_video<%= rand %>" class="video-js vjs-default-skin vjs-big-play-centered"
24 height="353" width="499" 24 height="353" width="499"
25 controls preload="auto" 25 controls preload="auto"
26 data-setup='<%=CGI::escapeHTML("{ \"example_option\":true}") %>'> 26 data-setup='<%=CGI::escapeHTML("{ \"example_option\":true}") %>'>
plugins/video/views/content_viewer/video_plugin/video_video.html.erb
@@ -1,34 +0,0 @@ @@ -1,34 +0,0 @@
1 -<div align="center">  
2 -<%if @page.video_provider=='youtube' %>  
3 - <link type="text/css" rel="stylesheet" href="https://vjs.zencdn.net/4.5.1/video-js.css" />  
4 - <video id="embedded_video" src="" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto"  
5 - width="<%= @page.fitted_width %>" height="<%= @page.fitted_height %>"  
6 - data-setup='{ "techOrder": ["youtube"], "src": "<%= @page.video_url %>" }'>  
7 - <%= @page.no_browser_support_message %>  
8 - </video>  
9 - <script src="https://vjs.zencdn.net/4.5.1/video.js"></script>  
10 - <script src="/plugins/video/javascripts/videojs/vjs.youtube.js"></script>  
11 - <% elsif @page.video_provider=='vimeo' %>  
12 - <link type="text/css" rel="stylesheet" href="https://vjs.zencdn.net/4.5.1/video-js.css" />  
13 - <video id="embedded_video" src="" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto"  
14 - width="<%= @page.fitted_width %>" height="<%= @page.fitted_height %>"  
15 - data-setup='{ "techOrder": ["vimeo"], "src": "<%= @page.video_url %>", "loop": true, "autoplay": false }'>  
16 - <%= @page.no_browser_support_message %>  
17 - </video>  
18 - <script src="https://vjs.zencdn.net/4.5.1/video.js"></script>  
19 - <script src="/plugins/video/javascripts/videojs/vjs.vimeo.js"></script>  
20 -<% elsif @page.video_provider=='file' %>  
21 - <link href="https://vjs.zencdn.net/4.8/video-js.css" rel="stylesheet">  
22 - <script src="https://vjs.zencdn.net/4.8/video.js"></script>  
23 - <video id="embedded_video" class="video-js vjs-default-skin vjs-big-play-centered"  
24 - height="353" width="499"  
25 - controls preload="auto"  
26 - data-setup='{"example_option":true}'>  
27 - <source src="<%= @page.video_url %>" type='<%= @page.video_format %>' />  
28 - <%= @page.no_browser_support_message %>  
29 - </video>  
30 -<% end %>  
31 -<br style="clear:both" />  
32 -</div>  
33 -<% _("Description:") %>  
34 -<%= @page.body %>  
35 \ No newline at end of file 0 \ No newline at end of file
plugins/video/views/content_viewer/video_plugin/video_video_gallery.html.erb
@@ -1,28 +0,0 @@ @@ -1,28 +0,0 @@
1 -<%  
2 -def self.list_videos(configure={})  
3 - configure[:recursive] ||= false  
4 - configure[:list_type] ||= :folder  
5 - if !configure[:contents].blank?  
6 - configure[:contents] = configure[:contents].paginate(  
7 - :order => "updated_at DESC",  
8 - :per_page => 16,  
9 - :page => params[:npage]  
10 - )  
11 - render :file => 'shared/video_list', :locals => configure  
12 - else  
13 - content_tag('em', _('(empty folder)'))  
14 - end  
15 - end  
16 -%>  
17 -<% unless video_gallery.body.blank? %>  
18 - <div>  
19 - <%= video_gallery.body %>  
20 - </div>  
21 - <hr/>  
22 -<% end %>  
23 -  
24 -<% if video_gallery.children.empty? %>  
25 - <em><%= _('(empty video gallery)') %></em>  
26 -<% else %>  
27 - <%= list_videos(:contents=>video_gallery.children) %>  
28 -<% end %>  
29 \ No newline at end of file 0 \ No newline at end of file
plugins/video/views/shared/video_list.html.erb
1 <div> 1 <div>
2 - <% contents.each do |content| %> 2 + <%
  3 + first_video = contents[0]
  4 + first_video_arr = Array.new
  5 + first_video_arr.push(first_video)
  6 + other_videos = contents - first_video_arr %>
  7 + <% if first_video.display_to?(user) %>
  8 + <div class="video-gallery-table-big">
  9 + <div class="video-gallery-left-column-big">
  10 + <%= link_to first_video.view_url do %>
  11 + <img width="320" height="320" src='<%= first_video.video_thumbnail_url %>' class="disable-zoom"/>
  12 + <% end %>
  13 + </div>
  14 + <div class="video-gallery-right-column-big">
  15 + <div class="video-title-big"><%= first_video.title %></div>
  16 + <div class="video-author-big">
  17 + <%= _("by") %> <%= first_video.author_name %> <%= _("updated at") %> <%= time_ago_as_sentence(first_video.updated_at) %>
  18 + </div>
  19 + </div>
  20 + </div>
  21 + <% end %>
  22 + <% other_videos.each do |content| %>
3 <% if content.display_to?(user) %> 23 <% if content.display_to?(user) %>
4 <div class="video-gallery-thumbnail"> 24 <div class="video-gallery-thumbnail">
5 <div class="video-gallery-top-box"> 25 <div class="video-gallery-top-box">
6 <%= link_to content.view_url do %> 26 <%= link_to content.view_url do %>
7 - <img width="<%= content.thumbnail_fitted_width %>" height="<%= content.thumbnail_fitted_width %>" src='<%= content.video_thumbnail_url %>' class="disable-zoom"/> 27 + <img width="<%= content.thumbnail_fitted_width %>" height="<%= content.thumbnail_fitted_height %>" src='<%= content.video_thumbnail_url %>' class="disable-zoom"/>
8 <% end %> 28 <% end %>
9 </div> 29 </div>
10 <div class="video-gallery-botton-box"> 30 <div class="video-gallery-botton-box">
plugins/video/views/shared/video_plugin/apagar_video_block.html.erb 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +<h3 class="block-title">
  2 + <span><%=block.title%></span>
  3 +</h3>
  4 +<div class="video-block-data">
  5 + <% if block.is_youtube? %>
  6 + <div class='youtube'>
  7 + <%= render :partial => 'box_organizer/iframe_video_block', :locals => { :url => block.format_embed_video_url_for_youtube, :width => block.width, :height => block.height }%>
  8 + </div>
  9 + <% elsif block.is_vimeo? %>
  10 + <div class='vimeo'>
  11 + <%= render :partial => 'box_organizer/iframe_video_block', :locals => { :url => block.format_embed_video_url_for_vimeo, :width => block.width, :height => block.height }%>
  12 + </div>
  13 + <% elsif block.is_video_file? %>
  14 + <div class='video'>
  15 + <%= render :partial => 'box_organizer/html5_video_block', :locals => { :url => block.url, :width => block.width, :height => block.height }%>
  16 + </div>
  17 + <% else %>
  18 + <span class='alert-block'><%= _("Register a valid url (Vimeo, Youtube, video files)") %></span>
  19 + <% end %>
  20 +
  21 +</div>
plugins/video/views/shared/video_plugin/video_block.html.erb
@@ -1,21 +0,0 @@ @@ -1,21 +0,0 @@
1 -<h3 class="block-title">  
2 - <span><%=block.title%></span>  
3 -</h3>  
4 -<div class="video-block-data">  
5 - <% if block.is_youtube? %>  
6 - <div class='youtube'>  
7 - <%= render :partial => 'box_organizer/iframe_video_block', :locals => { :url => block.format_embed_video_url_for_youtube, :width => block.width, :height => block.height }%>  
8 - </div>  
9 - <% elsif block.is_vimeo? %>  
10 - <div class='vimeo'>  
11 - <%= render :partial => 'box_organizer/iframe_video_block', :locals => { :url => block.format_embed_video_url_for_vimeo, :width => block.width, :height => block.height }%>  
12 - </div>  
13 - <% elsif block.is_video_file? %>  
14 - <div class='video'>  
15 - <%= render :partial => 'box_organizer/html5_video_block', :locals => { :url => block.url, :width => block.width, :height => block.height }%>  
16 - </div>  
17 - <% else %>  
18 - <span class='alert-block'><%= _("Register a valid url (Vimeo, Youtube, video files)") %></span>  
19 - <% end %>  
20 -  
21 -</div>