webshims-rails 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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
  });