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