_V_.merge = function(obj1, obj2, safe){ // Make sure second object exists if (!obj2) { obj2 = {}; }; for (var attrname in obj2){ if (obj2.hasOwnProperty(attrname) && (!safe || !obj1.hasOwnProperty(attrname))) { obj1[attrname]=obj2[attrname]; } } return obj1; }; _V_.extend = function(obj){ this.merge(this, obj, true); }; _V_.extend({ tech: {}, // Holder for playback technology settings controlSets: {}, // Holder for control set definitions techSupports: function(tech, type, name){ if (_V_[tech].supports[type]) { return _V_[tech].supports[type][name]; } return false; }, updateTechSupport: function(tech, type, name, value){ if (_V_[tech].supports[type] === undefined) { _V_[tech].supports[type] = {}; } _V_[tech].supports[type][name] = value; }, // Device Checks isIE: function(){ return !+"\v1"; }, isIPad: function(){ return navigator.userAgent.match(/iPad/i) !== null; }, isIPhone: function(){ return navigator.userAgent.match(/iPhone/i) !== null; }, isIOS: function(){ return VideoJS.isIPhone() || VideoJS.isIPad(); }, iOSVersion: function() { var match = navigator.userAgent.match(/OS (\d+)_/i); if (match && match[1]) { return match[1]; } }, isAndroid: function(){ return navigator.userAgent.match(/Android.*AppleWebKit/i) !== null; }, androidVersion: function() { var match = navigator.userAgent.match(/Android (\d+)\./i); if (match && match[1]) { return match[1]; } }, //isAndroidBrowser each: function(arr, fn){ if (!arr || arr.length === 0) { return; } for (var i=0,j=arr.length; i 0 || gh > 0) ? h + ":" : ""; // If hours are showing, we may need to add a leading zero. // Always show at least one digit of minutes. m = (((h || gm >= 10) && m < 10) ? "0" + m : m) + ":"; // Check if leading zero is need for seconds s = (s < 10) ? "0" + s : s; return h + m + s; }, capitalize: function(string){ return string.charAt(0).toUpperCase() + string.slice(1); }, // Return the relative horizonal position of an event as a value from 0-1 getRelativePosition: function(x, relativeElement){ return Math.max(0, Math.min(1, (x - _V_.findPosX(relativeElement)) / relativeElement.offsetWidth)); }, getComputedStyleValue: function(element, style){ return window.getComputedStyle(element, null).getPropertyValue(style); }, trim: function(string){ return string.toString().replace(/^\s+/, "").replace(/\s+$/, ""); }, round: function(num, dec) { if (!dec) { dec = 0; } return Math.round(num*Math.pow(10,dec))/Math.pow(10,dec); }, isEmpty: function(object) { for (var prop in object) { return false; } return true; }, // Mimic HTML5 TimeRange Spec. createTimeRange: function(start, end){ return { length: 1, start: function() { return start; }, end: function() { return end; } }; }, /* Element Data Store. Allows for binding data to an element without putting it directly on the element. Ex. Event listneres are stored here. (also from jsninja.com) ================================================================================ */ cache: {}, // Where the data is stored guid: 1, // Unique ID for the element expando: "vdata" + (new Date).getTime(), // Unique attribute to store element's guid in // Returns the cache object where data for the element is stored getData: function(elem){ // _V_.log(arguments.callee.caller.arguments.callee.caller) var id = elem[_V_.expando]; if (!id) { id = elem[_V_.expando] = _V_.guid++; _V_.cache[id] = {}; } return _V_.cache[id]; }, // Delete data for the element from the cache and the guid attr from element removeData: function(elem){ var id = elem[_V_.expando]; if (!id) { return; } // Remove all stored data delete _V_.cache[id]; // Remove the expando property from the DOM node try { delete elem[_V_.expando]; } catch(e) { if (elem.removeAttribute) { elem.removeAttribute(_V_.expando); } else { // IE doesn't appear to support removeAttribute on the document element elem[_V_.expando] = null; } } }, /* Proxy (a.k.a Bind or Context). A simple method for changing the context of a function It also stores a unique id on the function so it can be easily removed from events ================================================================================ */ proxy: function(context, fn) { // Make sure the function has a unique ID if (!fn.guid) { fn.guid = _V_.guid++; } // Create the new function that changes the context var ret = function() { return fn.apply(context, arguments); }; // Give the new function the same ID // (so that they are equivalent and can be easily removed) ret.guid = fn.guid; return ret; }, get: function(url, onSuccess, onError){ // if (netscape.security.PrivilegeManager.enablePrivilege) { // netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); // } var local = (url.indexOf("file:") == 0 || (window.location.href.indexOf("file:") == 0 && url.indexOf("http:") == -1)); if (typeof XMLHttpRequest == "undefined") { XMLHttpRequest = function () { try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {} try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (f) {} try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (g) {} throw new Error("This browser does not support XMLHttpRequest."); }; } var request = new XMLHttpRequest(); try { request.open("GET", url); } catch(e) { _V_.log("VideoJS XMLHttpRequest (open)", e); // onError(e); return false; } request.onreadystatechange = _V_.proxy(this, function() { if (request.readyState == 4) { if (request.status == 200 || local && request.status == 0) { onSuccess(request.responseText); } else { if (onError) { onError(); } } } }); try { request.send(); } catch(e) { _V_.log("VideoJS XMLHttpRequest (send)", e); if (onError) { onError(e); } } }, /* Local Storage ================================================================================ */ setLocalStorage: function(key, value){ // IE was throwing errors referencing the var anywhere without this var localStorage = localStorage || false; if (!localStorage) { return; } try { localStorage[key] = value; } catch(e) { if (e.code == 22 || e.code == 1014) { // Webkit == 22 / Firefox == 1014 _V_.log("LocalStorage Full (VideoJS)", e); } else { _V_.log("LocalStorage Error (VideoJS)", e); } } } }); // usage: log('inside coolFunc', this, arguments); // paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/ _V_.log = function(){ _V_.log.history = _V_.log.history || [];// store logs to an array for reference _V_.log.history.push(arguments); if(window.console) { arguments.callee = arguments.callee.caller; var newarr = [].slice.call(arguments); (typeof console.log === 'object' ? _V_.log.apply.call(console.log, console, newarr) : console.log.apply(console, newarr)); } }; // make it safe to use console.log always (function(b){function c(){}for(var d="assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,timeStamp,profile,profileEnd,time,timeEnd,trace,warn".split(","),a;a=d.pop();){b[a]=b[a]||c}})((function(){try {console.log();return window.console;}catch(err){return window.console={};}})()); // Offset Left // getBoundingClientRect technique from John Resig http://ejohn.org/blog/getboundingclientrect-is-awesome/ if ("getBoundingClientRect" in document.documentElement) { _V_.findPosX = function(el) { var box; try { box = el.getBoundingClientRect(); } catch(e) {} if (!box) { return 0; } var docEl = document.documentElement, body = document.body, clientLeft = docEl.clientLeft || body.clientLeft || 0, scrollLeft = window.pageXOffset || body.scrollLeft, left = box.left + scrollLeft - clientLeft; return left; }; } else { _V_.findPosX = function(el) { var curleft = el.offsetLeft; // _V_.log(obj.className, obj.offsetLeft) while(el = obj.offsetParent) { if (el.className.indexOf("video-js") == -1) { // _V_.log(el.offsetParent, "OFFSETLEFT", el.offsetLeft) // _V_.log("-webkit-full-screen", el.webkitMatchesSelector("-webkit-full-screen")); // _V_.log("-webkit-full-screen", el.querySelectorAll(".video-js:-webkit-full-screen")); } else { } curleft += el.offsetLeft; } return curleft; }; }