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  * Get the default options for this plugin.
 72  *
 73  * @param {object} options The default options for this plugin.
 74  */
 75 minplayer.controller.prototype.defaultOptions = function(options) {
 76   options.disptime = 0;
 77   minplayer.display.prototype.defaultOptions.call(this, options);
 78 };
 79 
 80 /**
 81  * @see minplayer.plugin#construct
 82  */
 83 minplayer.controller.prototype.construct = function() {
 84 
 85   // Call the minplayer plugin constructor.
 86   minplayer.display.prototype.construct.call(this);
 87 
 88   // Set the plugin name within the options.
 89   this.options.pluginName = 'controller';
 90 
 91   // Keep track of if we are dragging...
 92   this.dragging = false;
 93 
 94   // Keep track of the current volume.
 95   this.vol = 0;
 96 
 97   // If they have a seek bar.
 98   if (this.elements.seek) {
 99 
100     // Create the seek bar slider control.
101     this.seekBar = this.elements.seek.slider({
102       range: 'min',
103       create: function(event, ui) {
104         jQuery('.ui-slider-range', event.target).addClass('ui-state-active');
105       }
106     });
107   }
108 
109   // If they have a volume bar.
110   if (this.elements.volume) {
111 
112     // Create the volume bar slider control.
113     this.volumeBar = this.elements.volume.slider({
114       animate: true,
115       range: 'min',
116       orientation: 'vertical'
117     });
118   }
119 
120   // Get the player plugin.
121   this.get('player', function(player) {
122 
123     // If they have a fullscreen button.
124     if (this.elements.fullscreen) {
125 
126       // Bind to the click event.
127       minplayer.click(this.elements.fullscreen.unbind(), function() {
128         player.toggleFullScreen();
129       }).css({'pointer' : 'hand'});
130     }
131   });
132 
133   // Get the media plugin.
134   this.get('media', function(media) {
135 
136     // Only bind if this player does not have its own play loader.
137     if (!media.hasController()) {
138 
139       // If they have a pause button
140       if (this.elements.pause) {
141 
142         // Bind to the click on this button.
143         minplayer.click(this.elements.pause.unbind(), (function(controller) {
144           return function(event) {
145             event.preventDefault();
146             controller.playPause(false, media);
147           };
148         })(this));
149 
150         // Bind to the pause event of the media.
151         media.ubind(this.uuid + ':pause', (function(controller) {
152           return function(event) {
153             controller.setPlayPause(true);
154           };
155         })(this));
156       }
157 
158       // If they have a play button
159       if (this.elements.play) {
160 
161         // Bind to the click on this button.
162         minplayer.click(this.elements.play.unbind(), (function(controller) {
163           return function(event) {
164             event.preventDefault();
165             controller.playPause(true, media);
166           };
167         })(this));
168 
169         // Bind to the play event of the media.
170         media.ubind(this.uuid + ':playing', (function(controller) {
171           return function(event) {
172             controller.setPlayPause(false);
173           };
174         })(this));
175       }
176 
177       // If they have a duration, then trigger on duration change.
178       if (this.elements.duration) {
179 
180         // Bind to the duration change event.
181         media.ubind(this.uuid + ':durationchange', (function(controller) {
182           return function(event, data) {
183             var duration = controller.options.disptime || data.duration;
184             controller.setTimeString('duration', duration);
185           };
186         })(this));
187 
188         // Set the timestring to the duration.
189         media.getDuration((function(controller) {
190           return function(duration) {
191             duration = controller.options.disptime || duration;
192             controller.setTimeString('duration', duration);
193           };
194         })(this));
195       }
196 
197       // If they have a progress element.
198       if (this.elements.progress) {
199 
200         // Bind to the progress event.
201         media.ubind(this.uuid + ':progress', (function(controller) {
202           return function(event, data) {
203             var percent = data.total ? (data.loaded / data.total) * 100 : 0;
204             controller.elements.progress.width(percent + '%');
205           };
206         })(this));
207       }
208 
209       // If they have a seek bar or timer, bind to the timeupdate.
210       if (this.seekBar || this.elements.timer) {
211 
212         // Bind to the time update event.
213         media.ubind(this.uuid + ':timeupdate', (function(controller) {
214           return function(event, data) {
215             if (!controller.dragging) {
216               var value = 0;
217               if (data.duration) {
218                 value = (data.currentTime / data.duration) * 100;
219               }
220 
221               // Update the seek bar if it exists.
222               if (controller.seekBar) {
223                 controller.seekBar.slider('option', 'value', value);
224               }
225 
226               controller.setTimeString('timer', data.currentTime);
227             }
228           };
229         })(this));
230       }
231 
232       // If they have a seekBar element.
233       if (this.seekBar) {
234 
235         // Register the events for the control bar to control the media.
236         this.seekBar.slider({
237           start: (function(controller) {
238             return function(event, ui) {
239               controller.dragging = true;
240             };
241           })(this),
242           stop: (function(controller) {
243             return function(event, ui) {
244               controller.dragging = false;
245               media.getDuration(function(duration) {
246                 media.seek((ui.value / 100) * duration);
247               });
248             };
249           })(this),
250           slide: (function(controller) {
251             return function(event, ui) {
252               media.getDuration(function(duration) {
253                 var time = (ui.value / 100) * duration;
254                 if (!controller.dragging) {
255                   media.seek(time);
256                 }
257                 controller.setTimeString('timer', time);
258               });
259             };
260           })(this)
261         });
262       }
263 
264       // Setup the mute button.
265       if (this.elements.mute) {
266         minplayer.click(this.elements.mute, (function(controller) {
267           return function(event) {
268             event.preventDefault();
269             var value = controller.volumeBar.slider('option', 'value');
270             if (value > 0) {
271               controller.vol = value;
272               controller.volumeBar.slider('option', 'value', 0);
273               media.setVolume(0);
274             }
275             else {
276               controller.volumeBar.slider('option', 'value', controller.vol);
277               media.setVolume(controller.vol / 100);
278             }
279           };
280         })(this));
281       }
282 
283       // Setup the volume bar.
284       if (this.volumeBar) {
285 
286         // Create the slider.
287         this.volumeBar.slider({
288           slide: function(event, ui) {
289             media.setVolume(ui.value / 100);
290           }
291         });
292 
293         media.ubind(this.uuid + ':volumeupdate', (function(controller) {
294           return function(event, vol) {
295             controller.volumeBar.slider('option', 'value', (vol * 100));
296           };
297         })(this));
298 
299         // Set the volume to match that of the player.
300         media.getVolume((function(controller) {
301           return function(vol) {
302             controller.volumeBar.slider('option', 'value', (vol * 100));
303           };
304         })(this));
305       }
306     }
307     else {
308 
309       // Hide this controller.
310       this.hide();
311     }
312   });
313 
314   // We are now ready.
315   this.ready();
316 };
317 
318 /**
319  * Sets the play and pause state of the control bar.
320  *
321  * @param {boolean} state TRUE - Show Play, FALSE - Show Pause.
322  */
323 minplayer.controller.prototype.setPlayPause = function(state) {
324   var css = '';
325   if (this.elements.play) {
326     css = state ? 'inherit' : 'none';
327     this.elements.play.css('display', css);
328   }
329   if (this.elements.pause) {
330     css = state ? 'none' : 'inherit';
331     this.elements.pause.css('display', css);
332   }
333 };
334 
335 /**
336  * Plays or pauses the media.
337  *
338  * @param {bool} state true => play, false => pause.
339  * @param {object} media The media player object.
340  */
341 minplayer.controller.prototype.playPause = function(state, media) {
342   var type = state ? 'play' : 'pause';
343   this.display.trigger(type);
344   this.setPlayPause(!state);
345   if (media) {
346     media[type]();
347   }
348 };
349 
350 /**
351  * Sets the time string on the control bar.
352  *
353  * @param {string} element The name of the element to set.
354  * @param {number} time The total time amount to set.
355  */
356 minplayer.controller.prototype.setTimeString = function(element, time) {
357   if (this.elements[element]) {
358     this.elements[element].text(minplayer.formatTime(time).time);
359   }
360 };
361