vendor/assets/javascripts/webshims/shims/combos/12.js in webshims-rails-0.4.7 vs vendor/assets/javascripts/webshims/shims/combos/12.js in webshims-rails-1.10.3

- old
+ new

@@ -1,1108 +1,503 @@ -//DOM-Extension helper -jQuery.webshims.register('dom-extend', function($, webshims, window, document, undefined){ - "use strict"; - //shortcus - var modules = webshims.modules; - var listReg = /\s*,\s*/; +/*! SWFMini - a SWFObject 2.2 cut down version for webshims + * + * based on SWFObject v2.2 <http://code.google.com/p/swfobject/> + is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> +*/ + +var swfmini = function() { + + var UNDEF = "undefined", + OBJECT = "object", + webshims = jQuery.webshims, + SHOCKWAVE_FLASH = "Shockwave Flash", + SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash", + FLASH_MIME_TYPE = "application/x-shockwave-flash", - //proxying attribute - var olds = {}; - var havePolyfill = {}; - var extendedProps = {}; - var extendQ = {}; - var modifyProps = {}; + win = window, + doc = document, + nav = navigator, + + plugin = false, + domLoadFnArr = [main], + objIdArr = [], + listenersArr = [], + storedAltContent, + storedAltContentId, + storedCallbackFn, + storedCallbackObj, + isDomLoaded = false, + dynamicStylesheet, + dynamicStylesheetMedia, + autoHideShow = true, - var oldVal = $.fn.val; - var singleVal = function(elem, name, val, pass, _argless){ - return (_argless) ? oldVal.call($(elem)) : oldVal.call($(elem), val); - }; - - $.fn.onTrigger = function(evt, fn){ - return this.on(evt, fn).each(fn); - }; - - $.fn.val = function(val){ - var elem = this[0]; - if(arguments.length && val == null){ - val = ''; + /* Centralized function for browser feature detection + - User agent string detection is only used when no good alternative is possible + - Is executed directly for optimal performance + */ + ua = function() { + var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF, + u = nav.userAgent.toLowerCase(), + p = nav.platform.toLowerCase(), + windows = p ? /win/.test(p) : /win/.test(u), + mac = p ? /mac/.test(p) : /mac/.test(u), + webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit + ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html + playerVersion = [0,0,0], + d = null; + if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) { + d = nav.plugins[SHOCKWAVE_FLASH].description; + if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+ + plugin = true; + ie = false; // cascaded feature detection for Internet Explorer + d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1"); + playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10); + playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10); + playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0; + } } - if(!arguments.length){ - if(!elem || elem.nodeType !== 1){return oldVal.call(this);} - return $.prop(elem, 'value', val, 'val', true); - } - if($.isArray(val)){ - return oldVal.apply(this, arguments); - } - var isFunction = $.isFunction(val); - return this.each(function(i){ - elem = this; - if(elem.nodeType === 1){ - if(isFunction){ - var genVal = val.call( elem, i, $.prop(elem, 'value', undefined, 'val', true)); - if(genVal == null){ - genVal = ''; + else if (typeof win.ActiveXObject != UNDEF) { + try { + var a = new ActiveXObject(SHOCKWAVE_FLASH_AX); + if (a) { // a will return null when ActiveX is disabled + d = a.GetVariable("$version"); + if (d) { + ie = true; // cascaded feature detection for Internet Explorer + d = d.split(" ")[1].split(","); + playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; } - $.prop(elem, 'value', genVal, 'val') ; - } else { - $.prop(elem, 'value', val, 'val'); } } - }); - }; + catch(e) {} + } + return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac }; + }(); - var dataID = '_webshimsLib'+ (Math.round(Math.random() * 1000)); - var elementData = function(elem, key, val){ - elem = elem.jquery ? elem[0] : elem; - if(!elem){return val || {};} - var data = $.data(elem, dataID); - if(val !== undefined){ - if(!data){ - data = $.data(elem, dataID, {}); - } - if(key){ - data[key] = val; - } + + function callDomLoadFunctions() { + if (isDomLoaded) { return; } + try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early + var t = doc.getElementsByTagName("body")[0].appendChild(createElement("span")); + t.parentNode.removeChild(t); } + catch (e) { return; } + isDomLoaded = true; + var dl = domLoadFnArr.length; + for (var i = 0; i < dl; i++) { + domLoadFnArr[i](); + } + } + + function addDomLoadEvent(fn) { + if (isDomLoaded) { + fn(); + } + else { + domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+ + } + } + + /* Cross-browser onload + - Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/ + - Will fire an event as soon as a web page including all of its assets are loaded + */ + function addLoadEvent(fn) { - return key ? data && data[key] : data; - }; - - - [{name: 'getNativeElement', prop: 'nativeElement'}, {name: 'getShadowElement', prop: 'shadowElement'}, {name: 'getShadowFocusElement', prop: 'shadowFocusElement'}].forEach(function(data){ - $.fn[data.name] = function(){ - return this.map(function(){ - var shadowData = elementData(this, 'shadowData'); - return shadowData && shadowData[data.prop] || this; - }); - }; - }); + } + /* Main function + - Will preferably execute onDomLoad, otherwise onload (as a fallback) + */ + function main() { + if (plugin) { + testPlayerVersion(); + } + } - ['removeAttr', 'prop', 'attr'].forEach(function(type){ - olds[type] = $[type]; - $[type] = function(elem, name, value, pass, _argless){ - var isVal = (pass == 'val'); - var oldMethod = !isVal ? olds[type] : singleVal; - if( !elem || !havePolyfill[name] || elem.nodeType !== 1 || (!isVal && pass && type == 'attr' && $.attrFn[name]) ){ - return oldMethod(elem, name, value, pass, _argless); - } - - var nodeName = (elem.nodeName || '').toLowerCase(); - var desc = extendedProps[nodeName]; - var curType = (type == 'attr' && (value === false || value === null)) ? 'removeAttr' : type; - var propMethod; - var oldValMethod; - var ret; - - - if(!desc){ - desc = extendedProps['*']; - } - if(desc){ - desc = desc[name]; - } - - if(desc){ - propMethod = desc[curType]; - } - - if(propMethod){ - if(name == 'value'){ - oldValMethod = propMethod.isVal; - propMethod.isVal = isVal; - } - if(curType === 'removeAttr'){ - return propMethod.value.call(elem); - } else if(value === undefined){ - return (propMethod.get) ? - propMethod.get.call(elem) : - propMethod.value - ; - } else if(propMethod.set) { - if(type == 'attr' && value === true){ - value = name; + /* Detect the Flash Player version for non-Internet Explorer browsers + - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description: + a. Both release and build numbers can be detected + b. Avoid wrong descriptions by corrupt installers provided by Adobe + c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports + - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available + */ + function testPlayerVersion() { + var b = doc.getElementsByTagName("body")[0]; + var o = createElement(OBJECT); + o.setAttribute("type", FLASH_MIME_TYPE); + var t = b.appendChild(o); + if (t) { + var counter = 0; + (function(){ + if (typeof t.GetVariable != UNDEF) { + var d = t.GetVariable("$version"); + if (d) { + d = d.split(" ")[1].split(","); + ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; } - - ret = propMethod.set.call(elem, value); } - if(name == 'value'){ - propMethod.isVal = oldValMethod; + else if (counter < 10) { + counter++; + setTimeout(arguments.callee, 10); + return; } - } else { - ret = oldMethod(elem, name, value, pass, _argless); + b.removeChild(o); + t = null; + })(); + } + } + + + function getObjectById(objectIdStr) { + var r = null; + var o = getElementById(objectIdStr); + if (o && o.nodeName == "OBJECT") { + if (typeof o.SetVariable != UNDEF) { + r = o; } - if((value !== undefined || curType === 'removeAttr') && modifyProps[nodeName] && modifyProps[nodeName][name]){ - - var boolValue; - if(curType == 'removeAttr'){ - boolValue = false; - } else if(curType == 'prop'){ - boolValue = !!(value); - } else { - boolValue = true; + else { + var n = o.getElementsByTagName(OBJECT)[0]; + if (n) { + r = n; } - - modifyProps[nodeName][name].forEach(function(fn){ - if(!fn.only || (fn.only = 'prop' && type == 'prop') || (fn.only == 'attr' && type != 'prop')){ - fn.call(elem, value, boolValue, (isVal) ? 'val' : curType, type); - } - }); } - return ret; - }; - - extendQ[type] = function(nodeName, prop, desc){ - - if(!extendedProps[nodeName]){ - extendedProps[nodeName] = {}; - } - if(!extendedProps[nodeName][prop]){ - extendedProps[nodeName][prop] = {}; - } - var oldDesc = extendedProps[nodeName][prop][type]; - var getSup = function(propType, descriptor, oDesc){ - if(descriptor && descriptor[propType]){ - return descriptor[propType]; + } + return r; + } + + + /* Functions to abstract and display alternative content + */ + function displayAltContent(obj) { + if (ua.ie && ua.win && obj.readyState != 4) { + // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it, + // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work + var el = createElement("div"); + obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content + el.parentNode.replaceChild(abstractAltContent(obj), el); + obj.style.display = "none"; + (function(){ + if (obj.readyState == 4) { + obj.parentNode.removeChild(obj); } - if(oDesc && oDesc[propType]){ - return oDesc[propType]; + else { + setTimeout(arguments.callee, 10); } - if(type == 'prop' && prop == 'value'){ - return function(value){ - var elem = this; - return (desc.isVal) ? - singleVal(elem, prop, value, false, (arguments.length === 0)) : - olds[type](elem, prop, value) - ; - }; + })(); + } + else { + obj.parentNode.replaceChild(abstractAltContent(obj), obj); + } + } + + function abstractAltContent(obj) { + var ac = createElement("div"); + if (ua.win && ua.ie) { + ac.innerHTML = obj.innerHTML; + } + else { + var nestedObj = obj.getElementsByTagName(OBJECT)[0]; + if (nestedObj) { + var c = nestedObj.childNodes; + if (c) { + var cl = c.length; + for (var i = 0; i < cl; i++) { + if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) { + ac.appendChild(c[i].cloneNode(true)); + } + } } - if(type == 'prop' && propType == 'value' && desc.value.apply){ - return function(value){ - var sup = olds[type](this, prop); - if(sup && sup.apply){ - sup = sup.apply(this, arguments); - } - return sup; - }; - } - return function(value){ - return olds[type](this, prop, value); - }; - }; - extendedProps[nodeName][prop][type] = desc; - if(desc.value === undefined){ - if(!desc.set){ - desc.set = desc.writeable ? - getSup('set', desc, oldDesc) : - (webshims.cfg.useStrict && prop == 'prop') ? - function(){throw(prop +' is readonly on '+ nodeName);} : - $.noop - ; - } - if(!desc.get){ - desc.get = getSup('get', desc, oldDesc); - } - } - - ['value', 'get', 'set'].forEach(function(descProp){ - if(desc[descProp]){ - desc['_sup'+descProp] = getSup(descProp, oldDesc); - } - }); - }; - - }); + } + return ac; + } - //see also: https://github.com/lojjic/PIE/issues/40 | https://prototype.lighthouseapp.com/projects/8886/tickets/1107-ie8-fatal-crash-when-prototypejs-is-loaded-with-rounded-cornershtc - var isExtendNativeSave = Modernizr.ES5; - var extendNativeValue = (function(){ - var UNKNOWN = webshims.getPrototypeOf(document.createElement('foobar')); - var has = Object.prototype.hasOwnProperty; - return function(nodeName, prop, desc){ - var elem; - var elemProto; - if( isExtendNativeSave && (elem = document.createElement(nodeName)) && (elemProto = webshims.getPrototypeOf(elem)) && UNKNOWN !== elemProto && ( !elem[prop] || !has.call(elem, prop) ) ){ - var sup = elem[prop]; - desc._supvalue = function(){ - if(sup && sup.apply){ - return sup.apply(this, arguments); + /* Cross-browser dynamic SWF creation + */ + function createSWF(attObj, parObj, id) { + var r, el = getElementById(id); + if (ua.wk && ua.wk < 312) { return r; } + if (el) { + if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content + attObj.id = id; + } + if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML + var att = ""; + for (var i in attObj) { + if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries + if (i.toLowerCase() == "data") { + parObj.movie = attObj[i]; + } + else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword + att += ' class="' + attObj[i] + '"'; + } + else if (i.toLowerCase() != "classid") { + att += ' ' + i + '="' + attObj[i] + '"'; + } } - return sup; - }; - elemProto[prop] = desc.value; - } else { - desc._supvalue = function(){ - var data = elementData(this, 'propValue'); - if(data && data[prop] && data[prop].apply){ - return data[prop].apply(this, arguments); + } + var par = ""; + for (var j in parObj) { + if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries + par += '<param name="' + j + '" value="' + parObj[j] + '" />'; } - return data && data[prop]; - }; - initProp.extendValue(nodeName, prop, desc.value); + } + el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>'; + objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only) + r = getElementById(attObj.id); } - desc.value._supvalue = desc._supvalue; - }; - })(); - - var initProp = (function(){ - - var initProps = {}; - - webshims.addReady(function(context, contextElem){ - var nodeNameCache = {}; - var getElementsByName = function(name){ - if(!nodeNameCache[name]){ - nodeNameCache[name] = $(context.getElementsByTagName(name)); - if(contextElem[0] && $.nodeName(contextElem[0], name)){ - nodeNameCache[name] = nodeNameCache[name].add(contextElem); + else { // well-behaving browsers + var o = createElement(OBJECT); + o.setAttribute("type", FLASH_MIME_TYPE); + for (var m in attObj) { + if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries + if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword + o.setAttribute("class", attObj[m]); + } + else if (m.toLowerCase() != "classid") { // filter out IE specific attribute + o.setAttribute(m, attObj[m]); + } } } - }; - - - $.each(initProps, function(name, fns){ - getElementsByName(name); - if(!fns || !fns.forEach){ - webshims.warn('Error: with '+ name +'-property. methods: '+ fns); - return; + for (var n in parObj) { + if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element + createObjParam(o, n, parObj[n]); + } } - fns.forEach(function(fn){ - nodeNameCache[name].each(fn); - }); - }); - nodeNameCache = null; - }); - - var tempCache; - var emptyQ = $([]); - var createNodeNameInit = function(nodeName, fn){ - if(!initProps[nodeName]){ - initProps[nodeName] = [fn]; - } else { - initProps[nodeName].push(fn); + el.parentNode.replaceChild(o, el); + r = o; } - if($.isDOMReady){ - (tempCache || $( document.getElementsByTagName(nodeName) )).each(fn); - } - }; - - var elementExtends = {}; - return { - createTmpCache: function(nodeName){ - if($.isDOMReady){ - tempCache = tempCache || $( document.getElementsByTagName(nodeName) ); - } - return tempCache || emptyQ; - }, - flushTmpCache: function(){ - tempCache = null; - }, - content: function(nodeName, prop){ - createNodeNameInit(nodeName, function(){ - var val = $.attr(this, prop); - if(val != null){ - $.attr(this, prop, val); + } + return r; + } + + function createObjParam(el, pName, pValue) { + var p = createElement("param"); + p.setAttribute("name", pName); + p.setAttribute("value", pValue); + el.appendChild(p); + } + + /* Cross-browser SWF removal + - Especially needed to safely and completely remove a SWF in Internet Explorer + */ + function removeSWF(id) { + var obj = getElementById(id); + if (obj && obj.nodeName == "OBJECT") { + if (ua.ie && ua.win) { + obj.style.display = "none"; + (function(){ + if (obj.readyState == 4) { + removeObjectInIE(id); } - }); - }, - createElement: function(nodeName, fn){ - createNodeNameInit(nodeName, fn); - }, - extendValue: function(nodeName, prop, value){ - createNodeNameInit(nodeName, function(){ - $(this).each(function(){ - var data = elementData(this, 'propValue', {}); - data[prop] = this[prop]; - this[prop] = value; - }); - }); + else { + setTimeout(arguments.callee, 10); + } + })(); } - }; - })(); - - var createPropDefault = function(descs, removeType){ - if(descs.defaultValue === undefined){ - descs.defaultValue = ''; + else { + obj.parentNode.removeChild(obj); + } } - if(!descs.removeAttr){ - descs.removeAttr = { - value: function(){ - descs[removeType || 'prop'].set.call(this, descs.defaultValue); - descs.removeAttr._supvalue.call(this); + } + + function removeObjectInIE(id) { + var obj = getElementById(id); + if (obj) { + for (var i in obj) { + if (typeof obj[i] == "function") { + obj[i] = null; } - }; + } + obj.parentNode.removeChild(obj); } - if(!descs.attr){ - descs.attr = {}; + } + + /* Functions to optimize JavaScript compression + */ + function getElementById(id) { + var el = null; + try { + el = doc.getElementById(id); } - }; + catch (e) {} + return el; + } - $.extend(webshims, { + function createElement(el) { + return doc.createElement(el); + } + + /* Updated attachEvent function for Internet Explorer + - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks + */ + function addListener(target, eventType, fn) { + target.attachEvent(eventType, fn); + listenersArr[listenersArr.length] = [target, eventType, fn]; + } + + /* Flash Player and SWF content version matching + */ + function hasPlayerVersion(rv) { + var pv = ua.pv, v = rv.split("."); + v[0] = parseInt(v[0], 10); + v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0" + v[2] = parseInt(v[2], 10) || 0; + return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false; + } + + + + function setVisibility(id, isVisible) { + if (!autoHideShow) { return; } + var elem; + var v = isVisible ? "visible" : "hidden"; + if (isDomLoaded && (elem && getElementById(id))) { + getElementById(id).style.visibility = v; + } + } - getID: (function(){ - var ID = new Date().getTime(); - return function(elem){ - elem = $(elem); - var id = elem.attr('id'); - if(!id){ - ID++; - id = 'ID-'+ ID; - elem.attr('id', id); + /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only) + */ + var cleanup = function() { + if (ua.ie && ua.win && window.attachEvent) { + window.attachEvent("onunload", function() { + // remove listeners to avoid memory leaks + var ll = listenersArr.length; + for (var i = 0; i < ll; i++) { + listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]); } - return id; - }; - })(), - extendUNDEFProp: function(obj, props){ - $.each(props, function(name, prop){ - if( !(name in obj) ){ - obj[name] = prop; + // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect + var il = objIdArr.length; + for (var j = 0; j < il; j++) { + removeSWF(objIdArr[j]); } - }); - }, - //http://www.w3.org/TR/html5/common-dom-interfaces.html#reflect - createPropDefault: createPropDefault, - data: elementData, - moveToFirstEvent: function(elem, eventType, bindType){ - var events = ($._data(elem, 'events') || {})[eventType]; - var fn; - - if(events && events.length > 1){ - fn = events.pop(); - if(!bindType){ - bindType = 'bind'; + // cleanup library's main closures to avoid memory leaks + for (var k in ua) { + ua[k] = null; } - if(bindType == 'bind' && events.delegateCount){ - events.splice( events.delegateCount, 0, fn); - } else { - events.unshift( fn ); + ua = null; + for (var l in swfmini) { + swfmini[l] = null; } - - + swfmini = null; + }); + } + }(); + + webshims.ready('DOM', callDomLoadFunctions); + + return { + /* Public API + - Reference: http://code.google.com/p/swfobject/wiki/documentation + */ + registerObject: function() { + + }, + + getObjectById: function(objectIdStr) { + if (ua.w3) { + return getObjectById(objectIdStr); } - elem = null; }, - addShadowDom: (function(){ - var resizeTimer; - var lastHeight; - var lastWidth; - - var docObserve = { - init: false, - runs: 0, - test: function(){ - var height = docObserve.getHeight(); - var width = docObserve.getWidth(); - - if(height != docObserve.height || width != docObserve.width){ - docObserve.height = height; - docObserve.width = width; - docObserve.handler({type: 'docresize'}); - docObserve.runs++; - if(docObserve.runs < 9){ - setTimeout(docObserve.test, 90); + + embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) { + var callbackObj = {success:false, id:replaceElemIdStr}; + if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) { + setVisibility(replaceElemIdStr, false); + addDomLoadEvent(function() { + widthStr += ""; // auto-convert to string + heightStr += ""; + var att = {}; + if (attObj && typeof attObj === OBJECT) { + for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs + att[i] = attObj[i]; } - } else { - docObserve.runs = 0; } - }, - handler: function(e){ - clearTimeout(resizeTimer); - resizeTimer = setTimeout(function(){ - if(e.type == 'resize'){ - var width = $(window).width(); - var height = $(window).width(); - if(height == lastHeight && width == lastWidth){ - return; - } - lastHeight = height; - lastWidth = width; - - docObserve.height = docObserve.getHeight(); - docObserve.width = docObserve.getWidth(); - + att.data = swfUrlStr; + att.width = widthStr; + att.height = heightStr; + var par = {}; + if (parObj && typeof parObj === OBJECT) { + for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs + par[j] = parObj[j]; } - $(document).triggerHandler('updateshadowdom'); - }, (e.type == 'resize') ? 50 : 9); - }, - _create: function(){ - $.each({ Height: "getHeight", Width: "getWidth" }, function(name, type){ - var body = document.body; - var doc = document.documentElement; - docObserve[type] = function(){ - return Math.max( - body[ "scroll" + name ], doc[ "scroll" + name ], - body[ "offset" + name ], doc[ "offset" + name ], - doc[ "client" + name ] - ); - }; - }); - }, - start: function(){ - if(!this.init && document.body){ - this.init = true; - this._create(); - this.height = docObserve.getHeight(); - this.width = docObserve.getWidth(); - setInterval(this.test, 600); - $(this.test); - webshims.ready('WINDOWLOAD', this.test); - $(window).bind('resize', this.handler); - (function(){ - var oldAnimate = $.fn.animate; - var animationTimer; - - $.fn.animate = function(){ - clearTimeout(animationTimer); - animationTimer = setTimeout(function(){ - docObserve.test(); - }, 99); - - return oldAnimate.apply(this, arguments); - }; - })(); } - } - }; - - - webshims.docObserve = function(){ - webshims.ready('DOM', function(){ - docObserve.start(); - }); - }; - return function(nativeElem, shadowElem, opts){ - opts = opts || {}; - if(nativeElem.jquery){ - nativeElem = nativeElem[0]; - } - if(shadowElem.jquery){ - shadowElem = shadowElem[0]; - } - var nativeData = $.data(nativeElem, dataID) || $.data(nativeElem, dataID, {}); - var shadowData = $.data(shadowElem, dataID) || $.data(shadowElem, dataID, {}); - var shadowFocusElementData = {}; - if(!opts.shadowFocusElement){ - opts.shadowFocusElement = shadowElem; - } else if(opts.shadowFocusElement){ - if(opts.shadowFocusElement.jquery){ - opts.shadowFocusElement = opts.shadowFocusElement[0]; - } - shadowFocusElementData = $.data(opts.shadowFocusElement, dataID) || $.data(opts.shadowFocusElement, dataID, shadowFocusElementData); - } - - nativeData.hasShadow = shadowElem; - shadowFocusElementData.nativeElement = shadowData.nativeElement = nativeElem; - shadowFocusElementData.shadowData = shadowData.shadowData = nativeData.shadowData = { - nativeElement: nativeElem, - shadowElement: shadowElem, - shadowFocusElement: opts.shadowFocusElement - }; - if(opts.shadowChilds){ - opts.shadowChilds.each(function(){ - elementData(this, 'shadowData', shadowData.shadowData); - }); - } - - if(opts.data){ - shadowFocusElementData.shadowData.data = shadowData.shadowData.data = nativeData.shadowData.data = opts.data; - } - opts = null; - webshims.docObserve(); - }; - })(), - propTypes: { - standard: function(descs, name){ - createPropDefault(descs); - if(descs.prop){return;} - descs.prop = { - set: function(val){ - descs.attr.set.call(this, ''+val); - }, - get: function(){ - return descs.attr.get.call(this) || descs.defaultValue; - } - }; - - }, - "boolean": function(descs, name){ - - createPropDefault(descs); - if(descs.prop){return;} - descs.prop = { - set: function(val){ - if(val){ - descs.attr.set.call(this, ""); - } else { - descs.removeAttr.value.call(this); - } - }, - get: function(){ - return descs.attr.get.call(this) != null; - } - }; - }, - "src": (function(){ - var anchor = document.createElement('a'); - anchor.style.display = "none"; - return function(descs, name){ - - createPropDefault(descs); - if(descs.prop){return;} - descs.prop = { - set: function(val){ - descs.attr.set.call(this, val); - }, - get: function(){ - var href = this.getAttribute(name); - var ret; - if(href == null){return '';} - - anchor.setAttribute('href', href+'' ); - - if(!$.support.hrefNormalized){ - try { - $(anchor).insertAfter(this); - ret = anchor.getAttribute('href', 4); - } catch(er){ - ret = anchor.getAttribute('href', 4); - } - $(anchor).detach(); + if (flashvarsObj && typeof flashvarsObj === OBJECT) { + for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs + if (typeof par.flashvars != UNDEF) { + par.flashvars += "&" + k + "=" + flashvarsObj[k]; } - return ret || anchor.href; - } - }; - }; - })(), - enumarated: function(descs, name){ - - createPropDefault(descs); - if(descs.prop){return;} - descs.prop = { - set: function(val){ - descs.attr.set.call(this, val); - }, - get: function(){ - var val = (descs.attr.get.call(this) || '').toLowerCase(); - if(!val || descs.limitedTo.indexOf(val) == -1){ - val = descs.defaultValue; + else { + par.flashvars = k + "=" + flashvarsObj[k]; } - return val; } - }; - } - -// ,unsignedLong: $.noop -// ,"doubble": $.noop -// ,"long": $.noop -// ,tokenlist: $.noop -// ,settableTokenlist: $.noop - }, - reflectProperties: function(nodeNames, props){ - if(typeof props == 'string'){ - props = props.split(listReg); - } - props.forEach(function(prop){ - webshims.defineNodeNamesProperty(nodeNames, prop, { - prop: { - set: function(val){ - $.attr(this, prop, val); - }, - get: function(){ - return $.attr(this, prop) || ''; + } + if (hasPlayerVersion(swfVersionStr)) { // create SWF + var obj = createSWF(att, par, replaceElemIdStr); + if (att.id == replaceElemIdStr) { + setVisibility(replaceElemIdStr, true); } + callbackObj.success = true; + callbackObj.ref = obj; } + else { // show alternative content + setVisibility(replaceElemIdStr, true); + } + if (callbackFn) { callbackFn(callbackObj); } }); - }); - }, - defineNodeNameProperty: function(nodeName, prop, descs){ - havePolyfill[prop] = true; - - if(descs.reflect){ - webshims.propTypes[descs.propType || 'standard'](descs, prop); } - - ['prop', 'attr', 'removeAttr'].forEach(function(type){ - var desc = descs[type]; - if(desc){ - if(type === 'prop'){ - desc = $.extend({writeable: true}, desc); - } else { - desc = $.extend({}, desc, {writeable: true}); - } - - extendQ[type](nodeName, prop, desc); - if(nodeName != '*' && webshims.cfg.extendNative && type == 'prop' && desc.value && $.isFunction(desc.value)){ - extendNativeValue(nodeName, prop, desc); - } - descs[type] = desc; - } - }); - if(descs.initAttr){ - initProp.content(nodeName, prop); - } - return descs; + else if (callbackFn) { callbackFn(callbackObj); } }, - defineNodeNameProperties: function(name, descs, propType, _noTmpCache){ - var olddesc; - for(var prop in descs){ - if(!_noTmpCache && descs[prop].initAttr){ - initProp.createTmpCache(name); - } - if(propType){ - if(descs[prop][propType]){ - //webshims.log('override: '+ name +'['+prop +'] for '+ propType); - } else { - descs[prop][propType] = {}; - ['value', 'set', 'get'].forEach(function(copyProp){ - if(copyProp in descs[prop]){ - descs[prop][propType][copyProp] = descs[prop][copyProp]; - delete descs[prop][copyProp]; - } - }); - } - } - descs[prop] = webshims.defineNodeNameProperty(name, prop, descs[prop]); - } - if(!_noTmpCache){ - initProp.flushTmpCache(); - } - return descs; + switchOffAutoHideShow: function() { + autoHideShow = false; }, - createElement: function(nodeName, create, descs){ - var ret; - if($.isFunction(create)){ - create = { - after: create - }; - } - initProp.createTmpCache(nodeName); - if(create.before){ - initProp.createElement(nodeName, create.before); - } - if(descs){ - ret = webshims.defineNodeNameProperties(nodeName, descs, false, true); - } - if(create.after){ - initProp.createElement(nodeName, create.after); - } - initProp.flushTmpCache(); - return ret; + ua: ua, + + getFlashPlayerVersion: function() { + return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] }; }, - onNodeNamesPropertyModify: function(nodeNames, props, desc, only){ - if(typeof nodeNames == 'string'){ - nodeNames = nodeNames.split(listReg); + + hasFlashPlayerVersion: hasPlayerVersion, + + createSWF: function(attObj, parObj, replaceElemIdStr) { + if (ua.w3) { + return createSWF(attObj, parObj, replaceElemIdStr); } - if($.isFunction(desc)){ - desc = {set: desc}; + else { + return undefined; } + }, + + showExpressInstall: function() { - nodeNames.forEach(function(name){ - if(!modifyProps[name]){ - modifyProps[name] = {}; - } - if(typeof props == 'string'){ - props = props.split(listReg); - } - if(desc.initAttr){ - initProp.createTmpCache(name); - } - props.forEach(function(prop){ - if(!modifyProps[name][prop]){ - modifyProps[name][prop] = []; - havePolyfill[prop] = true; - } - if(desc.set){ - if(only){ - desc.set.only = only; - } - modifyProps[name][prop].push(desc.set); - } - - if(desc.initAttr){ - initProp.content(name, prop); - } - }); - initProp.flushTmpCache(); - - }); }, - defineNodeNamesBooleanProperty: function(elementNames, prop, descs){ - if(!descs){ - descs = {}; + + removeSWF: function(objElemIdStr) { + if (ua.w3) { + removeSWF(objElemIdStr); } - if($.isFunction(descs)){ - descs.set = descs; - } - webshims.defineNodeNamesProperty(elementNames, prop, { - attr: { - set: function(val){ - this.setAttribute(prop, val); - if(descs.set){ - descs.set.call(this, true); - } - }, - get: function(){ - var ret = this.getAttribute(prop); - return (ret == null) ? undefined : prop; - } - }, - removeAttr: { - value: function(){ - this.removeAttribute(prop); - if(descs.set){ - descs.set.call(this, false); - } - } - }, - reflect: true, - propType: 'boolean', - initAttr: descs.initAttr || false - }); }, - contentAttr: function(elem, name, val){ - if(!elem.nodeName){return;} - var attr; - if(val === undefined){ - attr = (elem.attributes[name] || {}); - val = attr.specified ? attr.value : null; - return (val == null) ? undefined : val; - } + + createCSS: function() { - if(typeof val == 'boolean'){ - if(!val){ - elem.removeAttribute(name); - } else { - elem.setAttribute(name, name); - } - } else { - elem.setAttribute(name, val); - } }, -// set current Lang: -// - webshims.activeLang(lang:string); -// get current lang -// - webshims.activeLang(); -// get current lang -// webshims.activeLang({ -// register: moduleName:string, -// callback: callback:function -// }); -// get/set including removeLang -// - webshims.activeLang({ -// module: moduleName:string, -// callback: callback:function, -// langObj: languageObj:array/object -// }); - activeLang: (function(){ - var callbacks = []; - var registeredCallbacks = {}; - var currentLang; - var shortLang; - var notLocal = /:\/\/|^\.*\//; - var loadRemoteLang = function(data, lang, options){ - var langSrc; - if(lang && options && $.inArray(lang, options.availabeLangs || []) !== -1){ - data.loading = true; - langSrc = options.langSrc; - if(!notLocal.test(langSrc)){ - langSrc = webshims.cfg.basePath+langSrc; - } - webshims.loader.loadScript(langSrc+lang+'.js', function(){ - if(data.langObj[lang]){ - data.loading = false; - callLang(data, true); - } else { - $(function(){ - if(data.langObj[lang]){ - callLang(data, true); - } - data.loading = false; - }); - } - }); - return true; - } - return false; - }; - var callRegister = function(module){ - if(registeredCallbacks[module]){ - registeredCallbacks[module].forEach(function(data){ - data.callback(); - }); - } - }; - var callLang = function(data, _noLoop){ - if(data.activeLang != currentLang && data.activeLang !== shortLang){ - var options = modules[data.module].options; - if( data.langObj[currentLang] || (shortLang && data.langObj[shortLang]) ){ - data.activeLang = currentLang; - data.callback(data.langObj[currentLang] || data.langObj[shortLang], currentLang); - callRegister(data.module); - } else if( !_noLoop && - !loadRemoteLang(data, currentLang, options) && - !loadRemoteLang(data, shortLang, options) && - data.langObj[''] && data.activeLang !== '' ) { - data.activeLang = ''; - data.callback(data.langObj[''], currentLang); - callRegister(data.module); - } - } - }; + addDomLoadEvent: addDomLoadEvent, + + addLoadEvent: addLoadEvent, + + + // For internal usage only + expressInstallCallback: function() { - - var activeLang = function(lang){ - - if(typeof lang == 'string' && lang !== currentLang){ - currentLang = lang; - shortLang = currentLang.split('-')[0]; - if(currentLang == shortLang){ - shortLang = false; - } - $.each(callbacks, function(i, data){ - callLang(data); - }); - } else if(typeof lang == 'object'){ - - if(lang.register){ - if(!registeredCallbacks[lang.register]){ - registeredCallbacks[lang.register] = []; - } - registeredCallbacks[lang.register].push(lang); - lang.callback(); - } else { - if(!lang.activeLang){ - lang.activeLang = ''; - } - callbacks.push(lang); - callLang(lang); - } - } - return currentLang; - }; - - return activeLang; - })() - }); - - $.each({ - defineNodeNamesProperty: 'defineNodeNameProperty', - defineNodeNamesProperties: 'defineNodeNameProperties', - createElements: 'createElement' - }, function(name, baseMethod){ - webshims[name] = function(names, a, b, c){ - if(typeof names == 'string'){ - names = names.split(listReg); - } - var retDesc = {}; - names.forEach(function(nodeName){ - retDesc[nodeName] = webshims[baseMethod](nodeName, a, b, c); - }); - return retDesc; - }; - }); - - webshims.isReady('webshimLocalization', true); -}); -//html5a11y -(function($, document){ - //if we support basic styleing or do not support ARIA (assumed) abort - if(!Modernizr.localstorage || ('hidden' in document.createElement('a'))){return;} - - var elemMappings = { - article: "article", - aside: "complementary", - section: "region", - nav: "navigation", - address: "contentinfo" - }; - var addRole = function(elem, role){ - var hasRole = elem.getAttribute('role'); - if (!hasRole) { - elem.setAttribute('role', role); } }; - - $.webshims.addReady(function(context, contextElem){ - $.each(elemMappings, function(name, role){ - var elems = $(name, context).add(contextElem.filter(name)); - for (var i = 0, len = elems.length; i < len; i++) { - addRole(elems[i], role); - } - }); - if (context === document) { - var header = document.getElementsByTagName('header')[0]; - var footers = document.getElementsByTagName('footer'); - var footerLen = footers.length; - if (header && !$(header).closest('section, article')[0]) { - addRole(header, 'banner'); - } - if (!footerLen) { - return; - } - var footer = footers[footerLen - 1]; - if (!$(footer).closest('section, article')[0]) { - addRole(footer, 'contentinfo'); - } - } - }); - -})(jQuery, document); +}(); -jQuery.webshims.register('details', function($, webshims, window, doc, undefined, options){ - var isInterActiveSummary = function(summary){ - var details = $(summary).parent('details'); - if(details[0] && details.children(':first').get(0) === summary){ - return details; - } - }; - - var bindDetailsSummary = function(summary, details){ - summary = $(summary); - details = $(details); - var oldSummary = $.data(details[0], 'summaryElement'); - $.data(summary[0], 'detailsElement', details); - if(!oldSummary || summary[0] !== oldSummary[0]){ - if(oldSummary){ - if(oldSummary.hasClass('fallback-summary')){ - oldSummary.remove(); - } else { - oldSummary - .unbind('.summaryPolyfill') - .removeData('detailsElement') - .removeAttr('role') - .removeAttr('tabindex') - .removeAttr('aria-expanded') - .removeClass('summary-button') - .find('span.details-open-indicator') - .remove() - ; - } - } - $.data(details[0], 'summaryElement', summary); - details.prop('open', details.prop('open')); - } - }; - var getSummary = function(details){ - var summary = $.data(details, 'summaryElement'); - if(!summary){ - summary = $('> summary:first-child', details); - if(!summary[0]){ - $(details).prependPolyfill('<summary class="fallback-summary">'+ options.text +'</summary>'); - summary = $.data(details, 'summaryElement'); - } else { - bindDetailsSummary(summary, details); - } - } - return summary; - }; - -// var isOriginalPrevented = function(e){ -// var src = e.originalEvent; -// if(!src){return e.isDefaultPrevented();} -// -// return src.defaultPrevented || src.returnValue === false || -// src.getPreventDefault && src.getPreventDefault(); -// }; - - webshims.createElement('summary', function(){ - var details = isInterActiveSummary(this); - if(!details || $.data(this, 'detailsElement')){return;} - var timer; - var stopNativeClickTest; - var tabindex = $.attr(this, 'tabIndex') || '0'; - bindDetailsSummary(this, details); - $(this) - .on({ - 'focus.summaryPolyfill': function(){ - $(this).addClass('summary-has-focus'); - }, - 'blur.summaryPolyfill': function(){ - $(this).removeClass('summary-has-focus'); - }, - 'mouseenter.summaryPolyfill': function(){ - $(this).addClass('summary-has-hover'); - }, - 'mouseleave.summaryPolyfill': function(){ - $(this).removeClass('summary-has-hover'); - }, - 'click.summaryPolyfill': function(e){ - var details = isInterActiveSummary(this); - if(details){ - if(!stopNativeClickTest && e.originalEvent){ - stopNativeClickTest = true; - e.stopImmediatePropagation(); - e.preventDefault(); - $(this).trigger('click'); - stopNativeClickTest = false; - return false; - } else { - clearTimeout(timer); - - timer = setTimeout(function(){ - if(!e.isDefaultPrevented()){ - details.prop('open', !details.prop('open')); - } - }, 0); - } - } - }, - 'keydown.summaryPolyfill': function(e){ - if( (e.keyCode == 13 || e.keyCode == 32) && !e.isDefaultPrevented()){ - stopNativeClickTest = true; - e.preventDefault(); - $(this).trigger('click'); - stopNativeClickTest = false; - } - } - }) - .attr({tabindex: tabindex, role: 'button'}) - .prepend('<span class="details-open-indicator" />') - ; - webshims.moveToFirstEvent(this, 'click'); - }); - - var initDetails; - webshims.defineNodeNamesBooleanProperty('details', 'open', function(val){ - var summary = $($.data(this, 'summaryElement')); - if(!summary){return;} - var action = (val) ? 'removeClass' : 'addClass'; - var details = $(this); - if (!initDetails && options.animate){ - details.stop().css({width: '', height: ''}); - var start = { - width: details.width(), - height: details.height() - }; - } - summary.attr('aria-expanded', ''+val); - details[action]('closed-details-summary').children().not(summary[0])[action]('closed-details-child'); - if(!initDetails && options.animate){ - var end = { - width: details.width(), - height: details.height() - }; - details.css(start).animate(end, { - complete: function(){ - $(this).css({width: '', height: ''}); - } - }); - } - - }); - webshims.createElement('details', function(){ - initDetails = true; - var summary = getSummary(this); - $.prop(this, 'open', $.prop(this, 'open')); - initDetails = false; - }); -}); - (function($, Modernizr, webshims){ "use strict"; var hasNative = Modernizr.audio && Modernizr.video; var supportsLoop = false; var bugs = webshims.bugs; @@ -1114,11 +509,11 @@ webshims.reTest([swfType], hasNative); } }); }; var options = webshims.cfg.mediaelement; - var swfType = options && options.player == 'jwplayer' ? 'mediaelement-swf' : 'mediaelement-jaris'; + var swfType = 'mediaelement-jaris'; var hasSwf; if(!options){ webshims.error("mediaelement wasn't implemented but loaded"); return; } @@ -1139,38 +534,48 @@ webshims.reTest('mediaelement-native-fix'); } } if(hasNative && !options.preferFlash){ + var noSwitch = { + 1: 1, + 2: 1 + }; var switchOptions = function(e){ + var media; var parent = e.target.parentNode; - if(!options.preferFlash && ($(e.target).is('audio, video') || (parent && $('source:last', parent)[0] == e.target)) ){ - webshims.ready('DOM mediaelement', function(){ - if(hasSwf){ + if(!options.preferFlash && + ($(e.target).is('audio, video') || (parent && $('source:last', parent)[0] == e.target)) && + (media = $(e.target).closest('audio, video')) && !noSwitch[media.prop('error')] + ){ + $(function(){ + if(hasSwf && !options.preferFlash){ loadSwf(); + webshims.ready('WINDOWLOAD '+swfType, function(){ + setTimeout(function(){ + if(!options.preferFlash && webshims.mediaelement.createSWF && !media.is('.nonnative-api-active')){ + options.preferFlash = true; + document.removeEventListener('error', switchOptions, true); + $('audio, video').each(function(){ + webshims.mediaelement.selectSource(this); + }); + webshims.info("switching mediaelements option to 'preferFlash', due to an error with native player: "+e.target.src+" Mediaerror: "+ media.prop('error')); + } + }, 9); + }); + } else{ + document.removeEventListener('error', switchOptions, true); } - webshims.ready('WINDOWLOAD '+swfType, function(){ - setTimeout(function(){ - if(hasSwf && !options.preferFlash && webshims.mediaelement.createSWF && !$(e.target).closest('audio, video').is('.nonnative-api-active')){ - options.preferFlash = true; - document.removeEventListener('error', switchOptions, true); - $('audio, video').each(function(){ - webshims.mediaelement.selectSource(this); - }); - webshims.info("switching mediaelements option to 'preferFlash', due to an error with native player: "+e.target.src); - } else if(!hasSwf){ - document.removeEventListener('error', switchOptions, true); - } - }, 20); - }); }); } }; document.addEventListener('error', switchOptions, true); $('audio, video').each(function(){ - if(this.error){ + var error = $.prop(this, 'error'); + if(error && !noSwitch[error]){ switchOptions({target: this}); + return false; } }); } @@ -1201,10 +606,11 @@ if(this && $.nodeName(this, 'track')){ webshims.error("track support was overwritten. Please check your vtt including your vtt mime-type"); } else { webshims.info("track support was overwritten. due to bad browser support"); } + return false; } }; var detectTrackError = function(){ document.addEventListener('error', trackListener, true); @@ -1224,11 +630,11 @@ })(); } webshims.register('mediaelement-core', function($, webshims, window, document, undefined){ - hasSwf = swfobject.hasFlashPlayerVersion('9.0.115'); + hasSwf = swfmini.hasFlashPlayerVersion('9.0.115'); $('html').addClass(hasSwf ? 'swf' : 'no-swf'); var mediaelement = webshims.mediaelement; mediaelement.parseRtmp = function(data){ var src = data.src.split('://'); var paths = src[1].split('/'); @@ -1317,11 +723,11 @@ return function(){ if(loaded || !hasYt){return;} loaded = true; webshims.loader.loadScript("https://www.youtube.com/player_api"); $(function(){ - webshims.polyfill("mediaelement-yt"); + webshims._polyfill(["mediaelement-yt"]); }); }; })(); var loadThird = function(){ if(hasSwf){ @@ -1441,11 +847,11 @@ mediaelement.srces(this, srces); $(this).mediaLoad(); }); }; - mediaelement.swfMimeTypes = ['video/3gpp', 'video/x-msvideo', 'video/quicktime', 'video/x-m4v', 'video/mp4', 'video/m4p', 'video/x-flv', 'video/flv', 'audio/mpeg', 'audio/aac', 'audio/mp4', 'audio/x-m4a', 'audio/m4a', 'audio/mp3', 'audio/x-fla', 'audio/fla', 'youtube/flv', 'jwplayer/jwplayer', 'video/youtube', 'video/rtmp', 'audio/rtmp']; + mediaelement.swfMimeTypes = ['video/3gpp', 'video/x-msvideo', 'video/quicktime', 'video/x-m4v', 'video/mp4', 'video/m4p', 'video/x-flv', 'video/flv', 'audio/mpeg', 'audio/aac', 'audio/mp4', 'audio/x-m4a', 'audio/m4a', 'audio/mp3', 'audio/x-fla', 'audio/fla', 'youtube/flv', 'video/jarisplayer', 'jarisplayer/jarisplayer', 'video/youtube', 'video/rtmp', 'audio/rtmp']; mediaelement.canThirdPlaySrces = function(mediaElem, srces){ var ret = ''; if(hasSwf || hasYt){ mediaElem = $(mediaElem); @@ -1466,15 +872,16 @@ mediaelement.canNativePlaySrces = function(mediaElem, srces){ var ret = ''; if(hasNative){ mediaElem = $(mediaElem); var nodeName = (mediaElem[0].nodeName || '').toLowerCase(); - if(!nativeCanPlayType[nodeName]){return ret;} + var nativeCanPlay = (nativeCanPlayType[nodeName] || {prop: {_supvalue: false}}).prop._supvalue || mediaElem[0].canPlayType; + if(!nativeCanPlay){return ret;} srces = srces || mediaelement.srces(mediaElem); $.each(srces, function(i, src){ - if(src.type && nativeCanPlayType[nodeName].prop._supvalue.call(mediaElem[0], src.type) ){ + if(src.type && nativeCanPlay.call(mediaElem[0], src.type) ){ ret = src; return false; } }); } @@ -1485,11 +892,11 @@ if(!message){ message = "can't play sources"; } $(elem).pause().data('mediaerror', message); - webshims.warn('mediaelementError: '+ message); + webshims.error('mediaelementError: '+ message); setTimeout(function(){ if($(elem).data('mediaerror')){ $(elem).trigger('mediaerror'); } }, 1); @@ -1559,134 +966,155 @@ data = data || webshims.data(elem, 'mediaelement'); stepSources(elem, data, options.preferFlash || undefined, _srces); }; mediaelement.selectSource = selectSource; + $(document).on('ended', function(e){ var data = webshims.data(e.target, 'mediaelement'); if( supportsLoop && (!data || data.isActive == 'html5') && !$.prop(e.target, 'loop')){return;} setTimeout(function(){ if( $.prop(e.target, 'paused') || !$.prop(e.target, 'loop') ){return;} $(e.target).prop('currentTime', 0).play(); }, 1); }); - if(!supportsLoop){ - webshims.defineNodeNamesBooleanProperty(['audio', 'video'], 'loop'); - } - ['audio', 'video'].forEach(function(nodeName){ - var supLoad = webshims.defineNodeNameProperty(nodeName, 'load', { - prop: { - value: function(){ - var data = webshims.data(this, 'mediaelement'); - selectSource(this, data); - if(hasNative && (!data || data.isActive == 'html5') && supLoad.prop._supvalue){ - supLoad.prop._supvalue.apply(this, arguments); + webshims.ready('dom-support', function(){ + if(!supportsLoop){ + webshims.defineNodeNamesBooleanProperty(['audio', 'video'], 'loop'); + } + + ['audio', 'video'].forEach(function(nodeName){ + var supLoad = webshims.defineNodeNameProperty(nodeName, 'load', { + prop: { + value: function(){ + var data = webshims.data(this, 'mediaelement'); + selectSource(this, data); + if(hasNative && (!data || data.isActive == 'html5') && supLoad.prop._supvalue){ + supLoad.prop._supvalue.apply(this, arguments); + } } } - } - }); - nativeCanPlayType[nodeName] = webshims.defineNodeNameProperty(nodeName, 'canPlayType', { - prop: { - value: function(type){ - var ret = ''; - if(hasNative && nativeCanPlayType[nodeName].prop._supvalue){ - ret = nativeCanPlayType[nodeName].prop._supvalue.call(this, type); - if(ret == 'no'){ - ret = ''; + }); + nativeCanPlayType[nodeName] = webshims.defineNodeNameProperty(nodeName, 'canPlayType', { + prop: { + value: function(type){ + var ret = ''; + if(hasNative && nativeCanPlayType[nodeName].prop._supvalue){ + ret = nativeCanPlayType[nodeName].prop._supvalue.call(this, type); + if(ret == 'no'){ + ret = ''; + } } - } - if(!ret && hasSwf){ - type = $.trim((type || '').split(';')[0]); - if(mediaelement.swfMimeTypes.indexOf(type) != -1){ - ret = 'maybe'; + if(!ret && hasSwf){ + type = $.trim((type || '').split(';')[0]); + if(mediaelement.swfMimeTypes.indexOf(type) != -1){ + ret = 'maybe'; + } } + return ret; } - return ret; } + }); + }); + webshims.onNodeNamesPropertyModify(['audio', 'video'], ['src', 'poster'], { + set: function(){ + var elem = this; + var baseData = webshims.data(elem, 'mediaelementBase') || webshims.data(elem, 'mediaelementBase', {}); + clearTimeout(baseData.loadTimer); + baseData.loadTimer = setTimeout(function(){ + selectSource(elem); + elem = null; + }, 9); } }); }); - webshims.onNodeNamesPropertyModify(['audio', 'video'], ['src', 'poster'], { - set: function(){ - var elem = this; - var baseData = webshims.data(elem, 'mediaelementBase') || webshims.data(elem, 'mediaelementBase', {}); - clearTimeout(baseData.loadTimer); - baseData.loadTimer = setTimeout(function(){ - selectSource(elem); - elem = null; - }, 9); - } - }); var initMediaElements = function(){ - - webshims.addReady(function(context, insertedElement){ - var media = $('video, audio', context) - .add(insertedElement.filter('video, audio')) - .each(function(){ - var data = webshims.data(this, 'mediaelement'); + var testFixMedia = function(){ + if(webshims.implement(this, 'mediaelement')){ + selectSource(this); + + if(hasNative){ + var bufferTimer; + var lastBuffered; + var elem = this; + var getBufferedString = function(){ + var buffered = $.prop(elem, 'buffered'); + if(!buffered){return;} + var bufferString = ""; + for(var i = 0, len = buffered.length; i < len;i++){ + bufferString += buffered.end(i); + } + return bufferString; + }; + var testBuffer = function(){ + var buffered = getBufferedString(); + if(buffered != lastBuffered){ + lastBuffered = buffered; + $(elem).triggerHandler('progress'); + } + }; - if(hasNative && $.prop(this, 'paused') && !$.prop(this, 'readyState') && $(this).is('audio[preload="none"][controls]:not([autoplay])') && (!data || data.isActive == 'html5')){ - //IE controls not visible bug - $(this).prop('preload', 'metadata').mediaLoad(); - } else { - selectSource(this, data); - } - - if(hasNative){ - - //FF progress bug - (function(){ - var bufferTimer; - var lastBuffered; - var elem = this; - var getBufferedString = function(){ - var buffered = $.prop(elem, 'buffered'); - if(!buffered){return;} - var bufferString = ""; - for(var i = 0, len = buffered.length; i < len;i++){ - bufferString += buffered.end(i); + $(this) + .on({ + 'play loadstart progress': function(e){ + if(e.type == 'progress'){ + lastBuffered = getBufferedString(); } - return bufferString; - }; - var testBuffer = function(){ - var buffered = getBufferedString(); - if(buffered != lastBuffered){ - lastBuffered = buffered; - $(elem).triggerHandler('progress'); + clearTimeout(bufferTimer); + bufferTimer = setTimeout(testBuffer, 999); + }, + 'emptied stalled mediaerror abort suspend': function(e){ + if(e.type == 'emptied'){ + lastBuffered = false; } - }; - - $(this) - .on({ - 'play loadstart progress': function(e){ - if(e.type == 'progress'){ - lastBuffered = getBufferedString(); - } - clearTimeout(bufferTimer); - bufferTimer = setTimeout(testBuffer, 999); - }, - 'emptied stalled mediaerror abort suspend': function(e){ - if(e.type == 'emptied'){ - lastBuffered = false; - } - clearTimeout(bufferTimer); - } - }) - ; - })(); + clearTimeout(bufferTimer); + } + }) + ; + if('ActiveXObject' in window && $.prop(this, 'paused') && !$.prop(this, 'readyState') && $(this).is('audio[preload="none"][controls]:not([autoplay],.nonnative-api-active)')){ + $(this).prop('preload', 'metadata').mediaLoad(); } - - }) - ; - if(!loadTrackUi.loaded && $('track', media).length){ - loadTrackUi(); + } } - media = null; + + }; + var handleMedia = false; + + + webshims.ready('dom-support', function(){ + handleMedia = true; + webshims.addReady(function(context, insertedElement){ + var media = $('video, audio', context) + .add(insertedElement.filter('video, audio')) + .each(testFixMedia) + ; + if(!loadTrackUi.loaded && $('track', media).length){ + loadTrackUi(); + } + media = null; + }); }); + + if(hasNative && !handleMedia){ + webshims.addReady(function(context, insertedElement){ + if(!handleMedia){ + $('video, audio', context) + .add(insertedElement.filter('video, audio')) + .each(function(){ + if(!mediaelement.canNativePlaySrces(this) || (!loadTrackUi.loaded && $('track', this).length)){ + loadThird(); + handleMedia = true; + return false; + } + }) + ; + } + }); + } }; if(Modernizr.track && !bugs.track){ webshims.defineProperty(TextTrack.prototype, 'shimActiveCues', { get: function(){ @@ -1702,6 +1130,824 @@ } else { webshims.ready(swfType, initMediaElements); } webshims.ready('WINDOWLOAD mediaelement', loadTrackUi); }); -})(jQuery, Modernizr, jQuery.webshims); +})(jQuery, Modernizr, jQuery.webshims); +jQuery.webshims.register('track', function($, webshims, window, document, undefined){ + "use strict"; + var mediaelement = webshims.mediaelement; + var id = new Date().getTime(); + var ADDBACK = $.fn.addBack ? 'addBack' : 'andSelf'; + //descriptions are not really shown, but they are inserted into the dom + var showTracks = {subtitles: 1, captions: 1, descriptions: 1}; + var notImplemented = function(){ + webshims.error('not implemented yet'); + }; + var dummyTrack = $('<track />'); + var supportTrackMod = Modernizr.ES5 && Modernizr.objectAccessor; + var createEventTarget = function(obj){ + var eventList = {}; + obj.addEventListener = function(name, fn){ + if(eventList[name]){ + webshims.error('always use $.on to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn); + } + eventList[name] = fn; + + }; + obj.removeEventListener = function(name, fn){ + if(eventList[name] && eventList[name] != fn){ + webshims.error('always use $.on/$.off to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn); + } + if(eventList[name]){ + delete eventList[name]; + } + }; + return obj; + }; + + var cueListProto = { + getCueById: function(id){ + var cue = null; + for(var i = 0, len = this.length; i < len; i++){ + if(this[i].id === id){ + cue = this[i]; + break; + } + } + return cue; + } + }; + var numericModes = { + 0: 'disabled', + 1: 'hidden', + 2: 'showing' + }; + + var textTrackProto = { + shimActiveCues: null, + _shimActiveCues: null, + activeCues: null, + cues: null, + kind: 'subtitles', + label: '', + language: '', + mode: 'disabled', + readyState: 0, + oncuechange: null, + toString: function() { + return "[object TextTrack]"; + }, + addCue: function(cue){ + if(!this.cues){ + this.cues = mediaelement.createCueList(); + } else { + var lastCue = this.cues[this.cues.length-1]; + if(lastCue && lastCue.startTime > cue.startTime){ + webshims.error("cue startTime higher than previous cue's startTime"); + } + } + if(cue.track && cue.track.removeCue){ + cue.track.removeCue(cue); + } + cue.track = this; + this.cues.push(cue); + }, + //ToDo: make it more dynamic + removeCue: function(cue){ + var cues = this.cues || []; + var i = 0; + var len = cues.length; + if(cue.track != this){ + webshims.error("cue not part of track"); + return; + } + for(; i < len; i++){ + if(cues[i] === cue){ + cues.splice(i, 1); + cue.track = null; + break; + } + } + if(cue.track){ + webshims.error("cue not part of track"); + return; + } + }, + DISABLED: 'disabled', + OFF: 'disabled', + HIDDEN: 'hidden', + SHOWING: 'showing', + ERROR: 3, + LOADED: 2, + LOADING: 1, + NONE: 0 + }; + var copyProps = ['kind', 'label', 'srclang']; + var copyName = {srclang: 'language'}; + + var owns = Function.prototype.call.bind(Object.prototype.hasOwnProperty); + + var updateMediaTrackList = function(baseData, trackList){ + var removed = []; + var added = []; + var newTracks = []; + var i, len; + if(!baseData){ + baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {}); + } + + if(!trackList){ + baseData.blockTrackListUpdate = true; + trackList = $.prop(this, 'textTracks'); + baseData.blockTrackListUpdate = false; + } + + clearTimeout(baseData.updateTrackListTimer); + + $('track', this).each(function(){ + var track = $.prop(this, 'track'); + newTracks.push(track); + if(trackList.indexOf(track) == -1){ + added.push(track); + } + }); + + if(baseData.scriptedTextTracks){ + for(i = 0, len = baseData.scriptedTextTracks.length; i < len; i++){ + newTracks.push(baseData.scriptedTextTracks[i]); + if(trackList.indexOf(baseData.scriptedTextTracks[i]) == -1){ + added.push(baseData.scriptedTextTracks[i]); + } + } + } + + for(i = 0, len = trackList.length; i < len; i++){ + if(newTracks.indexOf(trackList[i]) == -1){ + removed.push(trackList[i]); + } + } + + if(removed.length || added.length){ + trackList.splice(0); + + for(i = 0, len = newTracks.length; i < len; i++){ + trackList.push(newTracks[i]); + } + for(i = 0, len = removed.length; i < len; i++){ + $([trackList]).triggerHandler($.Event({type: 'removetrack', track: removed[i]})); + } + for(i = 0, len = added.length; i < len; i++){ + $([trackList]).triggerHandler($.Event({type: 'addtrack', track: added[i]})); + } + if(baseData.scriptedTextTracks || removed.length){ + $(this).triggerHandler('updatetrackdisplay'); + } + } + }; + + var refreshTrack = function(track, trackData){ + if(!trackData){ + trackData = webshims.data(track, 'trackData'); + } + if(trackData && !trackData.isTriggering){ + trackData.isTriggering = true; + setTimeout(function(){ + if(!(trackData.track || {}).readyState){ + $(track).triggerHandler('checktrackmode'); + } else { + $(track).closest('audio, video').triggerHandler('updatetrackdisplay'); + } + trackData.isTriggering = false; + }, 1); + } + }; + + var emptyDiv = $('<div />')[0]; + window.TextTrackCue = function(startTime, endTime, text){ + if(arguments.length != 3){ + webshims.error("wrong arguments.length for TextTrackCue.constructor"); + } + + this.startTime = startTime; + this.endTime = endTime; + this.text = text; + + this.id = ""; + this.pauseOnExit = false; + + createEventTarget(this); + }; + + window.TextTrackCue.prototype = { + + onenter: null, + onexit: null, + pauseOnExit: false, + getCueAsHTML: function(){ + var lastText = ""; + var parsedText = ""; + var fragment = document.createDocumentFragment(); + var fn; + if(!owns(this, 'getCueAsHTML')){ + fn = this.getCueAsHTML = function(){ + var i, len; + if(lastText != this.text){ + lastText = this.text; + parsedText = mediaelement.parseCueTextToHTML(lastText); + emptyDiv.innerHTML = parsedText; + + for(i = 0, len = emptyDiv.childNodes.length; i < len; i++){ + fragment.appendChild(emptyDiv.childNodes[i].cloneNode(true)); + } + } + return fragment.cloneNode(true); + }; + + } + return fn ? fn.apply(this, arguments) : fragment.cloneNode(true); + }, + track: null, + + + id: '' + //todo--> +// , +// snapToLines: true, +// line: 'auto', +// size: 100, +// position: 50, +// vertical: '', +// align: 'middle' + }; + + + + + + mediaelement.createCueList = function(){ + return $.extend([], cueListProto); + }; + + mediaelement.parseCueTextToHTML = (function(){ + var tagSplits = /(<\/?[^>]+>)/ig; + var allowedTags = /^(?:c|v|ruby|rt|b|i|u)/; + var regEnd = /\<\s*\//; + var addToTemplate = function(localName, attribute, tag, html){ + var ret; + if(regEnd.test(html)){ + ret = '</'+ localName +'>'; + } else { + tag.splice(0, 1); + ret = '<'+ localName +' '+ attribute +'="'+ (tag.join(' ').replace(/\"/g, '&#34;')) +'">'; + } + return ret; + }; + var replacer = function(html){ + var tag = html.replace(/[<\/>]+/ig,"").split(/[\s\.]+/); + if(tag[0]){ + tag[0] = tag[0].toLowerCase(); + if(allowedTags.test(tag[0])){ + if(tag[0] == 'c'){ + html = addToTemplate('span', 'class', tag, html); + } else if(tag[0] == 'v'){ + html = addToTemplate('q', 'title', tag, html); + } + } else { + html = ""; + } + } + return html; + }; + + return function(cueText){ + return cueText.replace(tagSplits, replacer); + }; + })(); + + mediaelement.loadTextTrack = function(mediaelem, track, trackData, _default){ + var loadEvents = 'play playing timeupdate updatetrackdisplay'; + var obj = trackData.track; + var load = function(){ + var src = $.prop(track, 'src'); + var error; + var ajax; + if(obj.mode != 'disabled' && src && $.attr(track, 'src')){ + $(mediaelem).unbind(loadEvents, load); + $(track).unbind('checktrackmode', load); + if(!obj.readyState){ + error = function(){ + obj.readyState = 3; + obj.cues = null; + obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = null; + $(track).triggerHandler('error'); + }; + obj.readyState = 1; + try { + obj.cues = mediaelement.createCueList(); + obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = mediaelement.createCueList(); + ajax = $.ajax({ + dataType: 'text', + url: src, + success: function(text){ + if(ajax.getResponseHeader('content-type') != 'text/vtt'){ + webshims.error('set the mime-type of your WebVTT files to text/vtt. see: http://dev.w3.org/html5/webvtt/#text/vtt'); + } + mediaelement.parseCaptions(text, obj, function(cues){ + if(cues && 'length' in cues){ + obj.readyState = 2; + $(track).triggerHandler('load'); + $(mediaelem).triggerHandler('updatetrackdisplay'); + } else { + error(); + } + }); + + }, + error: error + }); + } catch(er){ + error(); + webshims.warn(er); + } + } + } + }; + obj.readyState = 0; + obj.shimActiveCues = null; + obj._shimActiveCues = null; + obj.activeCues = null; + obj.cues = null; + $(mediaelem).unbind(loadEvents, load); + $(track).unbind('checktrackmode', load); + $(mediaelem).on(loadEvents, load); + $(track).on('checktrackmode', load); + if(_default){ + obj.mode = showTracks[obj.kind] ? 'showing' : 'hidden'; + load(); + } + }; + + mediaelement.createTextTrack = function(mediaelem, track){ + var obj, trackData; + if(track.nodeName){ + trackData = webshims.data(track, 'trackData'); + + if(trackData){ + refreshTrack(track, trackData); + obj = trackData.track; + } + } + + if(!obj){ + obj = createEventTarget(webshims.objectCreate(textTrackProto)); + + if(!supportTrackMod){ + copyProps.forEach(function(copyProp){ + var prop = $.prop(track, copyProp); + if(prop){ + obj[copyName[copyProp] || copyProp] = prop; + } + }); + } + + + if(track.nodeName){ + + if(supportTrackMod){ + copyProps.forEach(function(copyProp){ + webshims.defineProperty(obj, copyName[copyProp] || copyProp, { + get: function(){ + return $.prop(track, copyProp); + } + }); + }); + } + + trackData = webshims.data(track, 'trackData', {track: obj}); + mediaelement.loadTextTrack(mediaelem, track, trackData, ($.prop(track, 'default') && $(track).siblings('track[default]')[ADDBACK]()[0] == track)); + } else { + if(supportTrackMod){ + copyProps.forEach(function(copyProp){ + webshims.defineProperty(obj, copyName[copyProp] || copyProp, { + value: track[copyProp], + writeable: false + }); + }); + } + obj.cues = mediaelement.createCueList(); + obj.activeCues = obj._shimActiveCues = obj.shimActiveCues = mediaelement.createCueList(); + obj.mode = 'hidden'; + obj.readyState = 2; + } + } + return obj; + }; + + +/* +taken from: +Captionator 0.5.1 [CaptionCrunch] +Christopher Giffard, 2011 +Share and enjoy + +https://github.com/cgiffard/Captionator + +modified for webshims +*/ + mediaelement.parseCaptionChunk = (function(){ + // Set up timestamp parsers + var WebVTTTimestampParser = /^(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s+\-\-\>\s+(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s*(.*)/; + var GoogleTimestampParser = /^([\d\.]+)\s+\+([\d\.]+)\s*(.*)/; + var WebVTTDEFAULTSCueParser = /^(DEFAULTS|DEFAULT)\s+\-\-\>\s+(.*)/g; + var WebVTTSTYLECueParser = /^(STYLE|STYLES)\s+\-\-\>\s*\n([\s\S]*)/g; + var WebVTTCOMMENTCueParser = /^(COMMENT|COMMENTS)\s+\-\-\>\s+(.*)/g; + + return function(subtitleElement,objectCount){ + var cueDefaults = []; + + var subtitleParts, timeIn, timeOut, html, timeData, subtitlePartIndex, cueSettings = "", id, specialCueData; + var timestampMatch, tmpCue; + + // WebVTT Special Cue Logic + if ((specialCueData = WebVTTDEFAULTSCueParser.exec(subtitleElement))) { +// cueDefaults = specialCueData.slice(2).join(""); +// cueDefaults = cueDefaults.split(/\s+/g).filter(function(def) { return def && !!def.length; }); + return null; + } else if ((specialCueData = WebVTTSTYLECueParser.exec(subtitleElement))) { + return null; + } else if ((specialCueData = WebVTTCOMMENTCueParser.exec(subtitleElement))) { + return null; // At this stage, we don't want to do anything with these. + } + + subtitleParts = subtitleElement.split(/\n/g); + + // Trim off any blank lines (logically, should only be max. one, but loop to be sure) + while (!subtitleParts[0].replace(/\s+/ig,"").length && subtitleParts.length > 0) { + subtitleParts.shift(); + } + + if (subtitleParts[0].match(/^\s*[a-z0-9-\_]+\s*$/ig)) { + // The identifier becomes the cue ID (when *we* load the cues from file. Programatically created cues can have an ID of whatever.) + id = String(subtitleParts.shift().replace(/\s*/ig,"")); + } + + for (subtitlePartIndex = 0; subtitlePartIndex < subtitleParts.length; subtitlePartIndex ++) { + var timestamp = subtitleParts[subtitlePartIndex]; + + if ((timestampMatch = WebVTTTimestampParser.exec(timestamp))) { + + // WebVTT + + timeData = timestampMatch.slice(1); + + timeIn = parseInt((timeData[0]||0) * 60 * 60,10) + // Hours + parseInt((timeData[1]||0) * 60,10) + // Minutes + parseInt((timeData[2]||0),10) + // Seconds + parseFloat("0." + (timeData[3]||0)); // MS + + timeOut = parseInt((timeData[4]||0) * 60 * 60,10) + // Hours + parseInt((timeData[5]||0) * 60,10) + // Minutes + parseInt((timeData[6]||0),10) + // Seconds + parseFloat("0." + (timeData[7]||0)); // MS +/* + if (timeData[8]) { + cueSettings = timeData[8]; + } +*/ + } + + // We've got the timestamp - return all the other unmatched lines as the raw subtitle data + subtitleParts = subtitleParts.slice(0,subtitlePartIndex).concat(subtitleParts.slice(subtitlePartIndex+1)); + break; + } + + if (!timeIn && !timeOut) { + // We didn't extract any time information. Assume the cue is invalid! + webshims.warn("couldn't extract time information: "+[timeIn, timeOut, subtitleParts.join("\n"), id].join(' ; ')); + return null; + } +/* + // Consolidate cue settings, convert defaults to object + var compositeCueSettings = + cueDefaults + .reduce(function(previous,current,index,array){ + previous[current.split(":")[0]] = current.split(":")[1]; + return previous; + },{}); + + // Loop through cue settings, replace defaults with cue specific settings if they exist + compositeCueSettings = + cueSettings + .split(/\s+/g) + .filter(function(set) { return set && !!set.length; }) + // Convert array to a key/val object + .reduce(function(previous,current,index,array){ + previous[current.split(":")[0]] = current.split(":")[1]; + return previous; + },compositeCueSettings); + + // Turn back into string like the TextTrackCue constructor expects + cueSettings = ""; + for (var key in compositeCueSettings) { + if (compositeCueSettings.hasOwnProperty(key)) { + cueSettings += !!cueSettings.length ? " " : ""; + cueSettings += key + ":" + compositeCueSettings[key]; + } + } +*/ + // The remaining lines are the subtitle payload itself (after removing an ID if present, and the time); + html = subtitleParts.join("\n"); + tmpCue = new TextTrackCue(timeIn, timeOut, html); + if(id){ + tmpCue.id = id; + } + return tmpCue; + }; + })(); + + mediaelement.parseCaptions = function(captionData, track, complete) { + var subtitles = mediaelement.createCueList(); + var cue, lazyProcess, regWevVTT; + var startDate; + var isWEBVTT; + if (captionData) { + + regWevVTT = /^WEBVTT(\s*FILE)?/ig; + + lazyProcess = function(i, len){ + + for(; i < len; i++){ + cue = captionData[i]; + if(regWevVTT.test(cue)){ + isWEBVTT = true; + } else if(cue.replace(/\s*/ig,"").length){ + if(!isWEBVTT){ + webshims.error('please use WebVTT format. This is the standard'); + complete(null); + break; + } + cue = mediaelement.parseCaptionChunk(cue, i); + if(cue){ + track.addCue(cue); + } + } + if(startDate < (new Date().getTime()) - 30){ + i++; + setTimeout(function(){ + startDate = new Date().getTime(); + lazyProcess(i, len); + }, 90); + + break; + } + } + if(i >= len){ + if(!isWEBVTT){ + webshims.error('please use WebVTT format. This is the standard'); + } + complete(track.cues); + } + }; + + captionData = captionData.replace(/\r\n/g,"\n"); + + setTimeout(function(){ + captionData = captionData.replace(/\r/g,"\n"); + setTimeout(function(){ + startDate = new Date().getTime(); + captionData = captionData.split(/\n\n+/g); + lazyProcess(0, captionData.length); + }, 9); + }, 9); + + } else { + webshims.error("Required parameter captionData not supplied."); + } + }; + + + mediaelement.createTrackList = function(mediaelem, baseData){ + baseData = baseData || webshims.data(mediaelem, 'mediaelementBase') || webshims.data(mediaelem, 'mediaelementBase', {}); + if(!baseData.textTracks){ + baseData.textTracks = []; + webshims.defineProperties(baseData.textTracks, { + onaddtrack: {value: null}, + onremovetrack: {value: null} + }); + createEventTarget(baseData.textTracks); + } + return baseData.textTracks; + }; + + if(!Modernizr.track){ + webshims.defineNodeNamesBooleanProperty(['track'], 'default'); + webshims.reflectProperties(['track'], ['srclang', 'label']); + + webshims.defineNodeNameProperties('track', { + src: { + //attr: {}, + reflect: true, + propType: 'src' + } + }); + } + + webshims.defineNodeNameProperties('track', { + kind: { + attr: Modernizr.track ? { + set: function(value){ + var trackData = webshims.data(this, 'trackData'); + this.setAttribute('data-kind', value); + if(trackData){ + trackData.attrKind = value; + } + }, + get: function(){ + var trackData = webshims.data(this, 'trackData'); + if(trackData && ('attrKind' in trackData)){ + return trackData.attrKind; + } + return this.getAttribute('kind'); + } + } : {}, + reflect: true, + propType: 'enumarated', + defaultValue: 'subtitles', + limitedTo: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata'] + } + }); + + $.each(copyProps, function(i, copyProp){ + var name = copyName[copyProp] || copyProp; + webshims.onNodeNamesPropertyModify('track', copyProp, function(){ + var trackData = webshims.data(this, 'trackData'); + var track = this; + if(trackData){ + if(copyProp == 'kind'){ + refreshTrack(this, trackData); + } + if(!supportTrackMod){ + trackData.track[name] = $.prop(this, copyProp); + } + clearTimeout(trackData.changedTrackPropTimer); + trackData.changedTrackPropTimer = setTimeout(function(){ + $(track).trigger('updatesubtitlestate'); + }, 1); + } + }); + }); + + + webshims.onNodeNamesPropertyModify('track', 'src', function(val){ + if(val){ + var data = webshims.data(this, 'trackData'); + var media; + if(data){ + media = $(this).closest('video, audio'); + if(media[0]){ + mediaelement.loadTextTrack(media, this, data); + } + } + } + + }); + + // + + webshims.defineNodeNamesProperties(['track'], { + ERROR: { + value: 3 + }, + LOADED: { + value: 2 + }, + LOADING: { + value: 1 + }, + NONE: { + value: 0 + }, + readyState: { + get: function(){ + return ($.prop(this, 'track') || {readyState: 0}).readyState; + }, + writeable: false + }, + track: { + get: function(){ + return mediaelement.createTextTrack($(this).closest('audio, video')[0], this); + }, + writeable: false + } + }, 'prop'); + + webshims.defineNodeNamesProperties(['audio', 'video'], { + textTracks: { + get: function(){ + var media = this; + var baseData = webshims.data(media, 'mediaelementBase') || webshims.data(media, 'mediaelementBase', {}); + var tracks = mediaelement.createTrackList(media, baseData); + if(!baseData.blockTrackListUpdate){ + updateMediaTrackList.call(media, baseData, tracks); + } + return tracks; + }, + writeable: false + }, + addTextTrack: { + value: function(kind, label, lang){ + var textTrack = mediaelement.createTextTrack(this, { + kind: dummyTrack.prop('kind', kind || '').prop('kind'), + label: label || '', + srclang: lang || '' + }); + var baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {}); + if (!baseData.scriptedTextTracks) { + baseData.scriptedTextTracks = []; + } + baseData.scriptedTextTracks.push(textTrack); + updateMediaTrackList.call(this); + return textTrack; + } + } + }, 'prop'); + + + $(document).on('emptied ended updatetracklist', function(e){ + if($(e.target).is('audio, video')){ + var baseData = webshims.data(e.target, 'mediaelementBase'); + if(baseData){ + clearTimeout(baseData.updateTrackListTimer); + baseData.updateTrackListTimer = setTimeout(function(){ + updateMediaTrackList.call(e.target, baseData); + }, 0); + } + } + }); + + var getNativeReadyState = function(trackElem, textTrack){ + return textTrack.readyState || trackElem.readyState; + }; + var stopOriginalEvent = function(e){ + if(e.originalEvent){ + e.stopImmediatePropagation(); + } + }; + var startTrackImplementation = function(){ + if(webshims.implement(this, 'track')){ + var shimedTrack = $.prop(this, 'track'); + var origTrack = this.track; + var kind; + var readyState; + if(origTrack){ + kind = $.prop(this, 'kind'); + readyState = getNativeReadyState(this, origTrack); + if (origTrack.mode || readyState) { + shimedTrack.mode = numericModes[origTrack.mode] || origTrack.mode; + } + //disable track from showing + remove UI + if(kind != 'descriptions'){ + origTrack.mode = (typeof origTrack.mode == 'string') ? 'disabled' : 0; + this.kind = 'metadata'; + $(this).attr({kind: kind}); + } + + } + $(this).on('load error', stopOriginalEvent); + } + }; + webshims.addReady(function(context, insertedElement){ + var insertedMedia = insertedElement.filter('video, audio, track').closest('audio, video'); + $('video, audio', context) + .add(insertedMedia) + .each(function(){ + updateMediaTrackList.call(this); + }) + .each(function(){ + if(Modernizr.track){ + var shimedTextTracks = $.prop(this, 'textTracks'); + var origTextTracks = this.textTracks; + if(shimedTextTracks.length != origTextTracks.length){ + webshims.error("textTracks couldn't be copied"); + } + + $('track', this).each(startTrackImplementation); + } + }) + ; + insertedMedia.each(function(){ + var media = this; + var baseData = webshims.data(media, 'mediaelementBase'); + if(baseData){ + clearTimeout(baseData.updateTrackListTimer); + baseData.updateTrackListTimer = setTimeout(function(){ + updateMediaTrackList.call(media, baseData); + }, 9); + } + }); + }); + + if(Modernizr.track){ + $('video, audio').trigger('trackapichange'); + } +}); \ No newline at end of file