1 /** The minplayer namespace. */
  2 var minplayer = minplayer || {};
  3 
  4 /**
  5  * @constructor
  6  * @extends minplayer.display
  7  * @class This is the base minplayer controller.  Other controllers can derive
  8  * from the base and either build on top of it or simply define the elements
  9  * that this base controller uses.
 10  *
 11  * @param {object} context The jQuery context.
 12  * @param {object} options This components options.
 13  */
 14 minplayer.controller = function(context, options) {
 15 
 16   // Derive from display
 17   minplayer.display.call(this, 'controller', context, options);
 18 };
 19 
 20 /** Derive from minplayer.display. */
 21 minplayer.controller.prototype = new minplayer.display();
 22 
 23 /** Reset the constructor. */
 24 minplayer.controller.prototype.constructor = minplayer.controller;
 25 
 26 /**
 27  * A static function that will format a time value into a string time format.
 28  *
 29  * @param {integer} time An integer value of time.
 30  * @return {string} A string representation of the time.
 31  */
 32 minplayer.formatTime = function(time) {
 33   time = time || 0;
 34   var seconds = 0, minutes = 0, hour = 0, timeString = '';
 35 
 36   hour = Math.floor(time / 3600);
 37   time -= (hour * 3600);
 38   minutes = Math.floor(time / 60);
 39   time -= (minutes * 60);
 40   seconds = Math.floor(time % 60);
 41 
 42   if (hour) {
 43     timeString += String(hour);
 44     timeString += ':';
 45   }
 46 
 47   timeString += (minutes >= 10) ? String(minutes) : ('0' + String(minutes));
 48   timeString += ':';
 49   timeString += (seconds >= 10) ? String(seconds) : ('0' + String(seconds));
 50   return {time: timeString, units: ''};
 51 };
 52 
 53 /**
 54  * @see minplayer.display#getElements
 55  * @return {object} The elements defined by this display.
 56  */
 57 minplayer.controller.prototype.getElements = function() {
 58   var elements = minplayer.display.prototype.getElements.call(this);
 59   return jQuery.extend(elements, {
 60     play: null,
 61     pause: null,
 62     fullscreen: null,
 63     seek: null,
 64     progress: null,
 65     volume: null,
 66     timer: null
 67   });
 68 };
 69 
 70 /**
 71  * @see minplayer.plugin#construct
 72  */
 73 minplayer.controller.prototype.construct = function() {
 74 
 75   // Call the minplayer plugin constructor.
 76   minplayer.display.prototype.construct.call(this);
 77 
 78   // Keep track of if we are dragging...
 79   this.dragging = false;
 80 
 81   // If they have a seek bar.
 82   if (this.elements.seek) {
 83 
 84     // Create the seek bar slider control.
 85     this.seekBar = this.elements.seek.slider({
 86       range: 'min'
 87     });
 88   }
 89 
 90   // If they have a volume bar.
 91   if (this.elements.volume) {
 92 
 93     // Create the volume bar slider control.
 94     this.volumeBar = this.elements.volume.slider({
 95       range: 'min',
 96       orientation: 'vertical'
 97     });
 98   }
 99 
100   // Get the player plugin.
101   this.get('player', function(player) {
102 
103     // If they have a fullscreen button.
104     if (this.elements.fullscreen) {
105 
106       // Bind to the click event.
107       this.elements.fullscreen.unbind().bind('click', function(e) {
108 
109         // Toggle fullscreen mode.
110         player.toggleFullScreen();
111       }).css({'pointer' : 'hand'});
112     }
113   });
114 
115   // Get the media plugin.
116   this.get('media', function(media) {
117 
118     // If they have a pause button
119     if (this.elements.pause) {
120 
121       // Bind to the click on this button.
122       this.elements.pause.unbind().bind('click', (function(controller) {
123         return function(event) {
124           event.preventDefault();
125           controller.playPause(false, media);
126         };
127       })(this));
128 
129       // Bind to the pause event of the media.
130       media.bind('pause', (function(controller) {
131         return function(event) {
132           controller.setPlayPause(true);
133         };
134       })(this));
135     }
136 
137     // If they have a play button
138     if (this.elements.play) {
139 
140       // Bind to the click on this button.
141       this.elements.play.unbind().bind('click', (function(controller) {
142         return function(event) {
143           event.preventDefault();
144           controller.playPause(true, media);
145         };
146       })(this));
147 
148       // Bind to the play event of the media.
149       media.bind('playing', (function(controller) {
150         return function(event) {
151           controller.setPlayPause(false);
152         };
153       })(this));
154     }
155 
156     // If they have a duration, then trigger on duration change.
157     if (this.elements.duration) {
158 
159       // Bind to the duration change event.
160       media.bind('durationchange', (function(controller) {
161         return function(event, data) {
162           controller.setTimeString('duration', data.duration);
163         };
164       })(this));
165 
166       // Set the timestring to the duration.
167       media.getDuration((function(controller) {
168         return function(duration) {
169           controller.setTimeString('duration', duration);
170         };
171       })(this));
172     }
173 
174     // If they have a progress element.
175     if (this.elements.progress) {
176 
177       // Bind to the progress event.
178       media.bind('progress', (function(controller) {
179         return function(event, data) {
180           var percent = data.total ? (data.loaded / data.total) * 100 : 0;
181           controller.elements.progress.width(percent + '%');
182         };
183       })(this));
184     }
185 
186     // If they have a seek bar or timer, bind to the timeupdate.
187     if (this.seekBar || this.elements.timer) {
188 
189       // Bind to the time update event.
190       media.bind('timeupdate', (function(controller) {
191         return function(event, data) {
192           if (!controller.dragging) {
193             var value = 0;
194             if (data.duration) {
195               value = (data.currentTime / data.duration) * 100;
196             }
197 
198             // Update the seek bar if it exists.
199             if (controller.seekBar) {
200               controller.seekBar.slider('option', 'value', value);
201             }
202 
203             controller.setTimeString('timer', data.currentTime);
204           }
205         };
206       })(this));
207     }
208 
209     // If they have a seekBar element.
210     if (this.seekBar) {
211 
212       // Register the events for the control bar to control the media.
213       this.seekBar.slider({
214         start: (function(controller) {
215           return function(event, ui) {
216             controller.dragging = true;
217           };
218         })(this),
219         stop: (function(controller) {
220           return function(event, ui) {
221             controller.dragging = false;
222             media.getDuration(function(duration) {
223               media.seek((ui.value / 100) * duration);
224             });
225           };
226         })(this),
227         slide: (function(controller) {
228           return function(event, ui) {
229             media.getDuration(function(duration) {
230               var time = (ui.value / 100) * duration;
231               if (!controller.dragging) {
232                 media.seek(time);
233               }
234               controller.setTimeString('timer', time);
235             });
236           };
237         })(this)
238       });
239     }
240 
241     // Setup the volume bar.
242     if (this.volumeBar) {
243 
244       // Create the slider.
245       this.volumeBar.slider({
246         slide: function(event, ui) {
247           media.setVolume(ui.value / 100);
248         }
249       });
250 
251       media.bind('volumeupdate', (function(controller) {
252         return function(event, vol) {
253           controller.volumeBar.slider('option', 'value', (vol * 100));
254         };
255       })(this));
256 
257       // Set the volume to match that of the player.
258       media.getVolume((function(controller) {
259         return function(vol) {
260           controller.volumeBar.slider('option', 'value', (vol * 100));
261         };
262       })(this));
263     }
264   });
265 
266   // We are now ready.
267   this.ready();
268 };
269 
270 /**
271  * Sets the play and pause state of the control bar.
272  *
273  * @param {boolean} state TRUE - Show Play, FALSE - Show Pause.
274  */
275 minplayer.controller.prototype.setPlayPause = function(state) {
276   var css = '';
277   if (this.elements.play) {
278     css = state ? 'inherit' : 'none';
279     this.elements.play.css('display', css);
280   }
281   if (this.elements.pause) {
282     css = state ? 'none' : 'inherit';
283     this.elements.pause.css('display', css);
284   }
285 };
286 
287 /**
288  * Plays or pauses the media.
289  *
290  * @param {bool} state true => play, false => pause.
291  * @param {object} media The media player object.
292  */
293 minplayer.controller.prototype.playPause = function(state, media) {
294   var type = state ? 'play' : 'pause';
295   this.display.trigger(type);
296   this.setPlayPause(!state);
297   if (media) {
298     media[type]();
299   }
300 };
301 
302 /**
303  * Sets the time string on the control bar.
304  *
305  * @param {string} element The name of the element to set.
306  * @param {number} time The total time amount to set.
307  */
308 minplayer.controller.prototype.setTimeString = function(element, time) {
309   if (this.elements[element]) {
310     this.elements[element].text(minplayer.formatTime(time).time);
311   }
312 };
313