webshims-rails 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/lib/webshims-rails/version.rb +2 -2
  2. data/vendor/assets/javascripts/webshims/minified/polyfiller.js +30 -29
  3. data/vendor/assets/javascripts/webshims/minified/shims/combos/1.js +12 -12
  4. data/vendor/assets/javascripts/webshims/minified/shims/combos/10.js +76 -76
  5. data/vendor/assets/javascripts/webshims/minified/shims/combos/11.js +12 -12
  6. data/vendor/assets/javascripts/webshims/minified/shims/combos/12.js +12 -12
  7. data/vendor/assets/javascripts/webshims/minified/shims/combos/13.js +27 -27
  8. data/vendor/assets/javascripts/webshims/minified/shims/combos/16.js +12 -12
  9. data/vendor/assets/javascripts/webshims/minified/shims/combos/17.js +14 -14
  10. data/vendor/assets/javascripts/webshims/minified/shims/combos/18.js +63 -60
  11. data/vendor/assets/javascripts/webshims/minified/shims/combos/19.js +59 -59
  12. data/vendor/assets/javascripts/webshims/minified/shims/combos/20.js +1 -1
  13. data/vendor/assets/javascripts/webshims/minified/shims/combos/22.js +1 -1
  14. data/vendor/assets/javascripts/webshims/minified/shims/combos/24.js +67 -67
  15. data/vendor/assets/javascripts/webshims/minified/shims/combos/25.js +59 -58
  16. data/vendor/assets/javascripts/webshims/minified/shims/combos/26.js +81 -80
  17. data/vendor/assets/javascripts/webshims/minified/shims/combos/27.js +103 -102
  18. data/vendor/assets/javascripts/webshims/minified/shims/combos/6.js +34 -31
  19. data/vendor/assets/javascripts/webshims/minified/shims/combos/7.js +41 -38
  20. data/vendor/assets/javascripts/webshims/minified/shims/combos/8.js +35 -35
  21. data/vendor/assets/javascripts/webshims/minified/shims/combos/9.js +67 -67
  22. data/vendor/assets/javascripts/webshims/minified/shims/dom-extend.js +17 -17
  23. data/vendor/assets/javascripts/webshims/minified/shims/form-number-date-api.js +10 -8
  24. data/vendor/assets/javascripts/webshims/minified/shims/form-number-date-ui.js +24 -23
  25. data/vendor/assets/javascripts/webshims/minified/shims/mediaelement-swf.js +1 -1
  26. data/vendor/assets/javascripts/webshims/minified/shims/styles/shim.css +9 -0
  27. data/vendor/assets/javascripts/webshims/minified/shims/track-ui.js +9 -9
  28. data/vendor/assets/javascripts/webshims/minified/shims/track.js +21 -20
  29. data/vendor/assets/javascripts/webshims/polyfiller.js +144 -140
  30. data/vendor/assets/javascripts/webshims/shims/combos/1.js +10 -6
  31. data/vendor/assets/javascripts/webshims/shims/combos/10.js +11 -7
  32. data/vendor/assets/javascripts/webshims/shims/combos/11.js +10 -6
  33. data/vendor/assets/javascripts/webshims/shims/combos/12.js +10 -6
  34. data/vendor/assets/javascripts/webshims/shims/combos/13.js +10 -6
  35. data/vendor/assets/javascripts/webshims/shims/combos/16.js +10 -6
  36. data/vendor/assets/javascripts/webshims/shims/combos/17.js +10 -6
  37. data/vendor/assets/javascripts/webshims/shims/combos/18.js +986 -924
  38. data/vendor/assets/javascripts/webshims/shims/combos/19.js +10 -6
  39. data/vendor/assets/javascripts/webshims/shims/combos/20.js +1 -1
  40. data/vendor/assets/javascripts/webshims/shims/combos/22.js +1 -1
  41. data/vendor/assets/javascripts/webshims/shims/combos/24.js +10 -6
  42. data/vendor/assets/javascripts/webshims/shims/combos/25.js +820 -768
  43. data/vendor/assets/javascripts/webshims/shims/combos/26.js +820 -768
  44. data/vendor/assets/javascripts/webshims/shims/combos/27.js +821 -769
  45. data/vendor/assets/javascripts/webshims/shims/combos/6.js +986 -924
  46. data/vendor/assets/javascripts/webshims/shims/combos/7.js +986 -924
  47. data/vendor/assets/javascripts/webshims/shims/combos/8.js +10 -6
  48. data/vendor/assets/javascripts/webshims/shims/combos/9.js +11 -7
  49. data/vendor/assets/javascripts/webshims/shims/dom-extend.js +10 -6
  50. data/vendor/assets/javascripts/webshims/shims/form-number-date-api.js +77 -77
  51. data/vendor/assets/javascripts/webshims/shims/form-number-date-ui.js +909 -847
  52. data/vendor/assets/javascripts/webshims/shims/mediaelement-swf.js +1 -1
  53. data/vendor/assets/javascripts/webshims/shims/styles/shim.css +9 -0
  54. data/vendor/assets/javascripts/webshims/shims/track-ui.js +300 -291
  55. data/vendor/assets/javascripts/webshims/shims/track.js +810 -762
  56. metadata +10 -5
@@ -1,763 +1,811 @@
1
- jQuery.webshims.register('track', function($, webshims, window, document, undefined){
2
- var mediaelement = webshims.mediaelement;
3
- var id = new Date().getTime();
4
- var showTracks = {subtitles: 1, captions: 1};
5
- var notImplemented = function(){
6
- webshims.error('not implemented yet');
7
- };
8
-
9
- var createEventTarget = function(obj){
10
- var eventList = {};
11
- obj.addEventListener = function(name, fn){
12
- if(eventList[name]){
13
- webshims.error('always use $.bind to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn);
14
- }
15
- eventList[name] = fn;
16
-
17
- };
18
- obj.removeEventListener = function(name, fn){
19
- if(eventList[name] && eventList[name] != fn){
20
- webshims.error('always use $.bind/$.unbind to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn);
21
- }
22
- if(eventList[name]){
23
- delete eventList[name];
24
- }
25
- };
26
- return obj;
27
- };
28
-
29
-
30
- var cueListProto = {
31
- getCueById: function(id){
32
- var cue = null;
33
- for(var i = 0, len = this.length; i < len; i++){
34
- if(this[i].id === id){
35
- cue = this[i];
36
- break;
37
- }
38
- }
39
- return cue;
40
- }
41
- };
42
- var textTrackProto = {
43
- shimActiveCues: null,
44
- _shimActiveCues: null,
45
- activeCues: null,
46
- cues: null,
47
- kind: 'subtitles',
48
- label: '',
49
- language: '',
50
- mode: 'disabled',
51
- readyState: 0,
52
- oncuechange: null,
53
- toString: function() {
54
- return "[object TextTrack]";
55
- },
56
- addCue: function(cue){
57
- if(!this.cues){
58
- this.cues = mediaelement.createCueList();
59
- } else {
60
- var lastCue = this.cues[this.cues.length-1];
61
- if(lastCue && lastCue.startTime > cue.startTime){
62
- webshims.error("cue startTime higher than previous cue's startTime");
63
- }
64
- }
65
- if(cue.track){
66
- webshims.error("cue already part of a track element");
67
- }
68
- cue.track = this;
69
- this.cues.push(cue);
70
- },
71
- removeCue: notImplemented,
72
- DISABLED: 'disabled',
73
- OFF: 'disabled',
74
- HIDDEN: 'hidden',
75
- SHOWING: 'showing',
76
- ERROR: 3,
77
- LOADED: 2,
78
- LOADING: 1,
79
- NONE: 0
80
- };
81
- var copyProps = ['kind', 'label', 'srclang'];
82
-
83
- var owns = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
84
-
85
- //ToDo: add/remove event
86
- var updateMediaTrackList = function(baseData, trackList){
87
- var removed = [];
88
- var added = [];
89
- var newTracks = [];
90
- var i, len;
91
- if(!baseData){
92
- baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {});
93
- }
94
-
95
- if(!trackList){
96
- baseData.blockTrackListUpdate = true;
97
- trackList = $.prop(this, 'textTracks');
98
- baseData.blockTrackListUpdate = false;
99
- }
100
-
101
- clearTimeout(baseData.updateTrackListTimer);
102
-
103
- $('track', this).each(function(){
104
- var track = $.prop(this, 'track');
105
- newTracks.push(track);
106
- if(trackList.indexOf(track) == -1){
107
- added.push(track);
108
- }
109
- });
110
-
111
- if(baseData.scriptedTextTracks){
112
- for(i = 0, len = baseData.scriptedTextTracks.length; i < len; i++){
113
- newTracks.push(baseData.scriptedTextTracks[i]);
114
- if(trackList.indexOf(baseData.scriptedTextTracks[i]) == -1){
115
- added.push(baseData.scriptedTextTracks[i]);
116
- }
117
- }
118
- }
119
-
120
- for(i = 0, len = trackList.length; i < len; i++){
121
- if(newTracks.indexOf(trackList[i]) == -1){
122
- removed.push(trackList[i]);
123
- }
124
- }
125
-
126
- if(removed.length || added.length){
127
- trackList.splice(0);
128
-
129
- for(i = 0, len = newTracks.length; i < len; i++){
130
- trackList.push(newTracks[i]);
131
- }
132
- for(i = 0, len = removed.length; i < len; i++){
133
- $([trackList]).triggerHandler($.Event({type: 'removetrack', track: trackList, track: removed[i]}));
134
- }
135
- for(i = 0, len = added.length; i < len; i++){
136
- $([trackList]).triggerHandler($.Event({type: 'addtrack', track: trackList, track: added[i]}));
137
- }
138
- if(baseData.scriptedTextTracks || removed.length){
139
- $(this).triggerHandler('updatetrackdisplay');
140
- }
141
- }
142
- };
143
-
144
- var refreshTrack = function(track, trackData){
145
- var mode, kind;
146
- if(!trackData){
147
- trackData = webshims.data(track, 'trackData');
148
- }
149
- if(trackData && !trackData.isTriggering){
150
- trackData.isTriggering = true;
151
- mode = (trackData.track || {}).mode;
152
- kind = (trackData.track || {}).kind;
153
- setTimeout(function(){
154
- if(mode !== (trackData.track || {}).mode || kind != (trackData.track || {}).kind){
155
- if(!(trackData.track || {}).readyState){
156
- $(track).triggerHandler('checktrackmode');
157
- } else {
158
- $(track).parent().triggerHandler('updatetrackdisplay');
159
- }
160
- }
161
- trackData.isTriggering = false;
162
-
163
- }, 9);
164
- }
165
- };
166
-
167
- var emptyDiv = $('<div />')[0];
168
- window.TextTrackCue = function(startTime, endTime, text){
169
- if(arguments.length != 3){
170
- webshims.error("wrong arguments.length for TextTrackCue.constructor");
171
- }
172
-
173
- this.startTime = startTime;
174
- this.endTime = endTime;
175
- this.text = text;
176
-
177
- this.id = "";
178
- this.pauseOnExit = false;
179
-
180
- createEventTarget(this);
181
- };
182
-
183
- window.TextTrackCue.prototype = {
184
-
185
- onenter: null,
186
- onexit: null,
187
- pauseOnExit: false,
188
- getCueAsHTML: function(){
189
- var lastText = "";
190
- var parsedText = "";
191
- var fragment = document.createDocumentFragment();
192
- var fn;
193
- if(!owns(this, 'getCueAsHTML')){
194
- fn = this.getCueAsHTML = function(){
195
- var i, len;
196
- if(lastText != this.text){
197
- lastText = this.text;
198
- parsedText = mediaelement.parseCueTextToHTML(lastText);
199
- emptyDiv.innerHTML = parsedText;
200
-
201
- for(i = 0, len = emptyDiv.childNodes.length; i < len; i++){
202
- fragment.appendChild(emptyDiv.childNodes[i].cloneNode(true));
203
- }
204
- }
205
- return fragment.cloneNode(true);
206
- };
207
-
208
- }
209
- return fn ? fn.apply(this, arguments) : fragment.cloneNode(true);
210
- },
211
- track: null,
212
-
213
-
214
- id: ''
215
- //todo-->
216
- // ,
217
- // snapToLines: true,
218
- // line: 'auto',
219
- // size: 100,
220
- // position: 50,
221
- // vertical: '',
222
- // align: 'middle'
223
- };
224
-
225
-
226
-
227
-
228
-
229
- mediaelement.createCueList = function(){
230
- return $.extend([], cueListProto);
231
- };
232
-
233
- mediaelement.parseCueTextToHTML = (function(){
234
- var tagSplits = /(<\/?[^>]+>)/ig;
235
- var allowedTags = /^(?:c|v|ruby|rt|b|i|u)/;
236
- var regEnd = /\<\s*\//;
237
- var addToTemplate = function(localName, attribute, tag, html){
238
- var ret;
239
- if(regEnd.test(html)){
240
- ret = '</'+ localName +'>';
241
- } else {
242
- tag.splice(0, 1);
243
- ret = '<'+ localName +' '+ attribute +'="'+ (tag.join(' ').replace(/\"/g, '&#34;')) +'">';
244
- }
245
- return ret;
246
- };
247
- var replacer = function(html){
248
- var tag = html.replace(/[<\/>]+/ig,"").split(/[\s\.]+/);
249
- if(tag[0]){
250
- tag[0] = tag[0].toLowerCase();
251
- if(allowedTags.test(tag[0])){
252
- if(tag[0] == 'c'){
253
- html = addToTemplate('span', 'class', tag, html);
254
- } else if(tag[0] == 'v'){
255
- html = addToTemplate('q', 'title', tag, html);
256
- }
257
- } else {
258
- html = "";
259
- }
260
- }
261
- return html;
262
- };
263
-
264
- return function(cueText){
265
- return cueText.replace(tagSplits, replacer);
266
- };
267
- })();
268
-
269
- mediaelement.loadTextTrack = function(mediaelem, track, trackData, _default){
270
- var loadEvents = 'play playing timeupdate updatetrackdisplay';
271
- var obj = trackData.track;
272
- var load = function(){
273
- var src = $.prop(track, 'src');
274
- var error;
275
- var ajax;
276
- if(obj.mode != 'disabled' && src && $.attr(track, 'src')){
277
- $(mediaelem).unbind(loadEvents, load);
278
- $(track).unbind('checktrackmode', load);
279
- if(!obj.readyState){
280
- error = function(){
281
- obj.readyState = 3;
282
- obj.cues = null;
283
- obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = null;
284
- $(track).triggerHandler('error');
285
- };
286
- obj.readyState = 1;
287
- try {
288
- obj.cues = mediaelement.createCueList();
289
- obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = mediaelement.createCueList();
290
- ajax = $.ajax({
291
- dataType: 'text',
292
- url: src,
293
- success: function(text){
294
- if(ajax.getResponseHeader('content-type') != 'text/vtt'){
295
- webshims.error('set the mime-type of your WebVTT files to text/vtt. see: http://dev.w3.org/html5/webvtt/#text/vtt');
296
- }
297
- mediaelement.parseCaptions(text, obj, function(cues){
298
- if(cues && 'length' in cues){
299
- obj.readyState = 2;
300
- $(track).triggerHandler('load');
301
- $(mediaelem).triggerHandler('updatetrackdisplay');
302
- } else {
303
- error();
304
- }
305
- });
306
-
307
- },
308
- error: error
309
- });
310
- } catch(er){
311
- error();
312
- webshims.warn(er);
313
- }
314
- }
315
- }
316
- };
317
- obj.readyState = 0;
318
- obj.shimActiveCues = null;
319
- obj._shimActiveCues = null;
320
- obj.activeCues = null;
321
- obj.cues = null;
322
- $(mediaelem).unbind(loadEvents, load);
323
- $(track).unbind('checktrackmode', load);
324
- $(mediaelem).bind(loadEvents, load);
325
- $(track).bind('checktrackmode', load);
326
- if(_default){
327
- obj.mode = showTracks[obj.kind] ? 'showing' : 'hidden';
328
- load();
329
- }
330
- };
331
-
332
- mediaelement.createTextTrack = function(mediaelem, track){
333
- var obj, trackData;
334
- if(track.nodeName){
335
- trackData = webshims.data(track, 'trackData');
336
-
337
- if(trackData){
338
- refreshTrack(track, trackData);
339
- obj = trackData.track;
340
- }
341
- }
342
-
343
- if(!obj){
344
- obj = createEventTarget(webshims.objectCreate(textTrackProto));
345
- copyProps.forEach(function(copyProp){
346
- var prop = $.prop(track, copyProp);
347
- if(prop){
348
- if(copyProp == 'srclang'){
349
- copyProp = 'language';
350
- }
351
- obj[copyProp] = prop;
352
- }
353
- });
354
-
355
-
356
- if(track.nodeName){
357
- trackData = webshims.data(track, 'trackData', {track: obj});
358
- mediaelement.loadTextTrack(mediaelem, track, trackData, $.prop(track, 'default'));
359
- } else {
360
- obj.cues = mediaelement.createCueList();
361
- obj.activeCues = obj._shimActiveCues = obj.shimActiveCues = mediaelement.createCueList();
362
- obj.mode = 'hidden';
363
- obj.readyState = 2;
364
- }
365
- }
366
- return obj;
367
- };
368
-
369
-
370
- /*
371
- taken from:
372
- Captionator 0.5.1 [CaptionCrunch]
373
- Christopher Giffard, 2011
374
- Share and enjoy
375
-
376
- https://github.com/cgiffard/Captionator
377
-
378
- modified for webshims
379
- */
380
- mediaelement.parseCaptionChunk = (function(){
381
- // Set up timestamp parsers
382
- var WebVTTTimestampParser = /^(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s+\-\-\>\s+(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s*(.*)/;
383
- var GoogleTimestampParser = /^([\d\.]+)\s+\+([\d\.]+)\s*(.*)/;
384
- var WebVTTDEFAULTSCueParser = /^(DEFAULTS|DEFAULT)\s+\-\-\>\s+(.*)/g;
385
- var WebVTTSTYLECueParser = /^(STYLE|STYLES)\s+\-\-\>\s*\n([\s\S]*)/g;
386
- var WebVTTCOMMENTCueParser = /^(COMMENT|COMMENTS)\s+\-\-\>\s+(.*)/g;
387
-
388
- return function(subtitleElement,objectCount){
389
- var cueDefaults = [];
390
-
391
- var subtitleParts, timeIn, timeOut, html, timeData, subtitlePartIndex, cueSettings = "", id, specialCueData;
392
- var timestampMatch, tmpCue;
393
-
394
- // WebVTT Special Cue Logic
395
- if ((specialCueData = WebVTTDEFAULTSCueParser.exec(subtitleElement))) {
396
- // cueDefaults = specialCueData.slice(2).join("");
397
- // cueDefaults = cueDefaults.split(/\s+/g).filter(function(def) { return def && !!def.length; });
398
- return null;
399
- } else if ((specialCueData = WebVTTSTYLECueParser.exec(subtitleElement))) {
400
- return null;
401
- } else if ((specialCueData = WebVTTCOMMENTCueParser.exec(subtitleElement))) {
402
- return null; // At this stage, we don't want to do anything with these.
403
- }
404
-
405
- subtitleParts = subtitleElement.split(/\n/g);
406
-
407
- // Trim off any blank lines (logically, should only be max. one, but loop to be sure)
408
- while (!subtitleParts[0].replace(/\s+/ig,"").length && subtitleParts.length > 0) {
409
- subtitleParts.shift();
410
- }
411
-
412
- if (subtitleParts[0].match(/^\s*[a-z0-9]+\s*$/ig)) {
413
- // The identifier becomes the cue ID (when *we* load the cues from file. Programatically created cues can have an ID of whatever.)
414
- id = String(subtitleParts.shift().replace(/\s*/ig,""));
415
- }
416
-
417
- for (subtitlePartIndex = 0; subtitlePartIndex < subtitleParts.length; subtitlePartIndex ++) {
418
- var timestamp = subtitleParts[subtitlePartIndex];
419
-
420
- if ((timestampMatch = WebVTTTimestampParser.exec(timestamp))) {
421
-
422
- // WebVTT
423
-
424
- timeData = timestampMatch.slice(1);
425
-
426
- timeIn = parseInt((timeData[0]||0) * 60 * 60,10) + // Hours
427
- parseInt((timeData[1]||0) * 60,10) + // Minutes
428
- parseInt((timeData[2]||0),10) + // Seconds
429
- parseFloat("0." + (timeData[3]||0)); // MS
430
-
431
- timeOut = parseInt((timeData[4]||0) * 60 * 60,10) + // Hours
432
- parseInt((timeData[5]||0) * 60,10) + // Minutes
433
- parseInt((timeData[6]||0),10) + // Seconds
434
- parseFloat("0." + (timeData[7]||0)); // MS
435
- /*
436
- if (timeData[8]) {
437
- cueSettings = timeData[8];
438
- }
439
- */
440
- }
441
-
442
- // We've got the timestamp - return all the other unmatched lines as the raw subtitle data
443
- subtitleParts = subtitleParts.slice(0,subtitlePartIndex).concat(subtitleParts.slice(subtitlePartIndex+1));
444
- break;
445
- }
446
-
447
- if (!timeIn && !timeOut) {
448
- // We didn't extract any time information. Assume the cue is invalid!
449
- return null;
450
- }
451
- /*
452
- // Consolidate cue settings, convert defaults to object
453
- var compositeCueSettings =
454
- cueDefaults
455
- .reduce(function(previous,current,index,array){
456
- previous[current.split(":")[0]] = current.split(":")[1];
457
- return previous;
458
- },{});
459
-
460
- // Loop through cue settings, replace defaults with cue specific settings if they exist
461
- compositeCueSettings =
462
- cueSettings
463
- .split(/\s+/g)
464
- .filter(function(set) { return set && !!set.length; })
465
- // Convert array to a key/val object
466
- .reduce(function(previous,current,index,array){
467
- previous[current.split(":")[0]] = current.split(":")[1];
468
- return previous;
469
- },compositeCueSettings);
470
-
471
- // Turn back into string like the TextTrackCue constructor expects
472
- cueSettings = "";
473
- for (var key in compositeCueSettings) {
474
- if (compositeCueSettings.hasOwnProperty(key)) {
475
- cueSettings += !!cueSettings.length ? " " : "";
476
- cueSettings += key + ":" + compositeCueSettings[key];
477
- }
478
- }
479
- */
480
- // The remaining lines are the subtitle payload itself (after removing an ID if present, and the time);
481
- html = subtitleParts.join("\n");
482
- tmpCue = new TextTrackCue(timeIn, timeOut, html);
483
- if(id){
484
- tmpCue.id = id;
485
- }
486
- return tmpCue;
487
- };
488
- })();
489
-
490
- mediaelement.parseCaptions = function(captionData, track, complete) {
491
- var subtitles = mediaelement.createCueList();
492
- var cue, lazyProcess, regWevVTT;
493
- var startDate;
494
- var isWEBVTT;
495
- if (captionData) {
496
-
497
- regWevVTT = /^WEBVTT(\s*FILE)?/ig;
498
-
499
- lazyProcess = function(i, len){
500
-
501
- for(; i < len; i++){
502
- cue = captionData[i];
503
- if(regWevVTT.test(cue)){
504
- isWEBVTT = true;
505
- } else if(cue.replace(/\s*/ig,"").length){
506
- if(!isWEBVTT){
507
- webshims.error('please use WebVTT format. This is the standard');
508
- complete(null);
509
- break;
510
- }
511
- cue = mediaelement.parseCaptionChunk(cue, i);
512
- if(cue){
513
- track.addCue(cue);
514
- }
515
- }
516
- if(startDate < (new Date().getTime()) - 9){
517
- i++;
518
- setTimeout(function(){
519
- startDate = new Date().getTime();
520
- lazyProcess(i, len);
521
- }, 90);
522
-
523
- break;
524
- }
525
- }
526
- if(i >= len){
527
- if(!isWEBVTT){
528
- webshims.error('please use WebVTT format. This is the standard');
529
- }
530
- complete(track.cues);
531
- }
532
- };
533
-
534
- captionData = captionData.replace(/\r\n/g,"\n");
535
-
536
- setTimeout(function(){
537
- captionData = captionData.replace(/\r/g,"\n");
538
- setTimeout(function(){
539
- startDate = new Date().getTime();
540
- captionData = captionData.split(/\n\n+/g);
541
- lazyProcess(0, captionData.length);
542
- }, 9);
543
- }, 9);
544
-
545
- } else {
546
- webshims.error("Required parameter captionData not supplied.");
547
- }
548
- };
549
-
550
-
551
- mediaelement.createTrackList = function(mediaelem, baseData){
552
- baseData = baseData || webshims.data(mediaelem, 'mediaelementBase') || webshims.data(mediaelem, 'mediaelementBase', {});
553
- if(!baseData.textTracks){
554
- baseData.textTracks = [];
555
- webshims.defineProperties(baseData.textTracks, {
556
- onaddtrack: {value: null},
557
- onremovetrack: {value: null}
558
- });
559
- createEventTarget(baseData.textTracks);
560
- }
561
- return baseData.textTracks;
562
- };
563
-
564
- if(!Modernizr.track){
565
- webshims.defineNodeNamesBooleanProperty(['track'], 'default');
566
- webshims.reflectProperties(['track'], ['srclang', 'label']);
567
-
568
- webshims.defineNodeNameProperties('track', {
569
- src: {
570
- //attr: {},
571
- reflect: true,
572
- propType: 'src'
573
- }
574
- });
575
- }
576
-
577
- webshims.defineNodeNameProperties('track', {
578
- kind: {
579
- attr: Modernizr.track ? {
580
- set: function(value){
581
- var trackData = webshims.data(this, 'trackData');
582
- this.setAttribute('data-kind', value);
583
- if(trackData){
584
- trackData.attrKind = value;
585
- }
586
- },
587
- get: function(){
588
- var trackData = webshims.data(this, 'trackData');
589
- if(trackData && ('attrKind' in trackData)){
590
- return trackData.attrKind;
591
- }
592
- return this.getAttribute('kind');
593
- }
594
- } : {},
595
- reflect: true,
596
- propType: 'enumarated',
597
- defaultValue: 'subtitles',
598
- limitedTo: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata']
599
- }
600
- });
601
-
602
- webshims.onNodeNamesPropertyModify('track', 'kind', function(){
603
- var trackData = webshims.data(this, 'trackData');
604
- if(trackData){
605
- trackData.track.kind = $.prop(this, 'kind');
606
- refreshTrack(this, trackData);
607
- }
608
- });
609
-
610
- webshims.onNodeNamesPropertyModify('track', 'src', function(val){
611
- if(val){
612
- var data = webshims.data(this, 'trackData');
613
- var media;
614
- if(data){
615
- media = $(this).closest('video, audio');
616
- if(media[0]){
617
- mediaelement.loadTextTrack(media, this, data);
618
- }
619
- }
620
- }
621
-
622
- });
623
-
624
- //
625
-
626
- webshims.defineNodeNamesProperties(['track'], {
627
- ERROR: {
628
- value: 3
629
- },
630
- LOADED: {
631
- value: 2
632
- },
633
- LOADING: {
634
- value: 1
635
- },
636
- NONE: {
637
- value: 0
638
- },
639
- readyState: {
640
- get: function(){
641
- return ($.prop(this, 'track') || {readyState: 0}).readyState;
642
- },
643
- writeable: false
644
- },
645
- track: {
646
- get: function(){
647
- return mediaelement.createTextTrack($(this).closest('audio, video')[0], this);
648
- },
649
- writeable: false
650
- }
651
- }, 'prop');
652
-
653
- webshims.defineNodeNamesProperties(['audio', 'video'], {
654
- textTracks: {
655
- get: function(){
656
-
657
- var media = this;
658
- var baseData = webshims.data(media, 'mediaelementBase') || webshims.data(media, 'mediaelementBase', {});
659
- var tracks = mediaelement.createTrackList(media, baseData);
660
- if(!baseData.blockTrackListUpdate){
661
- updateMediaTrackList.call(media, baseData, tracks);
662
- }
663
- return tracks;
664
- },
665
- writeable: false
666
- },
667
- addTextTrack: {
668
- value: function(kind, label, lang){
669
- var textTrack = mediaelement.createTextTrack(this, {
670
- kind: kind || '',
671
- label: label || '',
672
- srclang: lang || ''
673
- });
674
- var baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {});
675
- if (!baseData.scriptedTextTracks) {
676
- baseData.scriptedTextTracks = [];
677
- }
678
- baseData.scriptedTextTracks.push(textTrack);
679
- updateMediaTrackList.call(this);
680
- return textTrack;
681
- }
682
- }
683
- }, 'prop');
684
-
685
-
686
- $(document).bind('emptied ended updatetracklist', function(e){
687
- if($(e.target).is('audio, video')){
688
- var baseData = webshims.data(e.target, 'mediaelementBase');
689
- if(baseData){
690
- clearTimeout(baseData.updateTrackListTimer);
691
- baseData.updateTrackListTimer = setTimeout(function(){
692
- updateMediaTrackList.call(e.target, baseData);
693
- }, 0);
694
- }
695
- }
696
- });
697
-
698
- var getNativeReadyState = function(trackElem, textTrack){
699
- return textTrack.readyState || trackElem.readyState;
700
- };
701
-
702
- webshims.addReady(function(context, insertedElement){
703
- var insertedMedia = insertedElement.filter('video, audio, track').closest('audio, video');
704
- $('video, audio', context)
705
- .add(insertedMedia)
706
- .each(function(){
707
- updateMediaTrackList.call(this);
708
- })
709
- .each(function(){
710
- if(Modernizr.track){
711
- var shimedTextTracks = $.prop(this, 'textTracks');
712
- var origTextTracks = this.textTracks;
713
- if(shimedTextTracks.length != origTextTracks.length){
714
- webshims.error("textTracks couldn't be copied");
715
- }
716
-
717
- $('track', this)
718
- .each(function(){
719
- var shimedTrack = $.prop(this, 'track');
720
- var origTrack = this.track;
721
- var kind;
722
- var readyState;
723
- if(origTrack){
724
- kind = $.prop(this, 'kind');
725
- readyState = getNativeReadyState(this, origTrack);
726
- if (origTrack.mode || readyState) {
727
- shimedTrack.mode = origTrack.mode;
728
- }
729
- //disable track from showing + remove UI
730
- if(kind != 'descriptions'){
731
- origTrack.mode = (typeof origTrack.mode == 'string') ? 'disabled' : 0;
732
- this.kind = 'metadata';
733
- $(this).attr({kind: kind});
734
- }
735
-
736
- }
737
- })
738
- .bind('load error', function(e){
739
- if(e.originalEvent){
740
- e.stopImmediatePropagation();
741
- }
742
- })
743
- ;
744
- }
745
- })
746
- ;
747
- insertedMedia.each(function(){
748
- var media = this;
749
- var baseData = webshims.data(media, 'mediaelementBase');
750
- if(baseData){
751
- clearTimeout(baseData.updateTrackListTimer);
752
- baseData.updateTrackListTimer = setTimeout(function(){
753
- updateMediaTrackList.call(media, baseData);
754
- }, 9);
755
- }
756
- });
757
- });
758
-
759
- if(Modernizr.track){
760
- $('video, audio').trigger('trackapichange');
761
- }
762
-
1
+ jQuery.webshims.register('track', function($, webshims, window, document, undefined){
2
+ var mediaelement = webshims.mediaelement;
3
+ var id = new Date().getTime();
4
+ //descriptions are not really shown, but they are inserted into the dom
5
+ var showTracks = {subtitles: 1, captions: 1, descriptions: 1};
6
+ var notImplemented = function(){
7
+ webshims.error('not implemented yet');
8
+ };
9
+ var supportTrackMod = Modernizr.ES5 && Modernizr.objectAccessor;
10
+ var createEventTarget = function(obj){
11
+ var eventList = {};
12
+ obj.addEventListener = function(name, fn){
13
+ if(eventList[name]){
14
+ webshims.error('always use $.bind to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn);
15
+ }
16
+ eventList[name] = fn;
17
+
18
+ };
19
+ obj.removeEventListener = function(name, fn){
20
+ if(eventList[name] && eventList[name] != fn){
21
+ webshims.error('always use $.bind/$.unbind to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn);
22
+ }
23
+ if(eventList[name]){
24
+ delete eventList[name];
25
+ }
26
+ };
27
+ return obj;
28
+ };
29
+
30
+
31
+ var cueListProto = {
32
+ getCueById: function(id){
33
+ var cue = null;
34
+ for(var i = 0, len = this.length; i < len; i++){
35
+ if(this[i].id === id){
36
+ cue = this[i];
37
+ break;
38
+ }
39
+ }
40
+ return cue;
41
+ }
42
+ };
43
+
44
+ var textTrackProto = {
45
+ shimActiveCues: null,
46
+ _shimActiveCues: null,
47
+ activeCues: null,
48
+ cues: null,
49
+ kind: 'subtitles',
50
+ label: '',
51
+ language: '',
52
+ mode: 'disabled',
53
+ readyState: 0,
54
+ oncuechange: null,
55
+ toString: function() {
56
+ return "[object TextTrack]";
57
+ },
58
+ addCue: function(cue){
59
+ if(!this.cues){
60
+ this.cues = mediaelement.createCueList();
61
+ } else {
62
+ var lastCue = this.cues[this.cues.length-1];
63
+ if(lastCue && lastCue.startTime > cue.startTime){
64
+ webshims.error("cue startTime higher than previous cue's startTime");
65
+ }
66
+ }
67
+ if(cue.track && cue.track.removeCue){
68
+ cue.track.removeCue(cue);
69
+ }
70
+ cue.track = this;
71
+ this.cues.push(cue);
72
+ },
73
+ //ToDo: make it more dynamic
74
+ removeCue: function(cue){
75
+ var cues = this.cues || [];
76
+ var i = 0;
77
+ var len = cues.length;
78
+ if(cue.track != this){
79
+ webshims.error("cue not part of track");
80
+ return;
81
+ }
82
+ for(; i < len; i++){
83
+ if(cues[i] === cue){
84
+ cues.splice(i, 1);
85
+ cue.track = null;
86
+ break;
87
+ }
88
+ }
89
+ if(cue.track){
90
+ webshims.error("cue not part of track");
91
+ return;
92
+ }
93
+ },
94
+ DISABLED: 'disabled',
95
+ OFF: 'disabled',
96
+ HIDDEN: 'hidden',
97
+ SHOWING: 'showing',
98
+ ERROR: 3,
99
+ LOADED: 2,
100
+ LOADING: 1,
101
+ NONE: 0
102
+ };
103
+ var copyProps = ['kind', 'label', 'srclang'];
104
+ var copyName = {srclang: 'language'};
105
+
106
+ var owns = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
107
+
108
+ var updateMediaTrackList = function(baseData, trackList){
109
+ var removed = [];
110
+ var added = [];
111
+ var newTracks = [];
112
+ var i, len;
113
+ if(!baseData){
114
+ baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {});
115
+ }
116
+
117
+ if(!trackList){
118
+ baseData.blockTrackListUpdate = true;
119
+ trackList = $.prop(this, 'textTracks');
120
+ baseData.blockTrackListUpdate = false;
121
+ }
122
+
123
+ clearTimeout(baseData.updateTrackListTimer);
124
+
125
+ $('track', this).each(function(){
126
+ var track = $.prop(this, 'track');
127
+ newTracks.push(track);
128
+ if(trackList.indexOf(track) == -1){
129
+ added.push(track);
130
+ }
131
+ });
132
+
133
+ if(baseData.scriptedTextTracks){
134
+ for(i = 0, len = baseData.scriptedTextTracks.length; i < len; i++){
135
+ newTracks.push(baseData.scriptedTextTracks[i]);
136
+ if(trackList.indexOf(baseData.scriptedTextTracks[i]) == -1){
137
+ added.push(baseData.scriptedTextTracks[i]);
138
+ }
139
+ }
140
+ }
141
+
142
+ for(i = 0, len = trackList.length; i < len; i++){
143
+ if(newTracks.indexOf(trackList[i]) == -1){
144
+ removed.push(trackList[i]);
145
+ }
146
+ }
147
+
148
+ if(removed.length || added.length){
149
+ trackList.splice(0);
150
+
151
+ for(i = 0, len = newTracks.length; i < len; i++){
152
+ trackList.push(newTracks[i]);
153
+ }
154
+ for(i = 0, len = removed.length; i < len; i++){
155
+ $([trackList]).triggerHandler($.Event({type: 'removetrack', track: trackList, track: removed[i]}));
156
+ }
157
+ for(i = 0, len = added.length; i < len; i++){
158
+ $([trackList]).triggerHandler($.Event({type: 'addtrack', track: trackList, track: added[i]}));
159
+ }
160
+ if(baseData.scriptedTextTracks || removed.length){
161
+ $(this).triggerHandler('updatetrackdisplay');
162
+ }
163
+ }
164
+ };
165
+
166
+ var refreshTrack = function(track, trackData){
167
+ if(!trackData){
168
+ trackData = webshims.data(track, 'trackData');
169
+ }
170
+ if(trackData && !trackData.isTriggering){
171
+ trackData.isTriggering = true;
172
+ setTimeout(function(){
173
+ if(!(trackData.track || {}).readyState){
174
+ $(track).triggerHandler('checktrackmode');
175
+ } else {
176
+ $(track).closest('audio, video').triggerHandler('updatetrackdisplay');
177
+ }
178
+ trackData.isTriggering = false;
179
+ }, 1);
180
+ }
181
+ };
182
+
183
+ var emptyDiv = $('<div />')[0];
184
+ window.TextTrackCue = function(startTime, endTime, text){
185
+ if(arguments.length != 3){
186
+ webshims.error("wrong arguments.length for TextTrackCue.constructor");
187
+ }
188
+
189
+ this.startTime = startTime;
190
+ this.endTime = endTime;
191
+ this.text = text;
192
+
193
+ this.id = "";
194
+ this.pauseOnExit = false;
195
+
196
+ createEventTarget(this);
197
+ };
198
+
199
+ window.TextTrackCue.prototype = {
200
+
201
+ onenter: null,
202
+ onexit: null,
203
+ pauseOnExit: false,
204
+ getCueAsHTML: function(){
205
+ var lastText = "";
206
+ var parsedText = "";
207
+ var fragment = document.createDocumentFragment();
208
+ var fn;
209
+ if(!owns(this, 'getCueAsHTML')){
210
+ fn = this.getCueAsHTML = function(){
211
+ var i, len;
212
+ if(lastText != this.text){
213
+ lastText = this.text;
214
+ parsedText = mediaelement.parseCueTextToHTML(lastText);
215
+ emptyDiv.innerHTML = parsedText;
216
+
217
+ for(i = 0, len = emptyDiv.childNodes.length; i < len; i++){
218
+ fragment.appendChild(emptyDiv.childNodes[i].cloneNode(true));
219
+ }
220
+ }
221
+ return fragment.cloneNode(true);
222
+ };
223
+
224
+ }
225
+ return fn ? fn.apply(this, arguments) : fragment.cloneNode(true);
226
+ },
227
+ track: null,
228
+
229
+
230
+ id: ''
231
+ //todo-->
232
+ // ,
233
+ // snapToLines: true,
234
+ // line: 'auto',
235
+ // size: 100,
236
+ // position: 50,
237
+ // vertical: '',
238
+ // align: 'middle'
239
+ };
240
+
241
+
242
+
243
+
244
+
245
+ mediaelement.createCueList = function(){
246
+ return $.extend([], cueListProto);
247
+ };
248
+
249
+ mediaelement.parseCueTextToHTML = (function(){
250
+ var tagSplits = /(<\/?[^>]+>)/ig;
251
+ var allowedTags = /^(?:c|v|ruby|rt|b|i|u)/;
252
+ var regEnd = /\<\s*\//;
253
+ var addToTemplate = function(localName, attribute, tag, html){
254
+ var ret;
255
+ if(regEnd.test(html)){
256
+ ret = '</'+ localName +'>';
257
+ } else {
258
+ tag.splice(0, 1);
259
+ ret = '<'+ localName +' '+ attribute +'="'+ (tag.join(' ').replace(/\"/g, '&#34;')) +'">';
260
+ }
261
+ return ret;
262
+ };
263
+ var replacer = function(html){
264
+ var tag = html.replace(/[<\/>]+/ig,"").split(/[\s\.]+/);
265
+ if(tag[0]){
266
+ tag[0] = tag[0].toLowerCase();
267
+ if(allowedTags.test(tag[0])){
268
+ if(tag[0] == 'c'){
269
+ html = addToTemplate('span', 'class', tag, html);
270
+ } else if(tag[0] == 'v'){
271
+ html = addToTemplate('q', 'title', tag, html);
272
+ }
273
+ } else {
274
+ html = "";
275
+ }
276
+ }
277
+ return html;
278
+ };
279
+
280
+ return function(cueText){
281
+ return cueText.replace(tagSplits, replacer);
282
+ };
283
+ })();
284
+
285
+ mediaelement.loadTextTrack = function(mediaelem, track, trackData, _default){
286
+ var loadEvents = 'play playing timeupdate updatetrackdisplay';
287
+ var obj = trackData.track;
288
+ var load = function(){
289
+ var src = $.prop(track, 'src');
290
+ var error;
291
+ var ajax;
292
+ if(obj.mode != 'disabled' && src && $.attr(track, 'src')){
293
+ $(mediaelem).unbind(loadEvents, load);
294
+ $(track).unbind('checktrackmode', load);
295
+ if(!obj.readyState){
296
+ error = function(){
297
+ obj.readyState = 3;
298
+ obj.cues = null;
299
+ obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = null;
300
+ $(track).triggerHandler('error');
301
+ };
302
+ obj.readyState = 1;
303
+ try {
304
+ obj.cues = mediaelement.createCueList();
305
+ obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = mediaelement.createCueList();
306
+ ajax = $.ajax({
307
+ dataType: 'text',
308
+ url: src,
309
+ success: function(text){
310
+ if(ajax.getResponseHeader('content-type') != 'text/vtt'){
311
+ webshims.error('set the mime-type of your WebVTT files to text/vtt. see: http://dev.w3.org/html5/webvtt/#text/vtt');
312
+ }
313
+ mediaelement.parseCaptions(text, obj, function(cues){
314
+ if(cues && 'length' in cues){
315
+ obj.readyState = 2;
316
+ $(track).triggerHandler('load');
317
+ $(mediaelem).triggerHandler('updatetrackdisplay');
318
+ } else {
319
+ error();
320
+ }
321
+ });
322
+
323
+ },
324
+ error: error
325
+ });
326
+ } catch(er){
327
+ error();
328
+ webshims.warn(er);
329
+ }
330
+ }
331
+ }
332
+ };
333
+ obj.readyState = 0;
334
+ obj.shimActiveCues = null;
335
+ obj._shimActiveCues = null;
336
+ obj.activeCues = null;
337
+ obj.cues = null;
338
+ $(mediaelem).unbind(loadEvents, load);
339
+ $(track).unbind('checktrackmode', load);
340
+ $(mediaelem).bind(loadEvents, load);
341
+ $(track).bind('checktrackmode', load);
342
+ if(_default){
343
+ obj.mode = showTracks[obj.kind] ? 'showing' : 'hidden';
344
+ load();
345
+ }
346
+ };
347
+
348
+ mediaelement.createTextTrack = function(mediaelem, track){
349
+ var obj, trackData;
350
+ if(track.nodeName){
351
+ trackData = webshims.data(track, 'trackData');
352
+
353
+ if(trackData){
354
+ refreshTrack(track, trackData);
355
+ obj = trackData.track;
356
+ }
357
+ }
358
+
359
+ if(!obj){
360
+ obj = createEventTarget(webshims.objectCreate(textTrackProto));
361
+
362
+ if(!supportTrackMod){
363
+ copyProps.forEach(function(copyProp){
364
+ var prop = $.prop(track, copyProp);
365
+ if(prop){
366
+ obj[copyName[copyProp] || copyProp] = prop;
367
+ }
368
+ });
369
+ }
370
+
371
+
372
+ if(track.nodeName){
373
+
374
+ if(supportTrackMod){
375
+ copyProps.forEach(function(copyProp){
376
+ webshims.defineProperty(obj, copyName[copyProp] || copyProp, {
377
+ get: function(){
378
+ return $.prop(track, copyProp);
379
+ }
380
+ });
381
+ });
382
+ }
383
+
384
+ trackData = webshims.data(track, 'trackData', {track: obj});
385
+ mediaelement.loadTextTrack(mediaelem, track, trackData, ($.prop(track, 'default') && $(track).siblings('track[default]').andSelf()[0] == track));
386
+ } else {
387
+ if(supportTrackMod){
388
+ copyProps.forEach(function(copyProp){
389
+ webshims.defineProperty(obj, copyName[copyProp] || copyProp, {
390
+ value: track[copyProp],
391
+ writeable: false
392
+ });
393
+ });
394
+ }
395
+ obj.cues = mediaelement.createCueList();
396
+ obj.activeCues = obj._shimActiveCues = obj.shimActiveCues = mediaelement.createCueList();
397
+ obj.mode = 'hidden';
398
+ obj.readyState = 2;
399
+ }
400
+ }
401
+ return obj;
402
+ };
403
+
404
+
405
+ /*
406
+ taken from:
407
+ Captionator 0.5.1 [CaptionCrunch]
408
+ Christopher Giffard, 2011
409
+ Share and enjoy
410
+
411
+ https://github.com/cgiffard/Captionator
412
+
413
+ modified for webshims
414
+ */
415
+ mediaelement.parseCaptionChunk = (function(){
416
+ // Set up timestamp parsers
417
+ var WebVTTTimestampParser = /^(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s+\-\-\>\s+(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s*(.*)/;
418
+ var GoogleTimestampParser = /^([\d\.]+)\s+\+([\d\.]+)\s*(.*)/;
419
+ var WebVTTDEFAULTSCueParser = /^(DEFAULTS|DEFAULT)\s+\-\-\>\s+(.*)/g;
420
+ var WebVTTSTYLECueParser = /^(STYLE|STYLES)\s+\-\-\>\s*\n([\s\S]*)/g;
421
+ var WebVTTCOMMENTCueParser = /^(COMMENT|COMMENTS)\s+\-\-\>\s+(.*)/g;
422
+
423
+ return function(subtitleElement,objectCount){
424
+ var cueDefaults = [];
425
+
426
+ var subtitleParts, timeIn, timeOut, html, timeData, subtitlePartIndex, cueSettings = "", id, specialCueData;
427
+ var timestampMatch, tmpCue;
428
+
429
+ // WebVTT Special Cue Logic
430
+ if ((specialCueData = WebVTTDEFAULTSCueParser.exec(subtitleElement))) {
431
+ // cueDefaults = specialCueData.slice(2).join("");
432
+ // cueDefaults = cueDefaults.split(/\s+/g).filter(function(def) { return def && !!def.length; });
433
+ return null;
434
+ } else if ((specialCueData = WebVTTSTYLECueParser.exec(subtitleElement))) {
435
+ return null;
436
+ } else if ((specialCueData = WebVTTCOMMENTCueParser.exec(subtitleElement))) {
437
+ return null; // At this stage, we don't want to do anything with these.
438
+ }
439
+
440
+ subtitleParts = subtitleElement.split(/\n/g);
441
+
442
+ // Trim off any blank lines (logically, should only be max. one, but loop to be sure)
443
+ while (!subtitleParts[0].replace(/\s+/ig,"").length && subtitleParts.length > 0) {
444
+ subtitleParts.shift();
445
+ }
446
+
447
+ if (subtitleParts[0].match(/^\s*[a-z0-9-\_]+\s*$/ig)) {
448
+ // The identifier becomes the cue ID (when *we* load the cues from file. Programatically created cues can have an ID of whatever.)
449
+ id = String(subtitleParts.shift().replace(/\s*/ig,""));
450
+ }
451
+
452
+ for (subtitlePartIndex = 0; subtitlePartIndex < subtitleParts.length; subtitlePartIndex ++) {
453
+ var timestamp = subtitleParts[subtitlePartIndex];
454
+
455
+ if ((timestampMatch = WebVTTTimestampParser.exec(timestamp))) {
456
+
457
+ // WebVTT
458
+
459
+ timeData = timestampMatch.slice(1);
460
+
461
+ timeIn = parseInt((timeData[0]||0) * 60 * 60,10) + // Hours
462
+ parseInt((timeData[1]||0) * 60,10) + // Minutes
463
+ parseInt((timeData[2]||0),10) + // Seconds
464
+ parseFloat("0." + (timeData[3]||0)); // MS
465
+
466
+ timeOut = parseInt((timeData[4]||0) * 60 * 60,10) + // Hours
467
+ parseInt((timeData[5]||0) * 60,10) + // Minutes
468
+ parseInt((timeData[6]||0),10) + // Seconds
469
+ parseFloat("0." + (timeData[7]||0)); // MS
470
+ /*
471
+ if (timeData[8]) {
472
+ cueSettings = timeData[8];
473
+ }
474
+ */
475
+ }
476
+
477
+ // We've got the timestamp - return all the other unmatched lines as the raw subtitle data
478
+ subtitleParts = subtitleParts.slice(0,subtitlePartIndex).concat(subtitleParts.slice(subtitlePartIndex+1));
479
+ break;
480
+ }
481
+
482
+ if (!timeIn && !timeOut) {
483
+ // We didn't extract any time information. Assume the cue is invalid!
484
+ webshims.warn("couldn't extract time information: "+[timeIn, timeOut, subtitleParts.join("\n"), id].join(' ; '));
485
+ return null;
486
+ }
487
+ /*
488
+ // Consolidate cue settings, convert defaults to object
489
+ var compositeCueSettings =
490
+ cueDefaults
491
+ .reduce(function(previous,current,index,array){
492
+ previous[current.split(":")[0]] = current.split(":")[1];
493
+ return previous;
494
+ },{});
495
+
496
+ // Loop through cue settings, replace defaults with cue specific settings if they exist
497
+ compositeCueSettings =
498
+ cueSettings
499
+ .split(/\s+/g)
500
+ .filter(function(set) { return set && !!set.length; })
501
+ // Convert array to a key/val object
502
+ .reduce(function(previous,current,index,array){
503
+ previous[current.split(":")[0]] = current.split(":")[1];
504
+ return previous;
505
+ },compositeCueSettings);
506
+
507
+ // Turn back into string like the TextTrackCue constructor expects
508
+ cueSettings = "";
509
+ for (var key in compositeCueSettings) {
510
+ if (compositeCueSettings.hasOwnProperty(key)) {
511
+ cueSettings += !!cueSettings.length ? " " : "";
512
+ cueSettings += key + ":" + compositeCueSettings[key];
513
+ }
514
+ }
515
+ */
516
+ // The remaining lines are the subtitle payload itself (after removing an ID if present, and the time);
517
+ html = subtitleParts.join("\n");
518
+ tmpCue = new TextTrackCue(timeIn, timeOut, html);
519
+ if(id){
520
+ tmpCue.id = id;
521
+ }
522
+ return tmpCue;
523
+ };
524
+ })();
525
+
526
+ mediaelement.parseCaptions = function(captionData, track, complete) {
527
+ var subtitles = mediaelement.createCueList();
528
+ var cue, lazyProcess, regWevVTT;
529
+ var startDate;
530
+ var isWEBVTT;
531
+ if (captionData) {
532
+
533
+ regWevVTT = /^WEBVTT(\s*FILE)?/ig;
534
+
535
+ lazyProcess = function(i, len){
536
+
537
+ for(; i < len; i++){
538
+ cue = captionData[i];
539
+ if(regWevVTT.test(cue)){
540
+ isWEBVTT = true;
541
+ } else if(cue.replace(/\s*/ig,"").length){
542
+ if(!isWEBVTT){
543
+ webshims.error('please use WebVTT format. This is the standard');
544
+ complete(null);
545
+ break;
546
+ }
547
+ cue = mediaelement.parseCaptionChunk(cue, i);
548
+ if(cue){
549
+ track.addCue(cue);
550
+ }
551
+ }
552
+ if(startDate < (new Date().getTime()) - 30){
553
+ i++;
554
+ setTimeout(function(){
555
+ startDate = new Date().getTime();
556
+ lazyProcess(i, len);
557
+ }, 90);
558
+
559
+ break;
560
+ }
561
+ }
562
+ if(i >= len){
563
+ if(!isWEBVTT){
564
+ webshims.error('please use WebVTT format. This is the standard');
565
+ }
566
+ complete(track.cues);
567
+ }
568
+ };
569
+
570
+ captionData = captionData.replace(/\r\n/g,"\n");
571
+
572
+ setTimeout(function(){
573
+ captionData = captionData.replace(/\r/g,"\n");
574
+ setTimeout(function(){
575
+ startDate = new Date().getTime();
576
+ captionData = captionData.split(/\n\n+/g);
577
+ lazyProcess(0, captionData.length);
578
+ }, 9);
579
+ }, 9);
580
+
581
+ } else {
582
+ webshims.error("Required parameter captionData not supplied.");
583
+ }
584
+ };
585
+
586
+
587
+ mediaelement.createTrackList = function(mediaelem, baseData){
588
+ baseData = baseData || webshims.data(mediaelem, 'mediaelementBase') || webshims.data(mediaelem, 'mediaelementBase', {});
589
+ if(!baseData.textTracks){
590
+ baseData.textTracks = [];
591
+ webshims.defineProperties(baseData.textTracks, {
592
+ onaddtrack: {value: null},
593
+ onremovetrack: {value: null}
594
+ });
595
+ createEventTarget(baseData.textTracks);
596
+ }
597
+ return baseData.textTracks;
598
+ };
599
+
600
+ if(!Modernizr.track){
601
+ webshims.defineNodeNamesBooleanProperty(['track'], 'default');
602
+ webshims.reflectProperties(['track'], ['srclang', 'label']);
603
+
604
+ webshims.defineNodeNameProperties('track', {
605
+ src: {
606
+ //attr: {},
607
+ reflect: true,
608
+ propType: 'src'
609
+ }
610
+ });
611
+ }
612
+
613
+ webshims.defineNodeNameProperties('track', {
614
+ kind: {
615
+ attr: Modernizr.track ? {
616
+ set: function(value){
617
+ var trackData = webshims.data(this, 'trackData');
618
+ this.setAttribute('data-kind', value);
619
+ if(trackData){
620
+ trackData.attrKind = value;
621
+ }
622
+ },
623
+ get: function(){
624
+ var trackData = webshims.data(this, 'trackData');
625
+ if(trackData && ('attrKind' in trackData)){
626
+ return trackData.attrKind;
627
+ }
628
+ return this.getAttribute('kind');
629
+ }
630
+ } : {},
631
+ reflect: true,
632
+ propType: 'enumarated',
633
+ defaultValue: 'subtitles',
634
+ limitedTo: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata']
635
+ }
636
+ });
637
+
638
+ $.each(copyProps, function(i, copyProp){
639
+ var name = copyName[copyProp] || copyProp;
640
+ webshims.onNodeNamesPropertyModify('track', copyProp, function(){
641
+ var trackData = webshims.data(this, 'trackData');
642
+ var track = this;
643
+ if(trackData){
644
+ if(copyProp == 'kind'){
645
+ refreshTrack(this, trackData);
646
+ }
647
+ if(!supportTrackMod){
648
+ trackData.track[name] = $.prop(this, copyProp);
649
+ }
650
+ clearTimeout(trackData.changedTrackPropTimer);
651
+ trackData.changedTrackPropTimer = setTimeout(function(){
652
+ $(track).trigger('updatesubtitlestate');
653
+ }, 1);
654
+ }
655
+ });
656
+ });
657
+
658
+
659
+ webshims.onNodeNamesPropertyModify('track', 'src', function(val){
660
+ if(val){
661
+ var data = webshims.data(this, 'trackData');
662
+ var media;
663
+ if(data){
664
+ media = $(this).closest('video, audio');
665
+ if(media[0]){
666
+ mediaelement.loadTextTrack(media, this, data);
667
+ }
668
+ }
669
+ }
670
+
671
+ });
672
+
673
+ //
674
+
675
+ webshims.defineNodeNamesProperties(['track'], {
676
+ ERROR: {
677
+ value: 3
678
+ },
679
+ LOADED: {
680
+ value: 2
681
+ },
682
+ LOADING: {
683
+ value: 1
684
+ },
685
+ NONE: {
686
+ value: 0
687
+ },
688
+ readyState: {
689
+ get: function(){
690
+ return ($.prop(this, 'track') || {readyState: 0}).readyState;
691
+ },
692
+ writeable: false
693
+ },
694
+ track: {
695
+ get: function(){
696
+ return mediaelement.createTextTrack($(this).closest('audio, video')[0], this);
697
+ },
698
+ writeable: false
699
+ }
700
+ }, 'prop');
701
+
702
+ webshims.defineNodeNamesProperties(['audio', 'video'], {
703
+ textTracks: {
704
+ get: function(){
705
+ var media = this;
706
+ var baseData = webshims.data(media, 'mediaelementBase') || webshims.data(media, 'mediaelementBase', {});
707
+ var tracks = mediaelement.createTrackList(media, baseData);
708
+ if(!baseData.blockTrackListUpdate){
709
+ updateMediaTrackList.call(media, baseData, tracks);
710
+ }
711
+ return tracks;
712
+ },
713
+ writeable: false
714
+ },
715
+ addTextTrack: {
716
+ value: function(kind, label, lang){
717
+ var textTrack = mediaelement.createTextTrack(this, {
718
+ kind: kind || '',
719
+ label: label || '',
720
+ srclang: lang || ''
721
+ });
722
+ var baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {});
723
+ if (!baseData.scriptedTextTracks) {
724
+ baseData.scriptedTextTracks = [];
725
+ }
726
+ baseData.scriptedTextTracks.push(textTrack);
727
+ updateMediaTrackList.call(this);
728
+ return textTrack;
729
+ }
730
+ }
731
+ }, 'prop');
732
+
733
+
734
+ $(document).bind('emptied ended updatetracklist', function(e){
735
+ if($(e.target).is('audio, video')){
736
+ var baseData = webshims.data(e.target, 'mediaelementBase');
737
+ if(baseData){
738
+ clearTimeout(baseData.updateTrackListTimer);
739
+ baseData.updateTrackListTimer = setTimeout(function(){
740
+ updateMediaTrackList.call(e.target, baseData);
741
+ }, 0);
742
+ }
743
+ }
744
+ });
745
+
746
+ var getNativeReadyState = function(trackElem, textTrack){
747
+ return textTrack.readyState || trackElem.readyState;
748
+ };
749
+
750
+ webshims.addReady(function(context, insertedElement){
751
+ var insertedMedia = insertedElement.filter('video, audio, track').closest('audio, video');
752
+ $('video, audio', context)
753
+ .add(insertedMedia)
754
+ .each(function(){
755
+ updateMediaTrackList.call(this);
756
+ })
757
+ .each(function(){
758
+ if(Modernizr.track){
759
+ var shimedTextTracks = $.prop(this, 'textTracks');
760
+ var origTextTracks = this.textTracks;
761
+ if(shimedTextTracks.length != origTextTracks.length){
762
+ webshims.error("textTracks couldn't be copied");
763
+ }
764
+
765
+ $('track', this)
766
+ .each(function(){
767
+ var shimedTrack = $.prop(this, 'track');
768
+ var origTrack = this.track;
769
+ var kind;
770
+ var readyState;
771
+ if(origTrack){
772
+ kind = $.prop(this, 'kind');
773
+ readyState = getNativeReadyState(this, origTrack);
774
+ if (origTrack.mode || readyState) {
775
+ shimedTrack.mode = origTrack.mode;
776
+ }
777
+ //disable track from showing + remove UI
778
+ if(kind != 'descriptions'){
779
+ origTrack.mode = (typeof origTrack.mode == 'string') ? 'disabled' : 0;
780
+ this.kind = 'metadata';
781
+ $(this).attr({kind: kind});
782
+ }
783
+
784
+ }
785
+ })
786
+ .bind('load error', function(e){
787
+ if(e.originalEvent){
788
+ e.stopImmediatePropagation();
789
+ }
790
+ })
791
+ ;
792
+ }
793
+ })
794
+ ;
795
+ insertedMedia.each(function(){
796
+ var media = this;
797
+ var baseData = webshims.data(media, 'mediaelementBase');
798
+ if(baseData){
799
+ clearTimeout(baseData.updateTrackListTimer);
800
+ baseData.updateTrackListTimer = setTimeout(function(){
801
+ updateMediaTrackList.call(media, baseData);
802
+ }, 9);
803
+ }
804
+ });
805
+ });
806
+
807
+ if(Modernizr.track){
808
+ $('video, audio').trigger('trackapichange');
809
+ }
810
+
763
811
  });