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