/**
* Simple Caption Plugin for jme
* @version 1.0
*
* http://protofunc.com/jme
* http://github.com/aFarkas/jMediaelement
*
* -------------------
* Uses a modified Version of Silvia Pfeifers srt-parser
* http://www.annodex.net/~silvia/itext/
* -------------------
*
* @description
*
* HTML:
* name
* name
*
* API:
*
* $('video, audio').getTrackContent(index|object, callback)
*
* $('video, audio').enableTrack(index|object)
*
* $('video, audio').disableTrack(index|object)
*
*
* HTML-Display-Area:
*
*
* and
*
*
*
*
* and
*
*
*
* HTML-UI:
* only toggles first track on/off. for more functionality script your own UI. API is powerfull enough
* toggle track
*/
(function($){
//enable tracks
$(document).bind('jmeEmbed', function(e, data){
data = data.data;
var mm = $(e.target),
dir = ( mm.css('direction') === 'rtl' ) ? 'right' : 'left',
activeTracks = $('a.track[data-enabled]', mm)
;
data.trackDisplay = $('').insertAfter(e.target);
data.tadDisplay = $('').insertAfter(e.target);
data.trackDisplays = data.trackDisplay.add(data.tadDisplay);
if( activeTracks[0] ){
mm.enableTrack(activeTracks[0], data);
}
//add fullwindow support
if(data.trackDisplay.videoOverlay && mm.is('video')){
data.trackDisplay
.videoOverlay({
fullscreenClass: 'track-in-fullscreen',
video: mm,
startCSS: {
width: 'auto'
},
position: {
bottom: 0,
left: 0,
right: 0
}
})
;
}
});
/*
* extend the api
*/
var capTypes = {
'text/srt': ['text', 'parseSrt'],
'application/ttaf+xml': ['xml', 'parseDfxp']
};
$.multimediaSupport.fn._extend({
disableTrack: function(object, _data){
object = (isFinite(object)) ? tracks.filter(':eq('+ object +')') : $(object);
if( !_data ){
_data = $.data(this.element, 'mediaElemSupport');
}
object.removeAttr('data-enabled');
$(this.element).addTimeRange(object[0].href, false);
_data.trackDisplays.addClass('inactive-track-display').hide().empty();
this._trigger('trackChange', {track: object, enabled: false});
},
getTrackContent: function(object, fn, _trackData){
object = (isFinite(object)) ? $('a.track', this.element).filter(':eq('+ object +')') : $(object);
_trackData = _trackData || $.data(object[0], 'jmeTrack') || $.data(object[0], 'jmeTrack', {load: false});
if( !_trackData.load ){
_trackData.load = 'loading';
var type = object.attr('type') || 'text/srt';
type = capTypes[type];
if(!type){
setTimeout( function(){
throw("we don't know. captions type: "+ type);
}, 0);
return;
}
$.ajax({
url: object[0].href,
dataType: type[0],
success: function(srt){
_trackData.load = 'loaded';
$[type[1]](
srt,
function(caps){
_trackData.captions = caps;
fn( caps );
},
(object[0].attributes['data-sanitize'] || {}).specified
);
}
});
} else {
fn(trackData.captions);
}
},
enableTrack: function(object, _data){
var tracks = $('a.track', this.element),
that = this,
mm = $(this.element),
trackData,
found
;
if( !_data ){
_data = mm.data('mediaElemSupport');
}
object = (isFinite(object)) ? tracks.filter(':eq('+ object +')') : $(object);
tracks
.filter('[data-enabled]')
.each(function(){
if(this !== object[0]){
that.disableTrack(this, _data);
}
})
;
if( !object[0] ){return;}
trackData = $.data(object[0], 'jmeTrack') || $.data(object[0], 'jmeTrack', {load: false});
trackData.trackDisplay = ( object.is('[data-role=textaudiodesc]') ) ? _data.tadDisplay : _data.trackDisplay;
trackData.trackDisplay.removeClass('inactive-track-display').show();
if( !trackData.load ){
this.getTrackContent(object,
function(){
var captionChange = function (e){
e.target = mm[0];
e = $.extend({}, e, {
target: mm[0],
captions: trackData.captions,
caption: trackData.captions[e.rangeIndex],
type: (e.type === 'rangeenter') ? 'showCaption' : 'hideCaption'
});
if( e.type === 'showCaption' ){
trackData.trackDisplay.html( ''+ e.caption.content +'
' );
} else {
trackData.trackDisplay[0].innerHTML = '';
}
mm.triggerHandler(e.type, e);
};
$.each(trackData.captions, function(i, caption){
mm.addTimeRange(object[0].href, {
enter: caption.start,
leave: caption.end,
callback: captionChange,
activate: true
});
});
},
trackData
);
} else {
mm.addTimeRange(object[0].href, true);
}
object.attr('data-enabled', 'enabled');
this._trigger('trackChange', {track: object, enabled: true, trackData: trackData});
}
}, true);
/*
* extend jme controls
*/
$.fn.jmeControl.addControl('toggle-track', function(control, mm, data, o){
var elems = $.fn.jmeControl.getBtn(control),
tracks = $('a.track', this.element),
changeState = function(){
var enabled = tracks.filter('[data-enabled]');
if( enabled[0] ){
elems.text.text(elems.names[1]);
elems.title.attr('title', elems.titleText[1]);
elems.icon
.addClass('ui-icon-document')
.removeClass('ui-icon-document-b')
;
} else {
elems.text.text(elems.names[0]);
elems.title.attr('title', elems.titleText[0]);
elems.icon
.addClass('ui-icon-document-b')
.removeClass('ui-icon-document')
;
}
}
;
if(o.addThemeRoller){
control.addClass('ui-state-default ui-corner-all');
}
if( !tracks[0] ){
control.addClass(o.classPrefix +'no-track');
}
control
.bind('ariaclick', function(){
var enabled = tracks.filter('[data-enabled]');
if(enabled[0]){
mm.disableTrack(enabled);
} else if( tracks[0] ) {
mm.enableTrack(tracks[0]);
}
return false;
})
;
changeState();
mm.bind('trackChange', changeState);
});
$.backgroundEach = function(arr, processFn, completeFn){
var i = 0,
l = arr.length
;
var process = function(){
var start = new Date().getTime();
for(; i < l; i++){
processFn(i, arr[i], arr);
if(new Date().getTime() - start > 100){
setTimeout(process, 50);
break;
}
}
if( i >= l - 1 ){
completeFn(arr, i, l);
}
};
process();
};
$.parseDfxp = (function(){
var sanitizeReg = /<[a-zA-Z\/][^>]*>/g;
var getTime = function(time){
time = (time || '').split(':');
if(time.length === 3){
time = (parseInt(time[0], 10) * 60 * 60) +
(parseInt(time[1], 10) * 60) +
(parseInt(time[2], 10))
;
return isNaN(time) ? false : time;
}
return false;
},
doc = document,
allowedNodes = {
span: 1,
div: 1,
p: 1,
em: 1,
strong: 1,
br: 1
},
getContent = function(elem){
var childs = elem.childNodes,
div = doc.createElement('div'),
childElem, childContent
;
for(var i = 0, len = childs.length; i < len; i++){
if(childs[i].nodeType === 3){
div.appendChild( doc.createTextNode(childs[i].data) );
} else if(childs[i].nodeType === 1 && allowedNodes[childs[i].nodeName.toLowerCase()]){
childElem = doc.createElement(childs[i].nodeName);
childContent = getContent(childs[i]);
if(childContent){
childElem.innerHTML = childContent;
}
div.appendChild( childElem );
}
}
return div.innerHTML;
}
;
return function(xml, complete, sanitize){
var caps = $('p, div, span', xml).filter('[begin][end]'),
captions = []
;
var e, s, c;
$.backgroundEach(caps, function(i){
s = getTime(caps[i].getAttribute('begin'));
e = getTime(caps[i].getAttribute('end'));
if(s !== false && e !== false){
c = getContent(caps[i]) || '';
captions.push({content: c, start: s, end: e});
}
}, function(){
complete(captions);
});
};
})();
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is HTML5 video itext demonstration code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Silvia Pfeiffer
*
* ***** END LICENSE BLOCK ***** */
// SRT specification from http://forum.doom9.org/archive/index.php/t-73953.html
// but without the formatting, which is just interpreted as text
// Function to parse srt file
var regs = {
sanitize: /<[a-zA-Z\/][^>]*>/g,
dosLines: /\r+/g,
index: /^\d+$/,
time: /(\d+):(\d+):(\d+)(?:,(\d+))?\s*--?>\s*(\d+):(\d+):(\d+)(?:,(\d+))?/
};
$.parseSrt = function(srt, complete, sanitize) {
srt = srt.replace(regs.dosLines, ''); // remove dos newlines
srt = $.trim(srt); // trim white space start and end
if(sanitize){
srt = srt.replace(regs.sanitize, ''); // remove all html tags for security reasons
}
// get captions
var captions = [];
var caplist = srt.split('\n\n');
$.backgroundEach(caplist, function(i){
var caption = "";
var content, start, end, s;
caption = caplist[i];
s = caption.split(/\n/);
if (s[0].match(regs.index) && s[1]) {
// ignore caption number in s[0]
// parse time string
var m = s[1].match(regs.time);
if (m) {
start =
(parseInt(m[1], 10) * 60 * 60) +
(parseInt(m[2], 10) * 60) +
(parseInt(m[3], 10)) +
(parseInt(m[4], 10) / 1000);
end =
(parseInt(m[5], 10) * 60 * 60) +
(parseInt(m[6], 10) * 60) +
(parseInt(m[7], 10)) +
(parseInt(m[8], 10) / 1000);
content = s.slice(2).join("
");
captions.push({start: start, end: end, content: content});
}
}
}, function(){
complete(captions);
});
};
})(jQuery);