agenda-libre-ruby/public/webshims/shims/track-ui.js

470 lines
13 KiB
JavaScript

(function($){
if(webshims.support.texttrackapi && document.addEventListener){
var trackOptions = webshims.cfg.track;
var trackListener = function(e){
$(e.target).filter('track').each(changeApi);
};
var trackBugs = webshims.bugs.track;
var changeApi = function(){
if(trackBugs || (!trackOptions.override && $.prop(this, 'readyState') == 3)){
trackOptions.override = true;
webshims.reTest('track');
document.removeEventListener('error', trackListener, true);
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);
if(trackBugs){
changeApi();
} else {
$('track').each(changeApi);
}
if(!trackBugs && !trackOptions.override){
webshims.defineProperty(TextTrack.prototype, 'shimActiveCues', {
get: function(){
return this._shimActiveCues || this.activeCues;
}
});
}
};
if(!trackOptions.override){
$(detectTrackError);
}
}
})(webshims.$);
webshims.register('track-ui', function($, webshims, window, document, undefined){
"use strict";
var options = webshims.cfg.track;
var support = webshims.support;
//descriptions are not really shown, but they are inserted into the dom
var showTracks = {subtitles: 1, captions: 1, descriptions: 1};
var mediaelement = webshims.mediaelement;
var usesNativeTrack = function(){
return !options.override && support.texttrackapi;
};
var requestAnimationFrame = window.cancelAnimationFrame && window.requestAnimationFrame || function(fn){
setTimeout(fn, 17);
};
var cancelAnimationFrame = window.cancelAnimationFrame || window.clearTimeout;
var trackDisplay = {
update: function(baseData, media){
if(!baseData.activeCues.length){
this.hide(baseData);
} else {
if(!compareArray(baseData.displayedActiveCues, baseData.activeCues)){
baseData.displayedActiveCues = baseData.activeCues;
if(!baseData.trackDisplay){
baseData.trackDisplay = $('<div class="cue-display '+webshims.shadowClass+'"><span class="description-cues" aria-live="assertive" /></div>').insertAfter(media);
this.addEvents(baseData, media);
webshims.docObserve();
}
if(baseData.hasDirtyTrackDisplay){
media.triggerHandler('forceupdatetrackdisplay');
}
this.showCues(baseData);
}
}
},
showCues: function(baseData){
var element = $('<span class="cue-wrapper" />');
$.each(baseData.displayedActiveCues, function(i, cue){
var id = (cue.id) ? 'id="cue-id-'+cue.id +'"' : '';
var cueHTML = $('<span class="cue-line"><span '+ id+ ' class="cue" /></span>').find('span').html(cue.getCueAsHTML()).end();
if(cue.track.kind == 'descriptions'){
setTimeout(function(){
$('span.description-cues', baseData.trackDisplay).html(cueHTML);
}, 0);
} else {
element.prepend(cueHTML);
}
});
$('span.cue-wrapper', baseData.trackDisplay).remove();
baseData.trackDisplay.append(element);
},
addEvents: function(baseData, media){
if(options.positionDisplay){
var timer;
var positionDisplay = function(_force){
if(baseData.displayedActiveCues.length || _force === true){
baseData.trackDisplay.css({display: 'none'});
var uiElement = media.getShadowElement();
var uiHeight = uiElement.innerHeight();
var uiWidth = uiElement.innerWidth();
var position = uiElement.position();
baseData.trackDisplay.css({
left: position.left,
width: uiWidth,
height: uiHeight - 45,
top: position.top,
display: 'block'
});
baseData.trackDisplay.css('fontSize', Math.max(Math.round(uiHeight / 30), 7));
baseData.hasDirtyTrackDisplay = false;
} else {
baseData.hasDirtyTrackDisplay = true;
}
};
var delayed = function(e){
clearTimeout(timer);
timer = setTimeout(positionDisplay, 0);
};
var forceUpdate = function(){
positionDisplay(true);
};
media.on('playerdimensionchange mediaelementapichange updatetrackdisplay updatemediaelementdimensions swfstageresize', delayed);
media.on('forceupdatetrackdisplay', forceUpdate).onWSOff('updateshadowdom', delayed);
forceUpdate();
}
},
hide: function(baseData){
if(baseData.trackDisplay && baseData.displayedActiveCues.length){
baseData.displayedActiveCues = [];
$('span.cue-wrapper', baseData.trackDisplay).remove();
$('span.description-cues', baseData.trackDisplay).empty();
}
}
};
function compareArray(a1, a2){
var ret = true;
var i = 0;
var len = a1.length;
if(len != a2.length){
ret = false;
} else {
for(; i < len; i++){
if(a1[i] != a2[i]){
ret = false;
break;
}
}
}
return ret;
}
mediaelement.trackDisplay = trackDisplay;
if(!mediaelement.createCueList){
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;
}
};
mediaelement.createCueList = function(){
return $.extend([], cueListProto);
};
}
function triggerCueEvent(cue, type, baseData, media, trackIndex){
var trackElem, compareTrack;
var cueChange = $.Event('cuechange');
if(!baseData.trackElements){
baseData.trackElements = media[0].getElementsByTagName('track');
}
trackElem = baseData.trackElements[trackIndex];
if(trackElem){
compareTrack = (webshims.data(trackElem, 'trackData') || {track: $.prop(trackElem, 'track')}).track;
if(compareTrack != cue.track){
trackElem = null;
}
}
$.event.trigger(cueChange, null, cue.track, true);
if(trackElem){
$.event.trigger(cueChange, null, trackElem, true);
}
$.event.trigger(type, null, cue, true);
}
mediaelement.getActiveCue = function(track, media, time, baseData, trackIndex){
if(!track._lastFoundCue){
track._lastFoundCue = {index: 0, time: 0};
}
if(!track._shimActiveCues && support.texttrackapi && !options.override){
track._shimActiveCues = mediaelement.createCueList();
}
var i = 0;
var len, cue, delay;
for(; i < track.shimActiveCues.length; i++){
cue = track.shimActiveCues[i];
if(cue.startTime > time || cue.endTime < time){
track.shimActiveCues.splice(i, 1);
i--;
if(cue.pauseOnExit){
$(media).pause();
}
triggerCueEvent(cue, 'exit', baseData, media, trackIndex);
} else {
delay = cue.endTime - time;
if(baseData.nextUpdateDelay > delay){
baseData.nextUpdateDelay = delay;
baseData.nextEvent = cue.endTime;
}
if(track.mode == 'showing' && showTracks[track.kind] && $.inArray(cue, baseData.activeCues) == -1){
baseData.activeCues.push(cue);
}
}
}
len = track.cues.length;
i = track._lastFoundCue.time < time ? track._lastFoundCue.index : 0;
for(; i < len; i++){
cue = track.cues[i];
if(cue.startTime <= time && cue.endTime >= time && $.inArray(cue, track.shimActiveCues) == -1){
track.shimActiveCues.push(cue);
if(track.mode == 'showing' && showTracks[track.kind]){
baseData.activeCues.push(cue);
}
triggerCueEvent(cue, 'enter', baseData, media, trackIndex);
track._lastFoundCue.time = time;
track._lastFoundCue.index = i;
delay = cue.endTime - time;
if(baseData.nextUpdateDelay > delay){
baseData.nextUpdateDelay = delay;
baseData.nextEvent = cue.endTime;
}
}
if(cue.startTime > time){
delay = cue.startTime - time;
if(baseData.nextUpdateDelay > delay){
baseData.nextUpdateDelay = delay;
baseData.nextEvent = cue.startTime;
}
break;
}
}
};
var filterTrackImplementation = function(){
return webshims.implement(this, 'trackui');
};
var implementTrackUi = function(){
var baseData, trackList, updateTimer, updateTimer2, lastDelay, lastTime, invalidTracksTimer;
var treshHold = 0.27;
var elem = $(this);
var recheckI = 0;
var recheckId;
var reCheck = function(){
recheckI++;
//if recheckI is over 5 video might be paused, stalled or waiting,
//in this case abort and wait for the next play, playing or timeupdate event
if(recheckI < 9){
if(elem.prop('currentTime') > baseData.nextEvent){
recheckI = undefined;
getDisplayCues();
} else {
recheckId = requestAnimationFrame(reCheck);
}
} else {
recheckI = undefined;
}
};
var getDisplayCues = function(e){
var track, time;
if(!trackList || !baseData){
trackList = elem.prop('textTracks');
baseData = webshims.data(elem[0], 'mediaelementBase') || webshims.data(elem[0], 'mediaelementBase', {});
if(!baseData.displayedActiveCues){
baseData.displayedActiveCues = [];
}
}
if (!trackList){return;}
time = elem.prop('currentTime');
if(!time && time !== 0){return;}
if(baseData.nextEvent && e && e.type == 'timeupdate' && time >= lastTime && baseData.nextEvent - time > treshHold && time - lastTime < 9){
return;
}
lastTime = time;
lastDelay = baseData.nextUpdateDelay;
baseData.nextUpdateDelay = Number.MAX_VALUE;
baseData.activeCues = [];
for(var i = 0, len = trackList.length; i < len; i++){
track = trackList[i];
if(track.mode != 'disabled' && track.cues && track.cues.length){
mediaelement.getActiveCue(track, elem, time, baseData, i);
}
}
trackDisplay.update(baseData, elem);
clearTimeout(updateTimer);
if(baseData.nextUpdateDelay <= treshHold && (e || lastDelay != baseData.nextUpdateDelay) && baseData.nextUpdateDelay > 0){
lastDelay = baseData.nextUpdateDelay;
clearTimeout(updateTimer2);
if(recheckId){
cancelAnimationFrame(recheckId);
}
recheckI = 0;
updateTimer2 = setTimeout(reCheck, (baseData.nextUpdateDelay * 1000) + 9);
} else if(baseData.nextUpdateDelay >= Number.MAX_VALUE){
baseData.nextEvent = time + 2;
}
};
var invalidateTrackElems = function(){
if(baseData && baseData.trackElements){
delete baseData.trackElements;
}
};
var onUpdatCues = function(e){
if(baseData && e && (e.type == 'addtrack' || e.type == 'removetrack')){
clearTimeout(invalidTracksTimer);
invalidTracksTimer = setTimeout(invalidateTrackElems, 39);
}
clearTimeout(updateTimer);
updateTimer = setTimeout(getDisplayCues, 40);
};
var addTrackView = function(){
if(!trackList) {
if(baseData && 'blockTrackListUpdate' in baseData){
baseData.blockTrackListUpdate = true;
}
trackList = elem.prop('textTracks');
if(baseData && baseData.blockTrackListUpdate){
baseData.blockTrackListUpdate = false;
}
}
//as soon as change on trackList is implemented in all browsers we do not need to have 'updatetrackdisplay' anymore
$( [trackList] )
.off('.trackview')
.on('change.trackview addtrack.trackview removetrack.trackview', onUpdatCues)
;
elem
.off('.trackview')
.on('emptied.trackview', invalidateTrackElems)
.on('play.trackview playing.trackview updatetrackdisplay.trackview seeked.trackview', onUpdatCues)
.on('timeupdate.trackview', getDisplayCues)
;
};
elem.on('remove', function(e){
if(!e.originalEvent && baseData && baseData.trackDisplay){
setTimeout(function(){
baseData.trackDisplay.remove();
}, 4);
}
});
if(!usesNativeTrack()){
addTrackView();
} else {
if(elem.hasClass('nonnative-api-active')){
addTrackView();
}
elem
.on('mediaelementapichange trackapichange', function(){
if(!usesNativeTrack() || elem.hasClass('nonnative-api-active')){
addTrackView();
} else {
clearTimeout(updateTimer);
clearTimeout(updateTimer2);
if(recheckId){
cancelAnimationFrame(recheckId);
}
trackList = elem.prop('textTracks');
baseData = webshims.data(elem[0], 'mediaelementBase') || webshims.data(elem[0], 'mediaelementBase', {});
$.each(trackList, function(i, track){
if(track._shimActiveCues){
delete track._shimActiveCues;
}
});
$( [trackList] ).off('.trackview');
trackDisplay.hide(baseData);
elem.off('.trackview');
}
})
;
}
};
if(usesNativeTrack()){
(function(){
var block;
var triggerDisplayUpdate = function(elem){
block = true;
setTimeout(function(){
$(elem).triggerHandler('updatetrackdisplay');
block = false;
}, 9);
};
var createUpdateFn = function(nodeName, prop, type){
var superType = '_sup'+type;
var desc = {prop: {}};
var superDesc;
desc.prop[type] = function(){
if(!block && usesNativeTrack()){
triggerDisplayUpdate($(this).closest('audio, video'));
}
return superDesc.prop[superType].apply(this, arguments);
};
superDesc = webshims.defineNodeNameProperty(nodeName, prop, desc);
};
createUpdateFn('track', 'track', 'get');
['audio', 'video'].forEach(function(nodeName){
createUpdateFn(nodeName, 'textTracks', 'get');
createUpdateFn('nodeName', 'addTextTrack', 'value');
});
})();
$.propHooks.activeCues = {
get: function(obj){
return obj._shimActiveCues || obj.activeCues;
}
};
}
webshims.addReady(function(context, insertedElement){
$('video, audio', context)
.add(insertedElement.filter('video, audio'))
.filter(filterTrackImplementation)
.each(implementTrackUi)
;
});
});