');
data.api = false;
data.actionQueue = [];
box = data.shadowElem;
resetSwfProps(data);
data.currentSrc = canPlaySrc.srcProp;
} else {
$(document.getElementById('wrapper-'+ elemId )).remove();
box = $('
')
.css({
position: 'relative',
overflow: 'hidden'
})
;
data = webshims.data(elem, 'mediaelement', webshims.objectCreate(playerStateObj, {
actionQueue: {
value: []
},
shadowElem: {
value: box
},
_elemNodeName: {
value: elemNodeName
},
_elem: {
value: elem
},
currentSrc: {
value: streamRequest ? '' : canPlaySrc.srcProp
},
swfCreated: {
value: true
},
id: {
value: elemId.replace(/-/g, '')
},
buffered: {
value: {
start: function(index){
if(index >= data.buffered.length){
webshims.error('buffered index size error');
return;
}
return 0;
},
end: function(index){
if(index >= data.buffered.length){
webshims.error('buffered index size error');
return;
}
return ( (data.duration - data._bufferedStart) * data._bufferedEnd) + data._bufferedStart;
},
length: 0
}
}
}));
box.insertBefore(elem);
if(hasNative){
$.extend(data, {volume: $.prop(elem, 'volume'), muted: $.prop(elem, 'muted'), paused: $.prop(elem, 'paused')});
}
webshims.addShadowDom(elem, box);
if(!webshims.data(elem, 'mediaelement')){
webshims.data(elem, 'mediaelement', data);
}
addMediaToStopEvents(elem);
mediaelement.setActive(elem, 'third', data);
setElementDimension(data, hasControls);
$(elem)
.on({
'updatemediaelementdimensions loadedmetadata emptied': setDimension,
'remove': function(e){
if(!e.originalEvent && mediaelement.jarisEvent[data.id] && mediaelement.jarisEvent[data.id].elem == elem){
delete mediaelement.jarisEvent[data.id];
clearTimeout(localConnectionTimer);
clearTimeout(data.flashBlock);
}
}
})
.onWSOff('updateshadowdom', setDimension)
;
}
if(mediaelement.jarisEvent[data.id] && mediaelement.jarisEvent[data.id].elem != elem){
webshims.error('something went wrong');
return;
} else if(!mediaelement.jarisEvent[data.id]){
mediaelement.jarisEvent[data.id] = function(jaris){
if(jaris.type == 'ready'){
var onReady = function(){
if(data.api){
if(!data.paused){
data.api.api_play();
}
if(bufferSrc(elem)){
data.api.api_preload();
}
onEvent.ready(jaris, data);
}
};
if(data.api){
onReady();
} else {
setTimeout(onReady, 9);
}
} else {
data.currentTime = jaris.position;
if(data.api){
if(!data._calledMeta && isNaN(jaris.duration) && data.duration != jaris.duration && isNaN(data.duration)){
onEvent.onDataInitialized(jaris, data);
}
if(!data._ppFlag && jaris.type != 'onPlayPause'){
onEvent.onPlayPause(jaris, data);
}
if(onEvent[jaris.type]){
onEvent[jaris.type](jaris, data);
}
}
data.duration = jaris.duration;
}
};
mediaelement.jarisEvent[data.id].elem = elem;
}
createSwf(elem, canPlaySrc, data, elemId, hasControls, elemNodeName);
if(!streamRequest){
trigger(data._elem, 'loadstart');
}
};
var createSwf = function(elem, canPlaySrc, data, elemId, hasControls, elemNodeName){
var vars, elemVars, params, attrs;
var isRtmp = canPlaySrc.type == 'audio/rtmp' || canPlaySrc.type == 'video/rtmp';
var isUserStream = canPlaySrc.type == 'jarisplayer/stream';
vars = $.extend({}, options.vars, {
poster: replaceVar($.attr(elem, 'poster') && $.prop(elem, 'poster') || ''),
source: replaceVar(canPlaySrc.streamId || canPlaySrc.srcProp),
server: replaceVar(canPlaySrc.server || '')
});
elemVars = $(elem).data('vars') || {};
$.extend(vars,
{
id: elemId,
evtId: data.id,
controls: ''+(!isUserStream && hasControls),
autostart: 'false',
nodename: elemNodeName
},
elemVars
);
if(isRtmp){
vars.streamtype = 'rtmp';
} else if(isUserStream){
vars.streamtype = 'usermedia';
} else if(canPlaySrc.type == 'audio/mpeg' || canPlaySrc.type == 'audio/mp3'){
vars.type = 'audio';
vars.streamtype = 'file';
} else if(canPlaySrc.type == 'video/youtube'){
vars.streamtype = 'youtube';
}
attrs = $.extend(
{},
options.attrs,
{
name: elemId,
id: elemId
},
$(elem).data('attrs')
);
params = $.extend(
{},
options.params,
$(elem).data('params')
);
options.changeSWF(vars, elem, canPlaySrc, data, 'embed');
clearTimeout(data.flashBlock);
swfmini.embedSWF(playerSwfPath, elemId, "100%", "100%", "11.3", false, vars, params, attrs, function(swfData){
if(swfData.success){
var fBlocker = function(){
if((!swfData.ref.parentNode) || swfData.ref.style.display == "none"){
$(elem).trigger('flashblocker');
webshims.warn("flashblocker assumed");
}
$(swfData.ref).css({'minHeight': '2px', 'minWidth': '2px', display: 'block'});
};
data.api = swfData.ref;
if(!hasControls){
$(swfData.ref).attr('tabindex', '-1').css('outline', 'none');
}
data.flashBlock = setTimeout(fBlocker, 99);
if(!localConnectionTimer){
clearTimeout(localConnectionTimer);
localConnectionTimer = setTimeout(function(){
fBlocker();
var flash = $(swfData.ref);
if(flash[0].offsetWidth > 1 && flash[0].offsetHeight > 1 && location.protocol.indexOf('file:') === 0){
webshims.error("Add your local development-directory to the local-trusted security sandbox: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html");
} else if(flash[0].offsetWidth < 2 || flash[0].offsetHeight < 2) {
webshims.warn("JS-SWF connection can't be established on hidden or unconnected flash objects");
}
flash = null;
}, 8000);
}
if(isUserStream){
webshim.usermedia.request(elem, canPlaySrc, data);
}
}
});
};
var queueSwfMethod = function(elem, fn, args, data){
data = data || getSwfDataFromElem(elem);
if(data){
if(data.api && data.api[fn]){
data.api[fn].apply(data.api, args || []);
} else {
//todo add to queue
data.actionQueue.push({fn: fn, args: args});
if(data.actionQueue.length > 10){
setTimeout(function(){
if(data.actionQueue.length > 5){
data.actionQueue.shift();
}
}, 99);
}
}
return data;
}
return false;
};
mediaelement.queueSwfMethod = queueSwfMethod;
['audio', 'video'].forEach(function(nodeName){
var descs = {};
var mediaSup;
var createGetProp = function(key){
if(nodeName == 'audio' && (key == 'videoHeight' || key == 'videoWidth')){return;}
descs[key] = {
get: function(){
var data = getSwfDataFromElem(this);
if(data){
return data[key];
} else if(hasNative && mediaSup[key].prop._supget) {
return mediaSup[key].prop._supget.apply(this);
} else {
return playerStateObj[key];
}
},
writeable: false
};
};
var createGetSetProp = function(key, setFn){
createGetProp(key);
delete descs[key].writeable;
descs[key].set = setFn;
};
createGetSetProp('seeking');
createGetSetProp('volume', function(v){
var data = getSwfDataFromElem(this);
if(data){
v *= 1;
if(!isNaN(v)){
if(v < 0 || v > 1){
webshims.error('volume greater or less than allowed '+ (v / 100));
}
queueSwfMethod(this, 'api_volume', [v], data);
if(data.volume != v){
data.volume = v;
trigger(data._elem, 'volumechange');
}
data = null;
}
} else if(mediaSup.volume.prop._supset) {
return mediaSup.volume.prop._supset.apply(this, arguments);
}
});
createGetSetProp('muted', function(m){
var data = getSwfDataFromElem(this);
if(data){
m = !!m;
queueSwfMethod(this, 'api_muted', [m], data);
if(data.muted != m){
data.muted = m;
trigger(data._elem, 'volumechange');
}
data = null;
} else if(mediaSup.muted.prop._supset) {
return mediaSup.muted.prop._supset.apply(this, arguments);
}
});
createGetSetProp('currentTime', function(t){
var data = getSwfDataFromElem(this);
if(data){
t *= 1;
if (!isNaN(t)) {
queueSwfMethod(this, 'api_seek', [t], data);
}
} else if(mediaSup.currentTime.prop._supset) {
return mediaSup.currentTime.prop._supset.apply(this, arguments);
}
});
['play', 'pause'].forEach(function(fn){
descs[fn] = {
value: function(){
var data = getSwfDataFromElem(this);
if(data){
if(data.stopPlayPause){
clearTimeout(data.stopPlayPause);
}
queueSwfMethod(this, fn == 'play' ? 'api_play' : 'api_pause', [], data);
data._ppFlag = true;
if(data.paused != (fn != 'play')){
data.paused = fn != 'play';
trigger(data._elem, fn);
}
} else if(mediaSup[fn].prop._supvalue) {
return mediaSup[fn].prop._supvalue.apply(this, arguments);
}
}
};
});
getPropKeys.forEach(createGetProp);
webshims.onNodeNamesPropertyModify(nodeName, 'controls', function(val, boolProp){
var data = getSwfDataFromElem(this);
$(this)[boolProp ? 'addClass' : 'removeClass']('webshims-controls');
if(data){
if(nodeName == 'audio'){
setElementDimension(data, boolProp);
}
queueSwfMethod(this, 'api_controls', [boolProp], data);
}
});
webshims.onNodeNamesPropertyModify(nodeName, 'preload', function(val){
var data, baseData, elem;
if(bufferSrc(this)){
data = getSwfDataFromElem(this);
if(data){
queueSwfMethod(this, 'api_preload', [], data);
} else if(needsLoadPreload && this.paused && !this.error && !$.data(this, 'mediaerror') && !this.readyState && !this.networkState && !this.autoplay && $(this).is(':not(.nonnative-api-active)')){
elem = this;
baseData = webshims.data(elem, 'mediaelementBase') || webshims.data(elem, 'mediaelementBase', {});
clearTimeout(baseData.loadTimer);
baseData.loadTimer = setTimeout(function(){
$(elem).mediaLoad();
}, 9);
}
}
});
mediaSup = webshims.defineNodeNameProperties(nodeName, descs, 'prop');
if(!support.mediaDefaultMuted){
webshims.defineNodeNameProperties(nodeName, {
defaultMuted: {
get: function(){
return $.attr(this, 'muted') != null;
},
set: function(val){
if(val){
$.attr(this, 'muted', '');
} else {
$(this).removeAttr('muted');
}
}
}
}, 'prop');
}
});
var addCanvasBridge = function(){
if(!window.CanvasRenderingContext2D){
return false;
}
var _drawImage = CanvasRenderingContext2D.prototype.drawImage;
var slice = Array.prototype.slice;
var isVideo = {
video: 1,
VIDEO: 1
};
var tested = {};
var addToBlob = function(){
var desc = webshim.defineNodeNameProperty('canvas', 'toBlob', {
prop: {
value: function(){
var context = $(this).callProp('getContext', ['2d']);
var that = this;
var args = arguments;
var cb = function(){
return desc.prop._supvalue.apply(that, args);
};
if(context.wsImageComplete && context._wsIsLoading){
context.wsImageComplete(cb);
} else {
return cb();
}
}
}
});
};
if(!_drawImage){
webshim.error('canvas.drawImage feature is needed. In IE8 flashvanvas pro can be used');
}
CanvasRenderingContext2D.prototype.wsImageComplete = function(cb){
if(this._wsIsLoading){
if(!this._wsLoadingCbs){
this._wsLoadingCbs = [];
}
this._wsLoadingCbs.push(cb);
} else {
cb.call(this, this);
}
};
CanvasRenderingContext2D.prototype.drawImage = function(elem){
var data, img, args, imgData, hadCachedImg;
var context = this;
if(isVideo[elem.nodeName] && (data = webshims.data(elem, 'mediaelement')) && data.isActive == 'third' && data.api.api_image){
try {
imgData = data.api.api_image();
} catch (er){
webshims.error(er);
}
if(!tested[data.currentSrc]){
tested[data.currentSrc] = true;
if(imgData == null){
webshims.error('video has to be same origin or a crossdomain.xml has to be provided. Video has to be visible for flash API');
}
}
args = slice.call(arguments, 1);
if(options.canvasSync && data.canvasImg){
args.unshift(data.canvasImg);
_drawImage.apply(context, args);
args = slice.call(arguments, 1);
hadCachedImg = true;
}
img = document.createElement('img');
//todo find a performant sync way
img.onload = function(){
args.unshift(this);
img.onload = null;
if(options.canvasSync){
data.canvasImg = img;
if(hadCachedImg && options.noDoubbleDraw){
return;
}
}
_drawImage.apply(context, args);
context._wsIsLoading = false;
if(context._wsLoadingCbs && context._wsLoadingCbs.length){
while(context._wsLoadingCbs.length){
context._wsLoadingCbs.shift().call(context, context);
}
}
};
img.src = 'data:image/jpeg;base64,'+imgData;
this._wsIsLoading = true;
if(img.complete && img.onload){
img.onload();
}
return;
}
return _drawImage.apply(this, arguments);
};
if(!document.createElement('canvas').toBlob){
webshims.ready('filereader', addToBlob);
} else {
addToBlob();
}
return true;
};
if(!addCanvasBridge()){
webshims.ready('canvas', addCanvasBridge);
}
if(hasFlash && $.cleanData){
var oldClean = $.cleanData;
var objElem = document.createElement('object');
var noRemove = {
SetVariable: 1,
GetVariable: 1,
SetReturnValue: 1,
GetReturnValue: 1
};
var flashNames = {
object: 1,
OBJECT: 1
};
$.cleanData = function(elems){
var i, len, prop;
var ret = oldClean.apply(this, arguments);
if(elems && (len = elems.length) && loadedSwf){
for(i = 0; i < len; i++){
if(flashNames[elems[i].nodeName] && 'api_destroy' in elems[i]){
loadedSwf--;
try {
elems[i].api_destroy();
if(elems[i].readyState == 4){
for (prop in elems[i]) {
if (!noRemove[prop] && !objElem[prop] && typeof elems[i][prop] == "function") {
elems[i][prop] = null;
}
}
}
} catch(er){console.log(er);}
}
}
}
return ret;
};
}
if(!hasNative){
['poster', 'src'].forEach(function(prop){
webshims.defineNodeNamesProperty(prop == 'src' ? ['audio', 'video', 'source'] : ['video'], prop, {
//attr: {},
reflect: true,
propType: 'src'
});
});
webshims.defineNodeNamesProperty(['audio', 'video'], 'preload', {
reflect: true,
propType: 'enumarated',
defaultValue: '',
limitedTo: ['', 'auto', 'metadata', 'none']
});
webshims.reflectProperties('source', ['type', 'media']);
['autoplay', 'controls'].forEach(function(name){
webshims.defineNodeNamesBooleanProperty(['audio', 'video'], name);
});
webshims.defineNodeNamesProperties(['audio', 'video'], {
HAVE_CURRENT_DATA: {
value: 2
},
HAVE_ENOUGH_DATA: {
value: 4
},
HAVE_FUTURE_DATA: {
value: 3
},
HAVE_METADATA: {
value: 1
},
HAVE_NOTHING: {
value: 0
},
NETWORK_EMPTY: {
value: 0
},
NETWORK_IDLE: {
value: 1
},
NETWORK_LOADING: {
value: 2
},
NETWORK_NO_SOURCE: {
value: 3
}
}, 'prop');
if(hasFlash){
webshims.ready('WINDOWLOAD', function(){
setTimeout(function(){
if(!loadedSwf){
document.createElement('img').src = playerSwfPath;
}
}, 9);
});
}
} else if(!('media' in document.createElement('source'))){
webshims.reflectProperties('source', ['media']);
}
if(hasNative && hasFlash && !options.preferFlash){
var switchErrors = {
3: 1,
4: 1
};
var switchOptions = function(e){
var media, error, parent;
if(
($(e.target).is('audio, video') || ((parent = e.target.parentNode) && $('source', parent).last()[0] == e.target)) &&
(media = $(e.target).closest('audio, video')) && !media.hasClass('nonnative-api-active')
){
error = media.prop('error');
setTimeout(function(){
if(!media.hasClass('nonnative-api-active')){
if(error && switchErrors[error.code]){
options.preferFlash = true;
document.removeEventListener('error', switchOptions, true);
$('audio, video').each(function(){
webshims.mediaelement.selectSource(this);
});
webshims.error("switching mediaelements option to 'preferFlash', due to an error with native player: "+e.target.currentSrc+" Mediaerror: "+ media.prop('error')+ ' error.code: '+ error.code);
}
webshims.warn('There was a mediaelement error. Run the following line in your console to get more info: webshim.mediaelement.loadDebugger();')
}
});
}
};
document.addEventListener('error', switchOptions, true);
setTimeout(function(){
$('audio, video').each(function(){
var error = $.prop(this, 'error');
if(error && switchErrors[error]){
switchOptions({target: this});
}
});
});
}
});
;webshims.register('track', function($, webshims, window, document, undefined){
"use strict";
var mediaelement = webshims.mediaelement;
var id = new Date().getTime();
//descriptions are not really shown, but they are inserted into the dom
var showTracks = {subtitles: 1, captions: 1, descriptions: 1};
var dummyTrack = $('
');
var support = webshims.support;
var supportTrackMod = support.ES5 && support.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: '',
id: '',
mode: 'disabled',
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");
return;
}
}
if(cue.startTime >= cue.endTime ){
webshim.error('startTime >= endTime of cue: '+ cue.text);
}
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 updateMediaTrackList = function(baseData, trackList){
var i, len;
var callChange = false;
var removed = [];
var added = [];
var newTracks = [];
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]}));
}
//todo: remove
if(baseData.scriptedTextTracks || removed.length){
$(this).triggerHandler('updatetrackdisplay');
}
}
for(i = 0, len = trackList.length; i < len; i++){
if(trackList[i].__wsmode != trackList[i].mode){
trackList[i].__wsmode = trackList[i].mode;
callChange = true;
}
}
if(callChange){
$([trackList]).triggerHandler('change');
}
};
var refreshTrack = function(track, trackData){
if(!trackData){
trackData = webshims.data(track, 'trackData');
}
if(trackData && !trackData.isTriggering){
trackData.isTriggering = true;
setTimeout(function(){
$(track).closest('audio, video').triggerHandler('updatetrackdisplay');
trackData.isTriggering = false;
}, 9);
}
};
var isDefaultTrack = (function(){
var defaultKinds = {
subtitles: {
subtitles: 1,
captions: 1
},
descriptions: {descriptions: 1},
chapters: {chapters: 1}
};
defaultKinds.captions = defaultKinds.subtitles;
return function(track){
var kind, firstDefaultTrack;
var isDefault = $.prop(track, 'default');
if(isDefault && (kind = $.prop(track, 'kind')) != 'metadata'){
firstDefaultTrack = $(track)
.parent()
.find('track[default]')
.filter(function(){
return !!(defaultKinds[kind][$.prop(this, 'kind')]);
})[0]
;
if(firstDefaultTrack != track){
isDefault = false;
webshims.error('more than one default track of a specific kind detected. Fall back to default = false');
}
}
return isDefault;
};
})();
var emptyDiv = $('
')[0];
function VTTCue(startTime, endTime, text){
if(arguments.length != 3){
webshims.error("wrong arguments.length for VTTCue.constructor");
}
this.startTime = startTime;
this.endTime = endTime;
this.text = text;
this.onenter = null;
this.onexit = null;
this.pauseOnExit = false;
this.track = null;
this.id = null;
this.getCueAsHTML = (function(){
var lastText = "";
var parsedText = "";
var fragment;
return function(){
var i, len;
if(!fragment){
fragment = document.createDocumentFragment();
}
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);
};
})();
}
window.VTTCue = VTTCue;
window.TextTrackCue = function(){
webshims.error("Use VTTCue constructor instead of abstract TextTrackCue constructor.");
VTTCue.apply(this, arguments);
};
window.TextTrackCue.prototype = VTTCue.prototype;
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, '"')) +'">';
}
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);
};
})();
var mapTtmlToVtt = function(i){
var content = i+'';
var begin = this.getAttribute('begin') || '';
var end = this.getAttribute('end') || '';
var text = $.trim($.text(this));
if(!/\./.test(begin)){
begin += '.000';
}
if(!/\./.test(end)){
end += '.000';
}
content += '\n';
content += begin +' --> '+end+'\n';
content += text;
return content;
};
var ttmlTextToVTT = function(ttml){
ttml = $.parseXML(ttml) || [];
return $(ttml).find('[begin][end]').map(mapTtmlToVtt).get().join('\n\n') || '';
};
var loadingTracks = 0;
mediaelement.loadTextTrack = function(mediaelem, track, trackData, _default){
var loadEvents = 'play playing loadedmetadata loadstart';
var obj = trackData.track;
var load = function(){
var error, ajax, createAjax;
var isDisabled = obj.mode == 'disabled';
var videoState = !!($.prop(mediaelem, 'readyState') > 0 || $.prop(mediaelem, 'networkState') == 2 || !$.prop(mediaelem, 'paused'));
var src = (!isDisabled || videoState) && ($.attr(track, 'src') && $.prop(track, 'src'));
if(src){
$(mediaelem).off(loadEvents, load).off('updatetrackdisplay', load);
if(!trackData.readyState){
error = function(){
loadingTracks--;
trackData.readyState = 3;
obj.cues = null;
obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = null;
$(track).triggerHandler('error');
};
trackData.readyState = 1;
try {
obj.cues = mediaelement.createCueList();
obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = mediaelement.createCueList();
loadingTracks++;
createAjax = function(){
ajax = $.ajax({
dataType: 'text',
url: src,
success: function(text){
loadingTracks--;
var contentType = ajax.getResponseHeader('content-type') || '';
if(!contentType.indexOf('application/xml')){
text = ttmlTextToVTT(text);
} else if(contentType.indexOf('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){
trackData.readyState = 2;
$(track).triggerHandler('load');
$(mediaelem).triggerHandler('updatetrackdisplay');
} else {
error();
}
});
},
error: error
});
};
if(isDisabled){
setTimeout(createAjax, loadingTracks * 2);
} else {
createAjax();
}
} catch(er){
error();
webshims.error(er);
}
}
}
};
trackData.readyState = 0;
obj.shimActiveCues = null;
obj._shimActiveCues = null;
obj.activeCues = null;
obj.cues = null;
$(mediaelem).on(loadEvents, load);
if(_default){
obj.mode = showTracks[obj.kind] ? 'showing' : 'hidden';
load();
} else {
$(mediaelem).on('updatetrackdisplay', 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);
}
});
});
}
obj.id = $(track).prop('id');
trackData = webshims.data(track, 'trackData', {track: obj});
mediaelement.loadTextTrack(mediaelem, track, trackData, isDefaultTrack(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;
}
if(obj.kind == 'subtitles' && !obj.language){
webshims.error('you must provide a language for track in subtitles state');
}
obj.__wsmode = obj.mode;
webshims.defineProperty(obj, '_wsUpdateMode', {
value: function(){
$(mediaelem).triggerHandler('updatetrackdisplay');
},
enumerable: false
});
}
return obj;
};
if(!$.propHooks.mode){
$.propHooks.mode = {
set: function(obj, value){
obj.mode = value;
if(obj._wsUpdateMode && obj._wsUpdateMode.call){
obj._wsUpdateMode();
}
return obj.mode;
}
};
}
/*
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 WebVTTDEFAULTSCueParser = /^(DEFAULTS|DEFAULT)\s+\-\-\>\s+(.*)/g;
var WebVTTSTYLECueParser = /^(STYLE|STYLES)\s+\-\-\>\s*\n([\s\S]*)/g;
var WebVTTCOMMENTCueParser = /^(COMMENT|COMMENTS)\s+\-\-\>\s+(.*)/g;
var SRTTimestampParser = /^(\d{2})?:?(\d{2}):(\d{2})[\.\,](\d+)\s+\-\-\>\s+(\d{2})?:?(\d{2}):(\d{2})[\.\,](\d+)\s*(.*)/;
return function(subtitleElement,objectCount){
var subtitleParts, timeIn, timeOut, html, timeData, subtitlePartIndex, id;
var timestampMatch, tmpCue;
// WebVTT Special Cue Logic
if (WebVTTDEFAULTSCueParser.exec(subtitleElement) || WebVTTCOMMENTCueParser.exec(subtitleElement) || WebVTTSTYLECueParser.exec(subtitleElement)) {
return null;
}
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)) || (timestampMatch = SRTTimestampParser.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 VTTCue 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 VTTCue(timeIn, timeOut, html);
if(id){
tmpCue.id = id;
}
return tmpCue;
};
})();
mediaelement.parseCaptions = function(captionData, track, complete) {
var cue, lazyProcess, regWevVTT, startDate, isWEBVTT;
mediaelement.createCueList();
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){
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},
onchange: {value: null},
getTrackById: {
value: function(id){
var track = null;
for(var i = 0; i < baseData.textTracks.length; i++){
if(id == baseData.textTracks[i].id){
track = baseData.textTracks[i];
break;
}
}
return track;
}
}
});
createEventTarget(baseData.textTracks);
$(mediaelem).on('updatetrackdisplay', function(){
var track;
for(var i = 0; i < baseData.textTracks.length; i++){
track = baseData.textTracks[i];
if(track.__wsmode != track.mode){
track.__wsmode = track.mode;
$([ baseData.textTracks ]).triggerHandler('change');
}
}
});
}
return baseData.textTracks;
};
if(!support.track){
webshims.defineNodeNamesBooleanProperty(['track'], 'default');
webshims.reflectProperties(['track'], ['srclang', 'label']);
webshims.defineNodeNameProperties('track', {
src: {
//attr: {},
reflect: true,
propType: 'src'
}
});
}
webshims.defineNodeNameProperties('track', {
kind: {
attr: support.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');
if(trackData){
if(copyProp == 'kind'){
refreshTrack(this, trackData);
}
if(!supportTrackMod){
trackData.track[name] = $.prop(this, copyProp);
}
}
});
});
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 (webshims.data(this, 'trackData') || {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');
//wsmediareload
var thUpdateList = 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 hideNativeTracks = function(){
if(webshims.implement(this, 'track')){
var kind;
var origTrack = this.track;
if(origTrack){
if (!webshims.bugs.track && (origTrack.mode || getNativeReadyState(this, origTrack))) {
$.prop(this, 'track').mode = numericModes[origTrack.mode] || origTrack.mode;
}
//disable track from showing + remove UI
kind = $.prop(this, 'kind');
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);
})
.on('emptied updatetracklist wsmediareload', thUpdateList)
.each(function(){
if(support.track){
var shimedTextTracks = $.prop(this, 'textTracks');
var origTextTracks = this.textTracks;
if(shimedTextTracks.length != origTextTracks.length){
webshims.warn("textTracks couldn't be copied");
}
$('track', this).each(hideNativeTracks);
}
})
;
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(support.texttrackapi){
$('video, audio').trigger('trackapichange');
}
});