1 /** The minplayer namespace. */
  2 minplayer = minplayer || {};
  3 
  4 /**
  5  * @constructor
  6  * @extends minplayer.plugin
  7  * @class Base class used to provide the display and options for any component
  8  * deriving from this class.  Components who derive are expected to provide
  9  * the elements that they define by implementing the getElements method.
 10  *
 11  * @param {string} name The name of this plugin.
 12  * @param {object} context The jQuery context this component resides.
 13  * @param {object} options The options for this component.
 14  * @param {object} queue The event queue to pass events around.
 15  */
 16 minplayer.display = function(name, context, options, queue) {
 17 
 18   // Derive from plugin
 19   minplayer.plugin.call(this, name, context, options, queue);
 20 };
 21 
 22 /** Derive from minplayer.plugin. */
 23 minplayer.display.prototype = new minplayer.plugin();
 24 
 25 /** Reset the constructor. */
 26 minplayer.display.prototype.constructor = minplayer.display;
 27 
 28 /**
 29  * Returns the display for this component.
 30  *
 31  * @return {object} The jQuery context for this display.
 32  */
 33 minplayer.display.prototype.getDisplay = function() {
 34   return this.context;
 35 };
 36 
 37 /**
 38  * @see minplayer.plugin.construct
 39  */
 40 minplayer.display.prototype.construct = function() {
 41 
 42   // Set the display.
 43   this.display = this.getDisplay(this.context, this.options);
 44 
 45   // Call the plugin constructor.
 46   minplayer.plugin.prototype.construct.call(this);
 47 
 48   // Set the plugin name within the options.
 49   this.options.pluginName = 'display';
 50 
 51   // Get the display elements.
 52   this.elements = this.getElements();
 53 
 54   // Set if this display is in autohide.
 55   this.autoHide = false;
 56 
 57   // Only do this if they allow resize for this display.
 58   if (this.onResize) {
 59 
 60     // Set the resize timeout and this pointer.
 61     var resizeTimeout = 0;
 62 
 63     // Add a handler to trigger a resize event.
 64     jQuery(window).resize((function(display) {
 65       return function() {
 66         clearTimeout(resizeTimeout);
 67         resizeTimeout = setTimeout(function() {
 68           display.onResize();
 69         }, 200);
 70       };
 71     })(this));
 72   }
 73 };
 74 
 75 /**
 76  * Called when the window resizes.
 77  */
 78 minplayer.display.prototype.onResize = false;
 79 
 80 /**
 81  * Wrapper around hide that will always not show.
 82  *
 83  * @param {object} element The element you wish to hide.
 84  */
 85 minplayer.display.prototype.hide = function(element) {
 86   element = element || this.display;
 87   if (element) {
 88     element.forceHide = true;
 89     element.unbind().hide();
 90   }
 91 };
 92 
 93 /**
 94  * Gets the full screen element.
 95  *
 96  * @return {object} The display to be used for full screen support.
 97  */
 98 minplayer.display.prototype.fullScreenElement = function() {
 99   return this.display;
100 };
101 
102 /**
103  * Fix for the click function in jQuery to be cross platform.
104  *
105  * @param {object} element The element that will be clicked.
106  * @param {function} fn Called when the element is clicked.
107  * @return {object} The element that is to be clicked.
108  */
109 minplayer.click = function(element, fn) {
110   var flag = false;
111   element = jQuery(element);
112   element.bind('touchstart click', function(event) {
113     if (!flag) {
114       flag = true;
115       setTimeout(function() {
116         flag = false;
117       }, 100);
118       fn.call(this, event);
119     }
120   });
121   return element;
122 };
123 
124 /**
125  * Determines if the player is in focus or not.
126  *
127  * @param {boolean} focus If the player is in focus.
128  */
129 minplayer.display.prototype.onFocus = function(focus) {
130   this.hasFocus = this.focus = focus;
131 
132   // If they have autoHide enabled, then show then hide this element.
133   if (this.autoHide) {
134     this.showThenHide(
135       this.autoHide.element,
136       this.autoHide.timeout,
137       this.autoHide.cb
138     );
139   }
140 };
141 
142 /**
143  * Called if you would like for your plugin to show then hide.
144  *
145  * @param {object} element The element you would like to hide or show.
146  * @param {number} timeout The timeout to hide and show.
147  * @param {function} cb Called when something happens.
148  */
149 minplayer.display.prototype.showThenHide = function(element, timeout, cb) {
150 
151   // Get the element type.
152   var elementType = (typeof element);
153 
154   // Set some interface defaults.
155   if (elementType === 'undefined') {
156     cb = null;
157     element = this.display;
158   }
159   else if (elementType === 'number') {
160     cb = timeout;
161     timeout = element;
162     element = this.display;
163   }
164   else if (elementType === 'function') {
165     cb = element;
166     element = this.display;
167   }
168 
169   // Make sure we have a timeout.
170   timeout = timeout || 5000;
171 
172   // Set the autohide variable.
173   this.autoHide = {
174     element: element,
175     timeout: timeout,
176     cb: cb
177   };
178 
179   // Show the element.
180   if (!element.forceHide) {
181     if (typeof element.showMe !== 'undefined') {
182       if (element.showMe) {
183         element.showMe(cb);
184       }
185     }
186     else {
187       element.show();
188       if (cb) {
189         cb(true);
190       }
191     }
192   }
193 
194   // Define the hover state for this element.
195   if (!element.hoverState) {
196     jQuery(element).bind('mouseenter', function() {
197       element.hoverState = true;
198     });
199     jQuery(element).bind('mouseleave', function() {
200       element.hoverState = false;
201     });
202   }
203 
204   // Clear the timeout and start it over again.
205   clearTimeout(this.showTimer);
206   this.showTimer = setTimeout((function(self) {
207     return function tryAgain() {
208 
209       // Check the hover state.
210       if (!element.hoverState) {
211         if (typeof element.hideMe !== 'undefined') {
212           if (element.hideMe) {
213             element.hideMe(cb);
214           }
215         }
216         else {
217           // Hide the element.
218           element.hide('slow', function() {
219             if (cb) {
220               cb(false);
221             }
222           });
223         }
224       }
225       else {
226 
227         // Try again in the timeout time.
228         self.showTimer = setTimeout(tryAgain, timeout);
229       }
230     };
231   })(this), timeout);
232 };
233 
234 /**
235  * Make this display element go fullscreen.
236  *
237  * @param {boolean} full Tell the player to go into fullscreen or not.
238  */
239 minplayer.display.prototype.fullscreen = function(full) {
240   var isFull = this.isFullScreen();
241   var element = this.fullScreenElement();
242   if (isFull && !full) {
243     element.removeClass('fullscreen');
244     if (screenfull) {
245       screenfull.exit();
246     }
247     this.trigger('fullscreen', false);
248   }
249   else if (!isFull && full) {
250     element.addClass('fullscreen');
251     if (screenfull) {
252       screenfull.request(element[0]);
253       screenfull.onchange = (function(display) {
254         return function(e) {
255           if (!screenfull.isFullscreen) {
256             display.fullscreen(false);
257           }
258         };
259       })(this);
260     }
261     this.trigger('fullscreen', true);
262   }
263 };
264 
265 /**
266  * Toggle fullscreen.
267  */
268 minplayer.display.prototype.toggleFullScreen = function() {
269   this.fullscreen(!this.isFullScreen());
270 };
271 
272 /**
273  * Checks to see if we are in fullscreen mode.
274  *
275  * @return {boolean} TRUE - fullscreen, FALSE - otherwise.
276  */
277 minplayer.display.prototype.isFullScreen = function() {
278   return this.fullScreenElement().hasClass('fullscreen');
279 };
280 
281 /**
282  * Returns a scaled rectangle provided a ratio and the container rect.
283  *
284  * @param {number} ratio The width/height ratio of what is being scaled.
285  * @param {object} rect The bounding rectangle for scaling.
286  * @return {object} The Rectangle object of the scaled rectangle.
287  */
288 minplayer.display.prototype.getScaledRect = function(ratio, rect) {
289   var scaledRect = {};
290   scaledRect.x = rect.x ? rect.x : 0;
291   scaledRect.y = rect.y ? rect.y : 0;
292   scaledRect.width = rect.width ? rect.width : 0;
293   scaledRect.height = rect.height ? rect.height : 0;
294   if (ratio) {
295     if ((rect.width / rect.height) > ratio) {
296       scaledRect.height = rect.height;
297       scaledRect.width = Math.floor(rect.height * ratio);
298     }
299     else {
300       scaledRect.height = Math.floor(rect.width / ratio);
301       scaledRect.width = rect.width;
302     }
303     scaledRect.x = Math.floor((rect.width - scaledRect.width) / 2);
304     scaledRect.y = Math.floor((rect.height - scaledRect.height) / 2);
305   }
306   return scaledRect;
307 };
308 
309 /**
310  * Returns all the jQuery elements that this component uses.
311  *
312  * @return {object} An object which defines all the jQuery elements that
313  * this component uses.
314  */
315 minplayer.display.prototype.getElements = function() {
316   return {};
317 };
318 
319 /**
320  * From https://github.com/sindresorhus/screenfull.js
321  */
322 /*global Element:true*/
323 (function(window, document) {
324   'use strict';
325   var methods = (function() {
326     var methodMap = [
327       [
328         'requestFullscreen',
329         'exitFullscreen',
330         'fullscreenchange',
331         'fullscreen',
332         'fullscreenElement'
333       ],
334       [
335         'webkitRequestFullScreen',
336         'webkitCancelFullScreen',
337         'webkitfullscreenchange',
338         'webkitIsFullScreen',
339         'webkitCurrentFullScreenElement'
340       ],
341       [
342         'mozRequestFullScreen',
343         'mozCancelFullScreen',
344         'mozfullscreenchange',
345         'mozFullScreen',
346         'mozFullScreenElement'
347       ]
348     ];
349     for (var i = 0, l = methodMap.length; i < l; i++) {
350       if (methodMap.hasOwnProperty(i)) {
351         var val = methodMap[i];
352         if (val[1] in document) {
353           return val;
354         }
355       }
356     }
357   })();
358 
359   if (!methods) {
360     return window.screenfull = false;
361   }
362 
363   var keyboardAllowed = 'ALLOW_KEYBOARD_INPUT' in Element;
364 
365   var screenfull = {
366     init: function() {
367       document.addEventListener(methods[2], function(e) {
368         screenfull.isFullscreen = document[methods[3]];
369         screenfull.element = document[methods[4]];
370         screenfull.onchange(e);
371       });
372       return this;
373     },
374     isFullscreen: document[methods[3]],
375     element: document[methods[4]],
376     request: function(elem) {
377       elem = elem || document.documentElement;
378       elem[methods[0]](keyboardAllowed && Element.ALLOW_KEYBOARD_INPUT);
379       // Work around Safari 5.1 bug: reports support for keyboard in fullscreen
380       // even though it doesn't.
381       if (!document.isFullscreen) {
382         elem[methods[0]]();
383       }
384     },
385     exit: function() {
386       document[methods[1]]();
387     },
388     toggle: function(elem) {
389       if (this.isFullscreen) {
390         this.exit();
391       } else {
392         this.request(elem);
393       }
394     },
395     onchange: function() {}
396   };
397 
398   window.screenfull = screenfull.init();
399 })(window, document);
400