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