src/js/widgets/playerWidget.js
branchnew-model
changeset 870 2c025db10a10
parent 842 4ae2247a59f4
child 874 38b65761a7d5
equal deleted inserted replaced
868:a525cc2214e7 870:2c025db10a10
    32         }
    32         }
    33     }
    33     }
    34 );
    34 );
    35 
    35 
    36 
    36 
    37 IriSP.PlayerWidget = function(Popcorn, config, Serializer) {
    37 IriSP.PlayerWidget = function(player, config) {
    38   IriSP.Widget.call(this, Popcorn, config, Serializer);
    38   IriSP.Widget.call(this, player, config);
    39   
    39   
    40   this._searchBlockOpen = false;
       
    41   this._searchLastValue = "";
    40   this._searchLastValue = "";
    42 };
    41 };
    43 
    42 
    44 IriSP.PlayerWidget.prototype = new IriSP.Widget();
    43 IriSP.PlayerWidget.prototype = new IriSP.Widget();
    45 
    44 
    46 IriSP.PlayerWidget.prototype.draw = function() {
    45 IriSP.PlayerWidget.prototype.draw = function() {
    47   var self = this;
    46     var _this = this,
    48   var width = this.width;
    47         _html = IriSP.templToHTML(IriSP.player_template, this);
    49 	var height = this.height;
    48     
    50 	var heightS = this.height-20;
    49     this.$.append(_html);
    51 	  
    50     
    52 	var playerTempl = IriSP.templToHTML(IriSP.player_template, this._config);
    51     // Define blocks
    53   this.selector.append(playerTempl);		
    52     this.$playButton = this.$.find(".Ldt-CtrlPlay");
    54 	
    53     this.$searchBlock = this.$.find(".LdtSearch");
    55   this.selector.children(".Ldt-controler").show();
    54     this.$searchInput = this.$.find(".LdtSearchInput");
    56     
    55     this.$volumeBar = this.$.find(".Ldt-Ctrl-Volume-Bar");
    57   // handle clicks by the user on the video.
    56     
    58   this._Popcorn.listen("play", IriSP.wrap(this, this.playButtonUpdater));
    57     // handle events
    59   this._Popcorn.listen("pause", IriSP.wrap(this, this.playButtonUpdater));
    58     this.bindPopcorn("play","playButtonUpdater");
    60   
    59     this.bindPopcorn("pause","playButtonUpdater");
    61   this._Popcorn.listen("volumechange", IriSP.wrap(this, this.volumeUpdater));
    60     this.bindPopcorn("volumechange","volumeUpdater");
    62 
    61     this.bindPopcorn("timeupdate","timeDisplayUpdater");
    63   this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeDisplayUpdater));  
    62     this.bindPopcorn("loadedmetadata","timeDisplayUpdater");
    64   // update the time display for the first time.
    63     this.bindPopcorn("IriSP.search.matchFound","searchMatch");
    65   this._Popcorn.listen("loadedmetadata", IriSP.wrap(this, this.timeDisplayUpdater));
    64     this.bindPopcorn("IriSP.search.noMatchFound","searchNoMatch");
    66   
    65     this.bindPopcorn("IriSP.search.triggeredSearch","triggeredSearch");
    67   this._Popcorn.listen("IriSP.search.matchFound", IriSP.wrap(this, this.searchMatch));
    66     
    68   this._Popcorn.listen("IriSP.search.noMatchFound", IriSP.wrap(this, this.searchNoMatch));
    67     // handle clicks
    69   this._Popcorn.listen("IriSP.search.triggeredSearch", IriSP.wrap(this, this.triggeredSearch));
    68     this.$playButton.click(this.functionWrapper("playHandler"));
    70   
    69     
    71   
    70     this.$.find(".Ldt-CtrlAnnotate").click(function() {
    72   this.selector.find(".Ldt-CtrlPlay").click(function() { self.playHandler.call(self); });
    71         _this.player.popcorn.trigger("IriSP.PlayerWidget.AnnotateButton.clicked");
    73   this.selector.find(".Ldt-CtrlAnnotate").click(function() 
    72     });
    74                                             { self._Popcorn.trigger("IriSP.PlayerWidget.AnnotateButton.clicked"); });
    73     this.$.find(".Ldt-CtrlSearch").click(this.functionWrapper("searchButtonHandler"));
    75   this.selector.find(".Ldt-CtrlSearch").click(function() { self.searchButtonHandler.call(self); });
    74     
    76   
    75     this.$searchInput.keyup(this.functionWrapper("searchHandler") );
    77 	var _volctrl = this.selector.find(".Ldt-Ctrl-Volume-Control");
    76   
    78     this.selector.find('.Ldt-CtrlSound')
    77 	var _volctrl = this.$.find(".Ldt-Ctrl-Volume-Control");
    79         .click(function() { self.muteHandler.call(self); } )
    78     this.$.find('.Ldt-CtrlSound')
       
    79         .click(this.functionWrapper("muteHandler"))
    80         .mouseover(function() {
    80         .mouseover(function() {
    81             _volctrl.show();
    81             _volctrl.show();
    82         })
    82         })
    83         .mouseout(function() {
    83         .mouseout(function() {
    84             _volctrl.hide();
    84             _volctrl.hide();
    87         _volctrl.show();
    87         _volctrl.show();
    88     }).mouseout(function() {
    88     }).mouseout(function() {
    89         _volctrl.hide();
    89         _volctrl.hide();
    90     });
    90     });
    91   
    91   
    92   /*
    92     
    93   var searchButtonPos = this.selector.find(".Ldt-CtrlSearch").position();
    93     // Allow Volume Cursor Dragging
    94   var searchBox = Mustache.to_html(IriSP.search_template, {margin_left : searchButtonPos.left + "px"});
    94     this.$volumeBar.slider({
    95   this.selector.find(".Ldt-CtrlSearch").after(searchBox);
    95         slide: function(event, ui) {
    96   */
    96             _this.$volumeBar.attr("title",IriSP.i18n.getMessage('volume')+': ' + ui.value + '%');
    97   
    97             _this.player.popcorn.volume(ui.value / 100);
    98   // trigger an IriSP.PlayerWidget.MouseOver to the widgets that are interested (i.e : sliderWidget)
    98         },
    99   this.selector.hover(function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOver"); }, 
    99         stop: this.functionWrapper("volumeUpdater")
   100                       function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOut"); });
   100     });
   101   this.selector.find(".Ldt-Ctrl-Volume-Cursor").draggable({
   101 
   102       axis: "x",
   102     // trigger an IriSP.PlayerWidget.MouseOver to the widgets that are interested (i.e : sliderWidget)
   103       drag: function(event, ui) {
   103     this.$.hover(
   104           var _vol = Math.max(0, Math.min( 1, ui.position.left / (ui.helper.parent().width() - ui.helper.outerWidth())));
   104         function() {
   105           ui.helper.attr("title",IriSP.i18n.getMessage('volume')+': ' + Math.floor(100*_vol) + '%');
   105             _this.player.popcorn.trigger("IriSP.PlayerWidget.MouseOver");
   106           self._Popcorn.volume(_vol);
   106         }, 
   107       },
   107         function() {
   108       containment: "parent"
   108             _this.player.popcorn.trigger("IriSP.PlayerWidget.MouseOut");
   109   });
   109         });
   110  
   110     setTimeout(this.functionWrapper("volumeUpdater"), 1000);
   111  setTimeout(function() {
   111     /* some players - including jwplayer - save the state of the mute button between sessions */
   112      self.volumeUpdater();
       
   113  }, 1000); /* some player - jwplayer notable - save the state of the mute button between sessions */
       
   114 };
   112 };
   115 
   113 
   116 /* Update the elasped time div */
   114 /* Update the elasped time div */
   117 IriSP.PlayerWidget.prototype.timeDisplayUpdater = function() {
   115 IriSP.PlayerWidget.prototype.timeDisplayUpdater = function() {
   118   
   116     var _curTime = this.player.popcorn.roundTime();
   119   if (this._previousSecond === undefined) {
   117     if (typeof this._previousSecond !== "undefined" && _curTime === this._previousSecond) {
   120     this._previousSecond = this._Popcorn.roundTime();
   118         return;
   121   }
   119     }
   122   else {
   120   
   123     /* we're still in the same second, so it's not necessary to update time */
   121     // we get it at each call because it may change.
   124     if (this._Popcorn.roundTime() == this._previousSecond)
   122     var _totalTime = this.source.getDuration(),
   125       return;
   123         _elapsedTime = new IriSP.Model.Time();
   126       
   124         
   127   }
   125     _elapsedTime.setSeconds(_curTime);
   128   
   126   
   129   // we get it at each call because it may change.
   127     this.$.find(".Ldt-ElapsedTime").html(_elapsedTime.toString());
   130   var duration = this.getDuration() / 1000; 
   128     this.$.find(".Ldt-TotalTime").html(_totalTime.toString());
   131   var totalTime = IriSP.secondsToTime(duration);
   129     this._previousSecond = _curTime;
   132   var elapsedTime = IriSP.secondsToTime(this._Popcorn.currentTime());
       
   133   
       
   134   this.selector.find(".Ldt-ElapsedTime").html(elapsedTime.toString());
       
   135   this.selector.find(".Ldt-TotalTime").html(totalTime.toString());
       
   136   this._previousSecond = this._Popcorn.roundTime();
       
   137 };
   130 };
   138 
   131 
   139 /* update the icon of the button - separate function from playHandler
   132 /* update the icon of the button - separate function from playHandler
   140    because in some cases (for instance, when the user directly clicks on
   133    because in some cases (for instance, when the user directly clicks on
   141    the jwplayer window) we have to change the icon without playing/pausing
   134    the jwplayer window) we have to change the icon without playing/pausing
   142 */
   135 */
   143 IriSP.PlayerWidget.prototype.playButtonUpdater = function() {
   136 IriSP.PlayerWidget.prototype.playButtonUpdater = function() {
   144   var status = this._Popcorn.media.paused;
   137     
   145   
   138     var status = this.player.popcorn.media.paused;
   146   if ( status == true ){
   139   
       
   140     if (status) {
   147     /* the background sprite is changed by adding/removing the correct classes */
   141     /* the background sprite is changed by adding/removing the correct classes */
   148     this.selector.find(".Ldt-CtrlPlay").attr("title", IriSP.i18n.getMessage('play'));
   142         this.$playButton
   149     this.selector.find(".Ldt-CtrlPlay").removeClass("Ldt-CtrlPlay-PauseState").addClass("Ldt-CtrlPlay-PlayState");
   143             .attr("title", IriSP.i18n.getMessage('play'))
   150   } else {
   144             .removeClass("Ldt-CtrlPlay-PauseState")
   151     this.selector.find(".Ldt-CtrlPlay").attr("title", IriSP.i18n.getMessage('pause'));
   145             .addClass("Ldt-CtrlPlay-PlayState");
   152     this.selector.find(".Ldt-CtrlPlay").removeClass("Ldt-CtrlPlay-PlayState").addClass("Ldt-CtrlPlay-PauseState");
   146     } else {
   153   }  
   147         this.$playButton
   154 
   148             .attr("title", IriSP.i18n.getMessage('pause'))
   155   return;
   149             .removeClass("Ldt-CtrlPlay-PlayState")
       
   150             .addClass("Ldt-CtrlPlay-PauseState");
       
   151     }
   156 };
   152 };
   157 
   153 
   158 
   154 
   159 IriSP.PlayerWidget.prototype.playHandler = function() {
   155 IriSP.PlayerWidget.prototype.playHandler = function() {
   160   var status = this._Popcorn.media.paused;
   156     
   161   
   157     var status = this.player.popcorn.media.paused;
   162   if ( status == true ){        
   158   
   163     this._Popcorn.play();   
   159     if (status) {        
   164   } else {
   160         this.player.popcorn.play();   
   165     this._Popcorn.pause();
   161     } else {
   166   }  
   162         this.player.popcorn.pause();
       
   163     }  
   167 };
   164 };
   168 
   165 
   169 IriSP.PlayerWidget.prototype.muteHandler = function() {
   166 IriSP.PlayerWidget.prototype.muteHandler = function() {
   170   this._Popcorn.mute(!this._Popcorn.muted());
   167     this.player.popcorn.mute(!this.player.popcorn.muted());
   171 };
   168 };
   172 
   169 
   173 IriSP.PlayerWidget.prototype.volumeUpdater = function() {
   170 IriSP.PlayerWidget.prototype.volumeUpdater = function() {
   174     var _muted = this._Popcorn.muted(),
   171     var _muted = this.player.popcorn.muted(),
   175         _vol = this._Popcorn.volume();
   172         _vol = this.player.popcorn.volume();
   176     if (_vol === false) {
   173     if (_vol === false) {
   177         _vol = .5;
   174         _vol = .5;
   178     }
   175     }
   179     var _soundCtl = this.selector.find(".Ldt-CtrlSound");
   176     var _soundCtl = this.$.find(".Ldt-CtrlSound");
   180     _soundCtl.removeClass("Ldt-CtrlSound-Mute Ldt-CtrlSound-Half Ldt-CtrlSound-Full");
   177     _soundCtl.removeClass("Ldt-CtrlSound-Mute Ldt-CtrlSound-Half Ldt-CtrlSound-Full");
   181     if (_muted) {        
   178     if (_muted) {        
   182         _soundCtl.attr("title", IriSP.i18n.getMessage('unmute'))
   179         _soundCtl.attr("title", IriSP.i18n.getMessage('unmute'))
   183             .addClass("Ldt-CtrlSound-Mute");    
   180             .addClass("Ldt-CtrlSound-Mute");    
   184     } else {
   181     } else {
   185         _soundCtl.attr("title", IriSP.i18n.getMessage('mute'))
   182         _soundCtl.attr("title", IriSP.i18n.getMessage('mute'))
   186             .addClass(_vol < .5 ? "Ldt-CtrlSound-Half" : "Ldt-CtrlSound-Full" )
   183             .addClass(_vol < .5 ? "Ldt-CtrlSound-Half" : "Ldt-CtrlSound-Full" )
   187     }
   184     }
   188     var _cursor = this.selector.find(".Ldt-Ctrl-Volume-Cursor");
   185     this.$volumeBar.slider("value", _muted ? 0 : 100 * _vol);
   189     _cursor.css({
       
   190         "left": ( _muted ? 0 : Math.floor(_vol * (_cursor.parent().width() - _cursor.outerWidth())) ) + "px"
       
   191     })
       
   192 };
   186 };
   193 
   187 
   194 IriSP.PlayerWidget.prototype.showSearchBlock = function() {
   188 IriSP.PlayerWidget.prototype.showSearchBlock = function() {
   195   var self = this;
   189     this.$searchBlock.show("blind", { direction: "horizontal"}, 100);
   196   
   190     this.$searchInput.css('background-color','#fff');
   197   if (this._searchBlockOpen == false) {
       
   198     this.selector.find(".LdtSearch").show("blind", { direction: "horizontal"}, 100);
       
   199     this.selector.find(".LdtSearchInput").css('background-color','#fff');
       
   200    
   191    
   201     this._searchBlockOpen = true;           
   192     this.$searchInput.focus();
   202     this.selector.find(".LdtSearchInput").bind('keyup', null, function() { self.searchHandler.call(self); } );
   193     
   203     this.selector.find(".LdtSearchInput").focus();
   194     // we need this variable because some widgets can find a match in
   204     
   195     // their data while at the same time others don't. As we want the
   205     // we need this variable because some widget can find a match in
       
   206     // their data while at the same time other's don't. As we want the
       
   207     // search field to become green when there's a match, we need a 
   196     // search field to become green when there's a match, we need a 
   208     // variable to remember that we had one.
   197     // variable to remember that we had one.
   209     this._positiveMatch = false;
   198     this._positiveMatch = false;
   210 
   199 
   211     // tell the world the field is open
   200     // tell the world the field is open
   212     this._Popcorn.trigger("IriSP.search.open");     
   201     this.player.popcorn.trigger("IriSP.search.open");
   213 	}
       
   214 };
   202 };
   215 
   203 
   216 IriSP.PlayerWidget.prototype.hideSearchBlock = function() {
   204 IriSP.PlayerWidget.prototype.hideSearchBlock = function() {
   217  if (this._searchBlockOpen == true) {
   205     this._searchLastValue = this.$searchInput.val();
   218     this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value');
   206     this.$searchInput.val('');
   219     this.selector.find(".LdtSearchInput").attr('value','');
   207     this.$searchBlock.hide("blind", { direction: "horizontal"}, 75);
   220     this.selector.find(".LdtSearch").hide("blind", { direction: "horizontal"}, 75);
       
   221     
       
   222     // unbind the watcher event.
       
   223     this.selector.find(".LdtSearchInput").unbind('keypress set');
       
   224     this._searchBlockOpen = false;
       
   225 
   208 
   226     this._positiveMatch = false;
   209     this._positiveMatch = false;
   227     
   210     
   228     this._Popcorn.trigger("IriSP.search.closed");
   211     this.player.popcorn.trigger("IriSP.search.closed");
   229 	}
       
   230 };
   212 };
   231 
   213 
   232 /** react to clicks on the search button */
   214 /** react to clicks on the search button */
   233 IriSP.PlayerWidget.prototype.searchButtonHandler = function() {
   215 IriSP.PlayerWidget.prototype.searchButtonHandler = function() {
   234   var self = this;
   216     
   235 
   217     if ( this.$searchBlock.is(":hidden") ) {
   236   /* show the search field if it is not shown */
   218         this.showSearchBlock();
   237   if ( this._searchBlockOpen == false ) {
   219         this.$searchInput.val(this._searchLastValue);      
   238     this.showSearchBlock();
   220         this.player.popcorn.trigger("IriSP.search", this._searchLastValue); // trigger the search to make it more natural.
   239     this.selector.find(".LdtSearchInput").attr('value', this._searchLastValue);      
       
   240     this._Popcorn.trigger("IriSP.search", this._searchLastValue); // trigger the search to make it more natural.
       
   241 	} else {
   221 	} else {
   242     this.hideSearchBlock();
   222         this.hideSearchBlock();
   243   }
   223     }
   244 };
   224 };
   245 
   225 
   246 /** this handler is called whenever the content of the search
   226 /** this handler is called whenever the content of the search
   247    field changes */
   227    field changes */
   248 IriSP.PlayerWidget.prototype.searchHandler = function() {
   228 IriSP.PlayerWidget.prototype.searchHandler = function() {
   249   this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value');
   229     this._searchLastValue = this.$searchInput.val();
   250   this._positiveMatch = false;
   230     this._positiveMatch = false;
   251   
   231   
   252   // do nothing if the search field is empty, instead of highlighting everything.
   232     // do nothing if the search field is empty, instead of highlighting everything.
   253   if (this._searchLastValue == "") {
   233     if (this._searchLastValue == "") {
   254     this._Popcorn.trigger("IriSP.search.cleared");
   234         this.player.popcorn.trigger("IriSP.search.cleared");
   255     this.selector.find(".LdtSearchInput").css('background-color','');
   235         this.$searchInput.css('background-color','');
   256   } else {
   236     } else {
   257     this._Popcorn.trigger("IriSP.search", this._searchLastValue);
   237         this.player.popcorn.trigger("IriSP.search", this._searchLastValue);
   258   }
   238     }
   259 };
   239 };
   260 
   240 
   261 /**
   241 /**
   262   handler for the IriSP.search.found message, which is sent by some views when they
   242   handler for the IriSP.search.found message, which is sent by some views when they
   263   highlight a match.
   243   highlight a match.
   264 */
   244 */
   265 IriSP.PlayerWidget.prototype.searchMatch = function() {
   245 IriSP.PlayerWidget.prototype.searchMatch = function() {
   266   this._positiveMatch = true;
   246     this._positiveMatch = true;
   267   this.selector.find(".LdtSearchInput").css('background-color','#e1ffe1');
   247     this.$searchInput.css('background-color','#e1ffe1');
   268 };
   248 };
   269 
   249 
   270 /** the same, except that no value could be found */
   250 /** the same, except that no value could be found */
   271 IriSP.PlayerWidget.prototype.searchNoMatch = function() {
   251 IriSP.PlayerWidget.prototype.searchNoMatch = function() {
   272   if (this._positiveMatch !== true)
   252     if (this._positiveMatch !== true) {
   273     this.selector.find(".LdtSearchInput").css('background-color', "#d62e3a");
   253         this.$searchInput.css('background-color', "#d62e3a");
       
   254     }
   274 };
   255 };
   275 
   256 
   276 /** react to an IriSP.Player.triggeredSearch - that is, when
   257 /** react to an IriSP.Player.triggeredSearch - that is, when
   277     a widget ask the PlayerWidget to do a search on his behalf */
   258     a widget ask the PlayerWidget to do a search on his behalf */
   278 IriSP.PlayerWidget.prototype.triggeredSearch = function(searchString) {
   259 IriSP.PlayerWidget.prototype.triggeredSearch = function(searchString) {
   279   this.showSearchBlock();
   260     this.showSearchBlock();
   280   this.selector.find(".LdtSearchInput").attr('value', searchString);      
   261     this.$searchInput.attr('value', searchString);      
   281   this._Popcorn.trigger("IriSP.search", searchString); // trigger the search to make it more natural.
   262     this.player.popcorn.trigger("IriSP.search", searchString); // trigger the search to make it more natural.
   282 };
   263 };
   283 
   264 
   284 
   265