1 // Add a way to instanciate using jQuery prototype.
  2 if (!jQuery.fn.osmplayer) {
  3 
  4   /**
  5    * A special jQuery event to handle the player being removed from DOM.
  6    *
  7    * @this The element that is being triggered with.
  8    **/
  9   jQuery.event.special.playerdestroyed = {
 10     remove: function(o) {
 11       if (o.handler) {
 12         o.handler(this);
 13       }
 14     }
 15   };
 16 
 17   /**
 18    * @constructor
 19    *
 20    * Define a jQuery osmplayer prototype.
 21    *
 22    * @param {object} options The options for this jQuery prototype.
 23    * @return {Array} jQuery object.
 24    */
 25   jQuery.fn.osmplayer = function(options) {
 26     return jQuery(this).each(function() {
 27       options = options || {};
 28       options.id = options.id || jQuery(this).attr('id') || Math.random();
 29       if (!minplayer.plugins[options.id]) {
 30         options.template = options.template || 'default';
 31         if (osmplayer[options.template]) {
 32           new osmplayer[options.template](jQuery(this), options);
 33         }
 34         else {
 35           new osmplayer(jQuery(this), options);
 36         }
 37       }
 38     });
 39   };
 40 }
 41 
 42 /**
 43  * @constructor
 44  * @extends minplayer
 45  * @class The main osmplayer class.
 46  *
 47  * <p><strong>Usage:</strong>
 48  * <pre><code>
 49  *
 50  *   // Create a media player.
 51  *   var player = jQuery("#player").osmplayer({
 52  *
 53  *   });
 54  *
 55  * </code></pre>
 56  * </p>
 57  *
 58  * @param {object} context The jQuery context.
 59  * @param {object} options This components options.
 60  */
 61 osmplayer = function(context, options) {
 62 
 63   // Derive from minplayer
 64   minplayer.call(this, context, options);
 65 };
 66 
 67 /** Derive from minplayer. */
 68 osmplayer.prototype = new minplayer();
 69 
 70 /** Reset the constructor. */
 71 osmplayer.prototype.constructor = osmplayer;
 72 
 73 /**
 74  * Creates a new plugin within this context.
 75  *
 76  * @param {string} name The name of the plugin you wish to create.
 77  * @param {object} base The base object for this plugin.
 78  * @param {object} context The context which you would like to create.
 79  * @return {object} The new plugin object.
 80  */
 81 osmplayer.prototype.create = function(name, base, context) {
 82   return minplayer.prototype.create.call(this, name, 'osmplayer', context);
 83 };
 84 
 85 /**
 86  * Get the default options for this plugin.
 87  *
 88  * @param {object} options The default options for this plugin.
 89  */
 90 osmplayer.prototype.defaultOptions = function(options) {
 91   options.playlist = '';
 92   options.node = {};
 93   options.link = 'http://www.mediafront.org';
 94   options.logo = 'http://mediafront.org/assets/osmplayer/logo.png';
 95   minplayer.prototype.defaultOptions.call(this, options);
 96 };
 97 
 98 /**
 99  * @see minplayer.plugin.construct
100  */
101 osmplayer.prototype.construct = function() {
102 
103   // Call the minplayer display constructor.
104   minplayer.prototype.construct.call(this);
105 
106   // We need to cleanup the player when it has been destroyed.
107   jQuery(this.display).bind('playerdestroyed', (function(player) {
108     return function(element) {
109       if (element === player.display.eq(0)[0]) {
110         for (var plugin in minplayer.plugins[player.options.id]) {
111           for (var index in minplayer.plugins[player.options.id][plugin]) {
112             minplayer.plugins[player.options.id][plugin][index].destroy();
113             delete minplayer.plugins[player.options.id][plugin][index];
114           }
115           minplayer.plugins[player.options.id][plugin].length = 0;
116         }
117         delete minplayer.plugins[player.options.id];
118         minplayer.plugins[player.options.id] = null;
119       }
120     };
121   })(this));
122 
123   /** The play queue and index. */
124   this.playQueue = [];
125   this.playIndex = 0;
126   this.hasPlaylist = false;
127 
128   /** The playlist for this media player. */
129   this.create('playlist', 'osmplayer');
130 
131   /** Get the playlist or any other playlist that connects. */
132   this.get('playlist', function(playlist) {
133     playlist.ubind(this.uuid + ':nodeLoad', (function(player) {
134       return function(event, data) {
135         player.hasPlaylist = true;
136         if (!player.options.autoplay && !!data.autoplay) {
137           player.options.autoplay = true;
138         }
139         player.loadNode(data);
140       };
141     })(this));
142   });
143 
144   // Play each media sequentially...
145   this.get('media', function(media) {
146     media.ubind(this.uuid + ':ended', (function(player) {
147       return function() {
148         player.options.autoplay = true;
149         player.playNext();
150       };
151     })(this));
152   });
153 
154   // Load the node if one is provided.
155   if (this.options.node) {
156     this.loadNode(this.options.node);
157   }
158 };
159 
160 /**
161  * Gets the full screen element.
162  *
163  * @return {object} The element that will go into fullscreen.
164  */
165 osmplayer.prototype.fullScreenElement = function() {
166   return this.elements.minplayer;
167 };
168 
169 /**
170  * Reset the osmplayer.
171  *
172  * @param {function} callback Called when it is done resetting.
173  */
174 osmplayer.prototype.reset = function(callback) {
175 
176   // Empty the playqueue.
177   this.playQueue.length = 0;
178   this.playQueue = [];
179   this.playIndex = 0;
180 
181   // Clear the playloader.
182   if (this.playLoader && this.options.preview) {
183     this.options.preview = '';
184     this.playLoader.clear((function(player) {
185       return function() {
186         callback.call(player);
187       };
188     })(this));
189   }
190   else if (callback) {
191     callback.call(this);
192   }
193 };
194 
195 /**
196  * The load node function.
197  *
198  * @param {object} node A media node object.
199  * @return {boolean} If the node was loaded.
200  */
201 osmplayer.prototype.loadNode = function(node) {
202 
203   // Make sure this is a valid node.
204   if (!node || (node.hasOwnProperty('length') && (node.length === 0))) {
205     return false;
206   }
207 
208   // Reset the player.
209   this.reset(function() {
210 
211     // Set the hasMedia flag.
212     this.hasMedia = node && node.mediafiles && node.mediafiles.media;
213 
214     // If this node is set and has files.
215     if (node && node.mediafiles) {
216 
217       // Load the media files.
218       var media = node.mediafiles.media;
219       if (media) {
220         var file = null;
221         var types = [];
222 
223         // For mobile devices, we should only show the main media.
224         if (minplayer.isAndroid || minplayer.isIDevice) {
225           types = ['media'];
226         }
227         else {
228           types = ['intro', 'commercial', 'prereel', 'media', 'postreel'];
229         }
230 
231         // Iterate through the types.
232         jQuery.each(types, (function(player) {
233           return function(key, type) {
234             file = player.addToQueue(media[type]);
235             if (file) {
236               file.queueType = type;
237             }
238           };
239         })(this));
240       }
241       else {
242 
243         // Add a class to the display to let themes handle this.
244         this.display.addClass('nomedia');
245       }
246 
247       // Play the next media
248       this.playNext();
249 
250       // Load the preview image.
251       osmplayer.getImage(node.mediafiles, 'preview', (function(player) {
252         return function(image) {
253           if (player.playLoader && (player.playLoader.display.length > 0)) {
254             player.playLoader.enabled = true;
255             player.playLoader.loadPreview(image.path);
256             player.playLoader.previewFlag.setFlag('media', true);
257             if (!player.hasMedia) {
258               player.playLoader.busy.setFlag('media', false);
259               player.playLoader.bigPlay.setFlag('media', false);
260             }
261             player.playLoader.checkVisibility();
262           }
263         };
264       })(this));
265     }
266   });
267 };
268 
269 /**
270  * Adds a file to the play queue.
271  *
272  * @param {object} file The file to add to the queue.
273  * @return {object} The file that was added to the queue.
274  */
275 osmplayer.prototype.addToQueue = function(file) {
276   file = minplayer.getMediaFile(file);
277   if (file) {
278     this.playQueue.push(file);
279   }
280   return file;
281 };
282 
283 /**
284  * Plays the next media file in the queue.
285  */
286 osmplayer.prototype.playNext = function() {
287   if (this.playQueue.length > this.playIndex) {
288     this.load(this.playQueue[this.playIndex]);
289     this.playIndex++;
290   }
291   else if (this.options.repeat) {
292     this.playIndex = 0;
293     this.playNext();
294   }
295   else if (this.playQueue.length > 0) {
296 
297     // If we have a playlist, let them handle what to do next.
298     if (this.hasPlaylist && this.options.autoNext) {
299       this.trigger('player_ended');
300     }
301     else {
302       // If there is no playlist, and no repeat, we will
303       // just seek to the beginning and pause.
304       this.options.autoplay = false;
305       this.playIndex = 0;
306       this.playNext();
307     }
308   }
309   else if (this.media) {
310     this.media.stop();
311 
312     // If there is no media found, then clear the player.
313     if (!this.hasMedia) {
314       this.media.clear();
315     }
316   }
317 };
318 
319 /**
320  * Returns a node.
321  *
322  * @param {object} node The node to get.
323  * @param {function} callback Called when the node is retrieved.
324  */
325 osmplayer.getNode = function(node, callback) {
326   if (node && node.mediafiles && node.mediafiles.media) {
327     var mediaFile = minplayer.getMediaFile(node.mediafiles.media.media);
328     if (mediaFile) {
329       var player = minplayer.players[mediaFile.player];
330       if (player && (typeof player.getNode === 'function')) {
331         player.getNode(mediaFile, function(node) {
332           callback(node);
333         });
334       }
335     }
336   }
337 };
338 
339 /**
340  * Returns an image provided image array.
341  *
342  * @param {object} mediafiles The mediafiles to search within.
343  * @param {string} type The type of image to look for.
344  * @param {function} callback Called when the image is retrieved.
345  */
346 osmplayer.getImage = function(mediafiles, type, callback) {
347 
348   var image = '';
349   var images = mediafiles.image;
350   if (images) {
351 
352     // If the image type exists, then just use that one...
353     if (images[type]) {
354       image = images[type];
355     }
356     // Or try the original image...
357     else if (images.image) {
358       image = images.image;
359     }
360     // Otherwise, just try ANY image...
361     else {
362 
363       // Or, just pick the first one available.
364       for (type in images) {
365         if (images.hasOwnProperty(type)) {
366           image = images[type];
367           break;
368         }
369       }
370     }
371   }
372 
373   // If the image exists, then callback with that image.
374   if (image) {
375     callback(new minplayer.file(image));
376   }
377   else {
378     // Get the image from the media player...
379     var mediaFile = minplayer.getMediaFile(mediafiles.media.media);
380     if (mediaFile) {
381       var player = minplayer.players[mediaFile.player];
382       if (player && (typeof player.getImage === 'function')) {
383         player.getImage(mediaFile, type, function(src) {
384           callback(new minplayer.file(src));
385         });
386       }
387     }
388   }
389 };
390