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           if (typeof player.options.originalAutoPlay == 'undefined') {
138             player.options.originalAutoPlay = player.options.autoplay;
139           }
140           player.options.autoplay = true;
141         }
142         player.loadNode(data);
143       };
144     })(this));
145   });
146 
147   // Play each media sequentially...
148   this.get('media', function(media) {
149     media.ubind(this.uuid + ':ended', (function(player) {
150       return function() {
151         if (typeof player.options.originalAutoPlay == 'undefined') {
152           player.options.originalAutoPlay = player.options.autoplay;
153         }
154         player.options.autoplay = true;
155         player.playNext();
156       };
157     })(this));
158   });
159 
160   // Load the node if one is provided.
161   this.loadNode(this.options.node);
162 };
163 
164 /**
165  * Gets the full screen element.
166  *
167  * @return {object} The element that will go into fullscreen.
168  */
169 osmplayer.prototype.fullScreenElement = function() {
170   return this.elements.minplayer;
171 };
172 
173 /**
174  * Reset the osmplayer.
175  *
176  * @param {function} callback Called when it is done resetting.
177  */
178 osmplayer.prototype.reset = function(callback) {
179 
180   // Empty the playqueue.
181   this.playQueue.length = 0;
182   this.playQueue = [];
183   this.playIndex = 0;
184 
185   // Clear the playloader.
186   if (this.playLoader && this.options.preview) {
187     this.options.preview = '';
188     this.playLoader.clear((function(player) {
189       return function() {
190         callback.call(player);
191       };
192     })(this));
193   }
194   else if (callback) {
195     callback.call(this);
196   }
197 };
198 
199 /**
200  * The load node function.
201  *
202  * @param {object} node A media node object.
203  * @return {boolean} If the node was loaded.
204  */
205 osmplayer.prototype.loadNode = function(node) {
206 
207   // Make sure this is a valid node.
208   if (!node || (node.hasOwnProperty('length') && (node.length === 0))) {
209     return false;
210   }
211 
212   // Reset the player.
213   this.reset(function() {
214 
215     // Set the hasMedia flag.
216     this.hasMedia = node && node.mediafiles && node.mediafiles.media;
217     this.hasMedia = this.hasMedia || this.options.file;
218 
219     // If this node is set and has files.
220     if (node && node.mediafiles) {
221 
222       // Load the media files.
223       var media = node.mediafiles.media;
224       if (media) {
225         var file = null;
226         var types = [];
227 
228         // For mobile devices, we should only show the main media.
229         if (minplayer.isAndroid || minplayer.isIDevice) {
230           types = ['media'];
231         }
232         else {
233           types = ['intro', 'commercial', 'prereel', 'media', 'postreel'];
234         }
235 
236         // Iterate through the types.
237         jQuery.each(types, (function(player) {
238           return function(key, type) {
239             file = player.addToQueue(media[type]);
240             if (file) {
241               file.queueType = type;
242             }
243           };
244         })(this));
245       }
246       else {
247 
248         // Add a class to the display to let themes handle this.
249         this.display.addClass('nomedia');
250       }
251 
252       // Play the next media
253       this.playNext();
254 
255       // Load the preview image.
256       osmplayer.getImage(node.mediafiles, 'preview', (function(player) {
257         return function(image) {
258           if (player.playLoader && (player.playLoader.display.length > 0)) {
259             player.playLoader.enabled = true;
260             player.playLoader.loadPreview(image.path);
261             player.playLoader.previewFlag.setFlag('media', true);
262             if (!player.hasMedia) {
263               player.playLoader.busy.setFlag('media', false);
264               player.playLoader.bigPlay.setFlag('media', false);
265             }
266             player.playLoader.checkVisibility();
267           }
268         };
269       })(this));
270     }
271   });
272 };
273 
274 /**
275  * Adds a file to the play queue.
276  *
277  * @param {object} file The file to add to the queue.
278  * @return {object} The file that was added to the queue.
279  */
280 osmplayer.prototype.addToQueue = function(file) {
281   file = minplayer.getMediaFile(file);
282   if (file) {
283     this.playQueue.push(file);
284   }
285   return file;
286 };
287 
288 /**
289  * Plays the next media file in the queue.
290  */
291 osmplayer.prototype.playNext = function() {
292   if (this.playQueue.length > this.playIndex) {
293     this.load(this.playQueue[this.playIndex]);
294     this.playIndex++;
295   }
296   else if (this.options.repeat) {
297     this.playIndex = 0;
298     this.playNext();
299   }
300   else if (this.playQueue.length > 0) {
301 
302     // If we have a playlist, let them handle what to do next.
303     if (this.hasPlaylist && this.options.autoNext) {
304       this.trigger('player_ended');
305     }
306     else {
307       // If there is no playlist, and no repeat, we will
308       // just seek to the beginning and pause.
309       this.options.autoplay = false;
310       this.playIndex = 0;
311       this.playNext();
312     }
313   }
314   else if (this.media) {
315 
316     // Reset the autoplay variable.
317     if (typeof this.options.originalAutoPlay != 'undefined') {
318       this.options.autoplay = this.options.originalAutoPlay;
319     }
320 
321     this.media.stop();
322 
323     // Load the media again.
324     if (this.options.file) {
325       this.load();
326     }
327     else {
328       this.loadNode();
329     }
330   }
331 };
332 
333 /**
334  * Returns a node.
335  *
336  * @param {object} node The node to get.
337  * @param {function} callback Called when the node is retrieved.
338  */
339 osmplayer.getNode = function(node, callback) {
340   if (node && node.mediafiles && node.mediafiles.media) {
341     var mediaFile = minplayer.getMediaFile(node.mediafiles.media.media);
342     if (mediaFile) {
343       var player = minplayer.players[mediaFile.player];
344       if (player && (typeof player.getNode === 'function')) {
345         player.getNode(mediaFile, function(node) {
346           callback(node);
347         });
348       }
349     }
350   }
351 };
352 
353 /**
354  * Returns an image provided image array.
355  *
356  * @param {object} mediafiles The mediafiles to search within.
357  * @param {string} type The type of image to look for.
358  * @param {function} callback Called when the image is retrieved.
359  */
360 osmplayer.getImage = function(mediafiles, type, callback) {
361 
362   var image = '';
363   var images = mediafiles.image;
364   if (images) {
365 
366     // If the image type exists, then just use that one...
367     if (images[type]) {
368       image = images[type];
369     }
370     // Or try the original image...
371     else if (images.image) {
372       image = images.image;
373     }
374     // Otherwise, just try ANY image...
375     else {
376 
377       // Or, just pick the first one available.
378       for (type in images) {
379         if (images.hasOwnProperty(type)) {
380           image = images[type];
381           break;
382         }
383       }
384     }
385   }
386 
387   // If the image exists, then callback with that image.
388   if (image) {
389     callback(new minplayer.file(image));
390   }
391   else {
392     // Get the image from the media player...
393     var mediaFile = minplayer.getMediaFile(mediafiles.media.media);
394     if (mediaFile) {
395       var player = minplayer.players[mediaFile.player];
396       if (player && (typeof player.getImage === 'function')) {
397         player.getImage(mediaFile, type, function(src) {
398           callback(new minplayer.file(src));
399         });
400       }
401     }
402   }
403 };
404