1 // Add a way to instanciate using jQuery prototype. 2 if (!jQuery.fn.minplayer) { 3 4 /** 5 * @constructor 6 * 7 * Define a jQuery minplayer prototype. 8 * 9 * @param {object} options The options for this jQuery prototype. 10 * @return {Array} jQuery object. 11 */ 12 jQuery.fn.minplayer = function(options) { 13 return jQuery(this).each(function() { 14 options = options || {}; 15 options.id = options.id || jQuery(this).attr('id') || Math.random(); 16 if (!minplayer.plugins[options.id]) { 17 options.template = options.template || 'default'; 18 if (minplayer[options.template]) { 19 new minplayer[options.template](jQuery(this), options); 20 } 21 else { 22 new minplayer(jQuery(this), options); 23 } 24 } 25 }); 26 }; 27 } 28 29 /** 30 * @constructor 31 * @extends minplayer.display 32 * @class The core media player class which governs the media player 33 * functionality. 34 * 35 * <p><strong>Usage:</strong> 36 * <pre><code> 37 * 38 * // Create a media player. 39 * var player = jQuery("#player").minplayer({ 40 * 41 * }); 42 * 43 * </code></pre> 44 * </p> 45 * 46 * @param {object} context The jQuery context. 47 * @param {object} options This components options. 48 */ 49 minplayer = jQuery.extend(function(context, options) { 50 51 // Derive from display 52 minplayer.display.call(this, 'player', context, options); 53 }, minplayer); 54 55 /** Derive from minplayer.display. */ 56 minplayer.prototype = new minplayer.display(); 57 58 /** Reset the constructor. */ 59 minplayer.prototype.constructor = minplayer; 60 61 /** 62 * @see minplayer.plugin.construct 63 */ 64 minplayer.prototype.construct = function() { 65 66 // Allow them to provide arguments based off of the DOM attributes. 67 jQuery.each(this.context[0].attributes, (function(player) { 68 return function(index, attr) { 69 player.options[attr.name] = player.options[attr.name] || attr.value; 70 }; 71 })(this)); 72 73 // Make sure we provide default options... 74 this.options = jQuery.extend({ 75 id: 'player', 76 build: false, 77 wmode: 'transparent', 78 preload: true, 79 autoplay: false, 80 autoload: true, 81 loop: false, 82 width: '100%', 83 height: '350px', 84 debug: false, 85 volume: 80, 86 files: null, 87 file: '', 88 preview: '', 89 attributes: {}, 90 logo: '', 91 link: '', 92 width: '100%', 93 height: '100%' 94 }, this.options); 95 96 // Call the minplayer display constructor. 97 minplayer.display.prototype.construct.call(this); 98 99 // Set the plugin name within the options. 100 this.options.pluginName = 'player'; 101 102 /** The controller for this player. */ 103 this.controller = this.create('controller'); 104 105 /** The play loader for this player. */ 106 this.playLoader = this.create('playLoader'); 107 108 // Set the focus of the element based on if they click in or outside of it. 109 minplayer.click(document, (function(player) { 110 return function(event) { 111 var target = jQuery(event.target); 112 var focus = !(target.closest('#' + player.options.id).length == 0); 113 minplayer.get.call(this, player.options.id, null, function(plugin) { 114 plugin.onFocus(focus); 115 }); 116 }; 117 })(this)); 118 119 /** Add the logo for the player. */ 120 if (this.options.logo && this.elements.logo) { 121 122 var code = ''; 123 if (this.options.link) { 124 code += '<a target="_blank" href="' + this.options.link + '">'; 125 } 126 code += '<img src="' + this.options.logo + '" >'; 127 if (this.options.link) { 128 code += '</a>'; 129 } 130 this.logo = this.elements.logo.append(code); 131 } 132 133 /** Variable to store the current media player. */ 134 this.currentPlayer = 'html5'; 135 136 // Add key events to the window. 137 this.addKeyEvents(); 138 139 // Called to add events. 140 this.addEvents(); 141 142 // Now load these files. 143 this.load(this.getFiles()); 144 145 // The player is ready. 146 this.ready(); 147 }; 148 149 /** 150 * Called when an error occurs. 151 * 152 * @param {object} plugin The plugin you wish to bind to. 153 */ 154 minplayer.prototype.bindTo = function(plugin) { 155 plugin.bind('error', (function(player) { 156 return function(event, data) { 157 if (player.currentPlayer == 'html5') { 158 minplayer.player = 'minplayer'; 159 player.options.file.player = 'minplayer'; 160 player.loadPlayer(); 161 } 162 else { 163 player.showError(data); 164 } 165 }; 166 })(this)); 167 168 // Bind to the fullscreen event. 169 plugin.bind('fullscreen', (function(player) { 170 return function(event, data) { 171 player.resize(); 172 }; 173 })(this)); 174 }; 175 176 /** 177 * We need to bind to events we are interested in. 178 */ 179 minplayer.prototype.addEvents = function() { 180 minplayer.get.call(this, this.options.id, null, (function(player) { 181 return function(plugin) { 182 player.bindTo(plugin); 183 }; 184 })(this)); 185 }; 186 187 /** 188 * Sets an error on the player. 189 * 190 * @param {string} error The error to display on the player. 191 */ 192 minplayer.prototype.showError = function(error) { 193 if (typeof error !== 'object') { 194 error = error || ''; 195 if (this.elements.error) { 196 197 // Set the error text. 198 this.elements.error.text(error); 199 if (error) { 200 // Show the error message. 201 this.elements.error.show(); 202 203 // Only show this error for a time interval. 204 setTimeout((function(player) { 205 return function() { 206 player.elements.error.hide('slow'); 207 }; 208 })(this), 5000); 209 } 210 else { 211 this.elements.error.hide(); 212 } 213 } 214 } 215 }; 216 217 /** 218 * Adds key events to the player. 219 */ 220 minplayer.prototype.addKeyEvents = function() { 221 jQuery(document).bind('keydown', (function(player) { 222 return function(event) { 223 switch (event.keyCode) { 224 case 113: // ESC 225 case 27: // Q 226 if (player.isFullScreen()) { 227 player.fullscreen(false); 228 } 229 break; 230 } 231 }; 232 })(this)); 233 }; 234 235 /** 236 * Returns all the media files available for this player. 237 * 238 * @return {array} All the media files for this player. 239 */ 240 minplayer.prototype.getFiles = function() { 241 242 // If they provide the files in the options, use those first. 243 if (this.options.files) { 244 return this.options.files; 245 } 246 247 if (this.options.file) { 248 return this.options.file; 249 } 250 251 var files = []; 252 var mediaSrc = null; 253 254 // Get the files involved... 255 if (this.elements.media) { 256 mediaSrc = this.elements.media.attr('src'); 257 if (mediaSrc) { 258 files.push({'path': mediaSrc}); 259 } 260 jQuery('source', this.elements.media).each(function() { 261 files.push({ 262 'path': jQuery(this).attr('src'), 263 'mimetype': jQuery(this).attr('type'), 264 'codecs': jQuery(this).attr('codecs') 265 }); 266 }); 267 } 268 269 return files; 270 }; 271 272 /** 273 * Returns the full media player object. 274 * 275 * @param {array} files An array of files to chose from. 276 * @return {object} The best media file to play in the current browser. 277 */ 278 minplayer.getMediaFile = function(files) { 279 280 // If there are no files then return null. 281 if (!files) { 282 return null; 283 } 284 285 // If the file is already a file object then just return. 286 if ((typeof files === 'string') || files.path || files.id) { 287 return new minplayer.file(files); 288 } 289 290 // Add the files and get the best player to play. 291 var bestPriority = 0, mFile = null, file = null; 292 for (var i in files) { 293 if (files.hasOwnProperty(i)) { 294 file = new minplayer.file(files[i]); 295 if (file.player && (file.priority > bestPriority)) { 296 mFile = file; 297 } 298 } 299 } 300 301 // Return the best minplayer file. 302 return mFile; 303 }; 304 305 /** 306 * Loads a media player based on the current file. 307 * 308 * @return {boolean} If a new player was loaded. 309 */ 310 minplayer.prototype.loadPlayer = function() { 311 312 // Do nothing if there isn't a file or anywhere to put it. 313 if (!this.options.file || (this.elements.display.length == 0)) { 314 return false; 315 } 316 317 // If no player is set, then also return false. 318 if (!this.options.file.player) { 319 return false; 320 } 321 322 // Reset the error. 323 this.showError(); 324 325 // Only destroy if the current player is different than the new player. 326 var player = this.options.file.player.toString(); 327 328 // If there isn't media or if the players are different. 329 if (!this.media || (player !== this.currentPlayer)) { 330 331 // Set the current media player. 332 this.currentPlayer = player; 333 334 // Do nothing if we don't have a display. 335 if (!this.elements.display) { 336 this.showError('No media display found.'); 337 return; 338 } 339 340 // Destroy the current media. 341 var queue = {}; 342 if (this.media) { 343 queue = this.media.queue; 344 this.media.destroy(); 345 } 346 347 // Get the class name and create the new player. 348 pClass = minplayer.players[this.options.file.player]; 349 350 // Create the new media player. 351 this.options.mediaelement = this.elements.media; 352 this.media = new pClass(this.elements.display, this.options, queue); 353 354 // Now get the media when it is ready. 355 this.get('media', (function(player) { 356 return function(media) { 357 358 // Load the media. 359 media.load(player.options.file); 360 player.display.addClass('minplayer-player-' + media.mediaFile.player); 361 }; 362 })(this)); 363 364 // Return that a new player is loaded. 365 return true; 366 } 367 // If the media object already exists... 368 else if (this.media) { 369 370 // Now load the different media file. 371 this.media.options = this.options; 372 this.display.removeClass('minplayer-player-' + this.media.mediaFile.player); 373 this.media.load(this.options.file); 374 this.display.addClass('minplayer-player-' + this.media.mediaFile.player); 375 return false; 376 } 377 }; 378 379 /** 380 * Load a set of files or a single file for the media player. 381 * 382 * @param {array} files An array of files to chose from to load. 383 */ 384 minplayer.prototype.load = function(files) { 385 386 // Set the id and class. 387 var id = '', pClass = ''; 388 389 // If no file was provided, then get it. 390 this.options.files = files || this.options.files; 391 this.options.file = minplayer.getMediaFile(this.options.files); 392 393 // Now load the player. 394 if (this.loadPlayer()) { 395 396 // Add the events since we now have a player. 397 this.bindTo(this.media); 398 399 // If the player isn't valid, then show an error. 400 if (this.options.file.mimetype && !this.options.file.player) { 401 this.showError('Cannot play media: ' + this.options.file.mimetype); 402 } 403 } 404 }; 405 406 /** 407 * Called when the player is resized. 408 */ 409 minplayer.prototype.resize = function() { 410 411 // Call onRezie for each plugin. 412 this.get(function(plugin) { 413 if (plugin.onResize) { 414 plugin.onResize(); 415 } 416 }); 417 }; 418