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
@@ -388,7 +388,7 @@ jQuery.webshims.register('dom-extend', function($, webshims, window, document, u
388
388
  var docObserve = {
389
389
  init: false,
390
390
  start: function(){
391
- if(!this.init){
391
+ if(!this.init && document.body){
392
392
  this.init = true;
393
393
  this.height = $(document).height();
394
394
  this.width = $(document).width();
@@ -400,7 +400,7 @@ jQuery.webshims.register('dom-extend', function($, webshims, window, document, u
400
400
  docObserve.width = width;
401
401
  handler({type: 'docresize'});
402
402
  }
403
- }, 400);
403
+ }, 600);
404
404
  }
405
405
  }
406
406
  };
@@ -416,8 +416,10 @@ jQuery.webshims.register('dom-extend', function($, webshims, window, document, u
416
416
  }
417
417
  lastHeight = height;
418
418
  lastWidth = width;
419
- docObserve.height = $(document).height();
420
- docObserve.width = $(document).width();
419
+ if(document.body){
420
+ docObserve.height = $(document).height();
421
+ docObserve.width = $(document).width();
422
+ }
421
423
  }
422
424
  $.event.trigger('updateshadowdom');
423
425
  }, 40);
@@ -463,7 +465,9 @@ jQuery.webshims.register('dom-extend', function($, webshims, window, document, u
463
465
  shadowFocusElementData.shadowData.data = shadowData.shadowData.data = nativeData.shadowData.data = opts.data;
464
466
  }
465
467
  opts = null;
466
- docObserve.start();
468
+ webshims.ready('DOM', function(){
469
+ docObserve.start();
470
+ });
467
471
  }
468
472
  })(),
469
473
  propTypes: {
@@ -607,7 +611,7 @@ jQuery.webshims.register('dom-extend', function($, webshims, window, document, u
607
611
  }
608
612
  if(propType){
609
613
  if(descs[prop][propType]){
610
- webshims.log('override: '+ name +'['+prop +'] for '+ propType);
614
+ //webshims.log('override: '+ name +'['+prop +'] for '+ propType);
611
615
  } else {
612
616
  descs[prop][propType] = {};
613
617
  ['value', 'set', 'get'].forEach(function(copyProp){
@@ -2098,766 +2102,814 @@ jQuery.webshims.register('form-core', function($, webshims, window, document, un
2098
2102
  });
2099
2103
  }
2100
2104
 
2101
- });jQuery.webshims.register('track', function($, webshims, window, document, undefined){
2102
- var mediaelement = webshims.mediaelement;
2103
- var id = new Date().getTime();
2104
- var showTracks = {subtitles: 1, captions: 1};
2105
- var notImplemented = function(){
2106
- webshims.error('not implemented yet');
2107
- };
2108
-
2109
- var createEventTarget = function(obj){
2110
- var eventList = {};
2111
- obj.addEventListener = function(name, fn){
2112
- if(eventList[name]){
2113
- webshims.error('always use $.bind to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn);
2114
- }
2115
- eventList[name] = fn;
2116
-
2117
- };
2118
- obj.removeEventListener = function(name, fn){
2119
- if(eventList[name] && eventList[name] != fn){
2120
- webshims.error('always use $.bind/$.unbind to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn);
2121
- }
2122
- if(eventList[name]){
2123
- delete eventList[name];
2124
- }
2125
- };
2126
- return obj;
2127
- };
2128
-
2129
-
2130
- var cueListProto = {
2131
- getCueById: function(id){
2132
- var cue = null;
2133
- for(var i = 0, len = this.length; i < len; i++){
2134
- if(this[i].id === id){
2135
- cue = this[i];
2136
- break;
2137
- }
2138
- }
2139
- return cue;
2140
- }
2141
- };
2142
- var textTrackProto = {
2143
- shimActiveCues: null,
2144
- _shimActiveCues: null,
2145
- activeCues: null,
2146
- cues: null,
2147
- kind: 'subtitles',
2148
- label: '',
2149
- language: '',
2150
- mode: 'disabled',
2151
- readyState: 0,
2152
- oncuechange: null,
2153
- toString: function() {
2154
- return "[object TextTrack]";
2155
- },
2156
- addCue: function(cue){
2157
- if(!this.cues){
2158
- this.cues = mediaelement.createCueList();
2159
- } else {
2160
- var lastCue = this.cues[this.cues.length-1];
2161
- if(lastCue && lastCue.startTime > cue.startTime){
2162
- webshims.error("cue startTime higher than previous cue's startTime");
2163
- }
2164
- }
2165
- if(cue.track){
2166
- webshims.error("cue already part of a track element");
2167
- }
2168
- cue.track = this;
2169
- this.cues.push(cue);
2170
- },
2171
- removeCue: notImplemented,
2172
- DISABLED: 'disabled',
2173
- OFF: 'disabled',
2174
- HIDDEN: 'hidden',
2175
- SHOWING: 'showing',
2176
- ERROR: 3,
2177
- LOADED: 2,
2178
- LOADING: 1,
2179
- NONE: 0
2180
- };
2181
- var copyProps = ['kind', 'label', 'srclang'];
2182
-
2183
- var owns = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
2184
-
2185
- //ToDo: add/remove event
2186
- var updateMediaTrackList = function(baseData, trackList){
2187
- var removed = [];
2188
- var added = [];
2189
- var newTracks = [];
2190
- var i, len;
2191
- if(!baseData){
2192
- baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {});
2193
- }
2194
-
2195
- if(!trackList){
2196
- baseData.blockTrackListUpdate = true;
2197
- trackList = $.prop(this, 'textTracks');
2198
- baseData.blockTrackListUpdate = false;
2199
- }
2200
-
2201
- clearTimeout(baseData.updateTrackListTimer);
2202
-
2203
- $('track', this).each(function(){
2204
- var track = $.prop(this, 'track');
2205
- newTracks.push(track);
2206
- if(trackList.indexOf(track) == -1){
2207
- added.push(track);
2208
- }
2209
- });
2210
-
2211
- if(baseData.scriptedTextTracks){
2212
- for(i = 0, len = baseData.scriptedTextTracks.length; i < len; i++){
2213
- newTracks.push(baseData.scriptedTextTracks[i]);
2214
- if(trackList.indexOf(baseData.scriptedTextTracks[i]) == -1){
2215
- added.push(baseData.scriptedTextTracks[i]);
2216
- }
2217
- }
2218
- }
2219
-
2220
- for(i = 0, len = trackList.length; i < len; i++){
2221
- if(newTracks.indexOf(trackList[i]) == -1){
2222
- removed.push(trackList[i]);
2223
- }
2224
- }
2225
-
2226
- if(removed.length || added.length){
2227
- trackList.splice(0);
2228
-
2229
- for(i = 0, len = newTracks.length; i < len; i++){
2230
- trackList.push(newTracks[i]);
2231
- }
2232
- for(i = 0, len = removed.length; i < len; i++){
2233
- $([trackList]).triggerHandler($.Event({type: 'removetrack', track: trackList, track: removed[i]}));
2234
- }
2235
- for(i = 0, len = added.length; i < len; i++){
2236
- $([trackList]).triggerHandler($.Event({type: 'addtrack', track: trackList, track: added[i]}));
2237
- }
2238
- if(baseData.scriptedTextTracks || removed.length){
2239
- $(this).triggerHandler('updatetrackdisplay');
2240
- }
2241
- }
2242
- };
2243
-
2244
- var refreshTrack = function(track, trackData){
2245
- var mode, kind;
2246
- if(!trackData){
2247
- trackData = webshims.data(track, 'trackData');
2248
- }
2249
- if(trackData && !trackData.isTriggering){
2250
- trackData.isTriggering = true;
2251
- mode = (trackData.track || {}).mode;
2252
- kind = (trackData.track || {}).kind;
2253
- setTimeout(function(){
2254
- if(mode !== (trackData.track || {}).mode || kind != (trackData.track || {}).kind){
2255
- if(!(trackData.track || {}).readyState){
2256
- $(track).triggerHandler('checktrackmode');
2257
- } else {
2258
- $(track).parent().triggerHandler('updatetrackdisplay');
2259
- }
2260
- }
2261
- trackData.isTriggering = false;
2262
-
2263
- }, 9);
2264
- }
2265
- };
2266
-
2267
- var emptyDiv = $('<div />')[0];
2268
- window.TextTrackCue = function(startTime, endTime, text){
2269
- if(arguments.length != 3){
2270
- webshims.error("wrong arguments.length for TextTrackCue.constructor");
2271
- }
2272
-
2273
- this.startTime = startTime;
2274
- this.endTime = endTime;
2275
- this.text = text;
2276
-
2277
- this.id = "";
2278
- this.pauseOnExit = false;
2279
-
2280
- createEventTarget(this);
2281
- };
2282
-
2283
- window.TextTrackCue.prototype = {
2284
-
2285
- onenter: null,
2286
- onexit: null,
2287
- pauseOnExit: false,
2288
- getCueAsHTML: function(){
2289
- var lastText = "";
2290
- var parsedText = "";
2291
- var fragment = document.createDocumentFragment();
2292
- var fn;
2293
- if(!owns(this, 'getCueAsHTML')){
2294
- fn = this.getCueAsHTML = function(){
2295
- var i, len;
2296
- if(lastText != this.text){
2297
- lastText = this.text;
2298
- parsedText = mediaelement.parseCueTextToHTML(lastText);
2299
- emptyDiv.innerHTML = parsedText;
2300
-
2301
- for(i = 0, len = emptyDiv.childNodes.length; i < len; i++){
2302
- fragment.appendChild(emptyDiv.childNodes[i].cloneNode(true));
2303
- }
2304
- }
2305
- return fragment.cloneNode(true);
2306
- };
2307
-
2308
- }
2309
- return fn ? fn.apply(this, arguments) : fragment.cloneNode(true);
2310
- },
2311
- track: null,
2312
-
2313
-
2314
- id: ''
2315
- //todo-->
2316
- // ,
2317
- // snapToLines: true,
2318
- // line: 'auto',
2319
- // size: 100,
2320
- // position: 50,
2321
- // vertical: '',
2322
- // align: 'middle'
2323
- };
2324
-
2325
-
2326
-
2327
-
2328
-
2329
- mediaelement.createCueList = function(){
2330
- return $.extend([], cueListProto);
2331
- };
2332
-
2333
- mediaelement.parseCueTextToHTML = (function(){
2334
- var tagSplits = /(<\/?[^>]+>)/ig;
2335
- var allowedTags = /^(?:c|v|ruby|rt|b|i|u)/;
2336
- var regEnd = /\<\s*\//;
2337
- var addToTemplate = function(localName, attribute, tag, html){
2338
- var ret;
2339
- if(regEnd.test(html)){
2340
- ret = '</'+ localName +'>';
2341
- } else {
2342
- tag.splice(0, 1);
2343
- ret = '<'+ localName +' '+ attribute +'="'+ (tag.join(' ').replace(/\"/g, '&#34;')) +'">';
2344
- }
2345
- return ret;
2346
- };
2347
- var replacer = function(html){
2348
- var tag = html.replace(/[<\/>]+/ig,"").split(/[\s\.]+/);
2349
- if(tag[0]){
2350
- tag[0] = tag[0].toLowerCase();
2351
- if(allowedTags.test(tag[0])){
2352
- if(tag[0] == 'c'){
2353
- html = addToTemplate('span', 'class', tag, html);
2354
- } else if(tag[0] == 'v'){
2355
- html = addToTemplate('q', 'title', tag, html);
2356
- }
2357
- } else {
2358
- html = "";
2359
- }
2360
- }
2361
- return html;
2362
- };
2363
-
2364
- return function(cueText){
2365
- return cueText.replace(tagSplits, replacer);
2366
- };
2367
- })();
2368
-
2369
- mediaelement.loadTextTrack = function(mediaelem, track, trackData, _default){
2370
- var loadEvents = 'play playing timeupdate updatetrackdisplay';
2371
- var obj = trackData.track;
2372
- var load = function(){
2373
- var src = $.prop(track, 'src');
2374
- var error;
2375
- var ajax;
2376
- if(obj.mode != 'disabled' && src && $.attr(track, 'src')){
2377
- $(mediaelem).unbind(loadEvents, load);
2378
- $(track).unbind('checktrackmode', load);
2379
- if(!obj.readyState){
2380
- error = function(){
2381
- obj.readyState = 3;
2382
- obj.cues = null;
2383
- obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = null;
2384
- $(track).triggerHandler('error');
2385
- };
2386
- obj.readyState = 1;
2387
- try {
2388
- obj.cues = mediaelement.createCueList();
2389
- obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = mediaelement.createCueList();
2390
- ajax = $.ajax({
2391
- dataType: 'text',
2392
- url: src,
2393
- success: function(text){
2394
- if(ajax.getResponseHeader('content-type') != 'text/vtt'){
2395
- webshims.error('set the mime-type of your WebVTT files to text/vtt. see: http://dev.w3.org/html5/webvtt/#text/vtt');
2396
- }
2397
- mediaelement.parseCaptions(text, obj, function(cues){
2398
- if(cues && 'length' in cues){
2399
- obj.readyState = 2;
2400
- $(track).triggerHandler('load');
2401
- $(mediaelem).triggerHandler('updatetrackdisplay');
2402
- } else {
2403
- error();
2404
- }
2405
- });
2406
-
2407
- },
2408
- error: error
2409
- });
2410
- } catch(er){
2411
- error();
2412
- webshims.warn(er);
2413
- }
2414
- }
2415
- }
2416
- };
2417
- obj.readyState = 0;
2418
- obj.shimActiveCues = null;
2419
- obj._shimActiveCues = null;
2420
- obj.activeCues = null;
2421
- obj.cues = null;
2422
- $(mediaelem).unbind(loadEvents, load);
2423
- $(track).unbind('checktrackmode', load);
2424
- $(mediaelem).bind(loadEvents, load);
2425
- $(track).bind('checktrackmode', load);
2426
- if(_default){
2427
- obj.mode = showTracks[obj.kind] ? 'showing' : 'hidden';
2428
- load();
2429
- }
2430
- };
2431
-
2432
- mediaelement.createTextTrack = function(mediaelem, track){
2433
- var obj, trackData;
2434
- if(track.nodeName){
2435
- trackData = webshims.data(track, 'trackData');
2436
-
2437
- if(trackData){
2438
- refreshTrack(track, trackData);
2439
- obj = trackData.track;
2440
- }
2441
- }
2442
-
2443
- if(!obj){
2444
- obj = createEventTarget(webshims.objectCreate(textTrackProto));
2445
- copyProps.forEach(function(copyProp){
2446
- var prop = $.prop(track, copyProp);
2447
- if(prop){
2448
- if(copyProp == 'srclang'){
2449
- copyProp = 'language';
2450
- }
2451
- obj[copyProp] = prop;
2452
- }
2453
- });
2454
-
2455
-
2456
- if(track.nodeName){
2457
- trackData = webshims.data(track, 'trackData', {track: obj});
2458
- mediaelement.loadTextTrack(mediaelem, track, trackData, $.prop(track, 'default'));
2459
- } else {
2460
- obj.cues = mediaelement.createCueList();
2461
- obj.activeCues = obj._shimActiveCues = obj.shimActiveCues = mediaelement.createCueList();
2462
- obj.mode = 'hidden';
2463
- obj.readyState = 2;
2464
- }
2465
- }
2466
- return obj;
2467
- };
2468
-
2469
-
2470
- /*
2471
- taken from:
2472
- Captionator 0.5.1 [CaptionCrunch]
2473
- Christopher Giffard, 2011
2474
- Share and enjoy
2475
-
2476
- https://github.com/cgiffard/Captionator
2477
-
2478
- modified for webshims
2479
- */
2480
- mediaelement.parseCaptionChunk = (function(){
2481
- // Set up timestamp parsers
2482
- var WebVTTTimestampParser = /^(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s+\-\-\>\s+(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s*(.*)/;
2483
- var GoogleTimestampParser = /^([\d\.]+)\s+\+([\d\.]+)\s*(.*)/;
2484
- var WebVTTDEFAULTSCueParser = /^(DEFAULTS|DEFAULT)\s+\-\-\>\s+(.*)/g;
2485
- var WebVTTSTYLECueParser = /^(STYLE|STYLES)\s+\-\-\>\s*\n([\s\S]*)/g;
2486
- var WebVTTCOMMENTCueParser = /^(COMMENT|COMMENTS)\s+\-\-\>\s+(.*)/g;
2487
-
2488
- return function(subtitleElement,objectCount){
2489
- var cueDefaults = [];
2490
-
2491
- var subtitleParts, timeIn, timeOut, html, timeData, subtitlePartIndex, cueSettings = "", id, specialCueData;
2492
- var timestampMatch, tmpCue;
2493
-
2494
- // WebVTT Special Cue Logic
2495
- if ((specialCueData = WebVTTDEFAULTSCueParser.exec(subtitleElement))) {
2496
- // cueDefaults = specialCueData.slice(2).join("");
2497
- // cueDefaults = cueDefaults.split(/\s+/g).filter(function(def) { return def && !!def.length; });
2498
- return null;
2499
- } else if ((specialCueData = WebVTTSTYLECueParser.exec(subtitleElement))) {
2500
- return null;
2501
- } else if ((specialCueData = WebVTTCOMMENTCueParser.exec(subtitleElement))) {
2502
- return null; // At this stage, we don't want to do anything with these.
2503
- }
2504
-
2505
- subtitleParts = subtitleElement.split(/\n/g);
2506
-
2507
- // Trim off any blank lines (logically, should only be max. one, but loop to be sure)
2508
- while (!subtitleParts[0].replace(/\s+/ig,"").length && subtitleParts.length > 0) {
2509
- subtitleParts.shift();
2510
- }
2511
-
2512
- if (subtitleParts[0].match(/^\s*[a-z0-9]+\s*$/ig)) {
2513
- // The identifier becomes the cue ID (when *we* load the cues from file. Programatically created cues can have an ID of whatever.)
2514
- id = String(subtitleParts.shift().replace(/\s*/ig,""));
2515
- }
2516
-
2517
- for (subtitlePartIndex = 0; subtitlePartIndex < subtitleParts.length; subtitlePartIndex ++) {
2518
- var timestamp = subtitleParts[subtitlePartIndex];
2519
-
2520
- if ((timestampMatch = WebVTTTimestampParser.exec(timestamp))) {
2521
-
2522
- // WebVTT
2523
-
2524
- timeData = timestampMatch.slice(1);
2525
-
2526
- timeIn = parseInt((timeData[0]||0) * 60 * 60,10) + // Hours
2527
- parseInt((timeData[1]||0) * 60,10) + // Minutes
2528
- parseInt((timeData[2]||0),10) + // Seconds
2529
- parseFloat("0." + (timeData[3]||0)); // MS
2530
-
2531
- timeOut = parseInt((timeData[4]||0) * 60 * 60,10) + // Hours
2532
- parseInt((timeData[5]||0) * 60,10) + // Minutes
2533
- parseInt((timeData[6]||0),10) + // Seconds
2534
- parseFloat("0." + (timeData[7]||0)); // MS
2535
- /*
2536
- if (timeData[8]) {
2537
- cueSettings = timeData[8];
2538
- }
2539
- */
2540
- }
2541
-
2542
- // We've got the timestamp - return all the other unmatched lines as the raw subtitle data
2543
- subtitleParts = subtitleParts.slice(0,subtitlePartIndex).concat(subtitleParts.slice(subtitlePartIndex+1));
2544
- break;
2545
- }
2546
-
2547
- if (!timeIn && !timeOut) {
2548
- // We didn't extract any time information. Assume the cue is invalid!
2549
- return null;
2550
- }
2551
- /*
2552
- // Consolidate cue settings, convert defaults to object
2553
- var compositeCueSettings =
2554
- cueDefaults
2555
- .reduce(function(previous,current,index,array){
2556
- previous[current.split(":")[0]] = current.split(":")[1];
2557
- return previous;
2558
- },{});
2559
-
2560
- // Loop through cue settings, replace defaults with cue specific settings if they exist
2561
- compositeCueSettings =
2562
- cueSettings
2563
- .split(/\s+/g)
2564
- .filter(function(set) { return set && !!set.length; })
2565
- // Convert array to a key/val object
2566
- .reduce(function(previous,current,index,array){
2567
- previous[current.split(":")[0]] = current.split(":")[1];
2568
- return previous;
2569
- },compositeCueSettings);
2570
-
2571
- // Turn back into string like the TextTrackCue constructor expects
2572
- cueSettings = "";
2573
- for (var key in compositeCueSettings) {
2574
- if (compositeCueSettings.hasOwnProperty(key)) {
2575
- cueSettings += !!cueSettings.length ? " " : "";
2576
- cueSettings += key + ":" + compositeCueSettings[key];
2577
- }
2578
- }
2579
- */
2580
- // The remaining lines are the subtitle payload itself (after removing an ID if present, and the time);
2581
- html = subtitleParts.join("\n");
2582
- tmpCue = new TextTrackCue(timeIn, timeOut, html);
2583
- if(id){
2584
- tmpCue.id = id;
2585
- }
2586
- return tmpCue;
2587
- };
2588
- })();
2589
-
2590
- mediaelement.parseCaptions = function(captionData, track, complete) {
2591
- var subtitles = mediaelement.createCueList();
2592
- var cue, lazyProcess, regWevVTT;
2593
- var startDate;
2594
- var isWEBVTT;
2595
- if (captionData) {
2596
-
2597
- regWevVTT = /^WEBVTT(\s*FILE)?/ig;
2598
-
2599
- lazyProcess = function(i, len){
2600
-
2601
- for(; i < len; i++){
2602
- cue = captionData[i];
2603
- if(regWevVTT.test(cue)){
2604
- isWEBVTT = true;
2605
- } else if(cue.replace(/\s*/ig,"").length){
2606
- if(!isWEBVTT){
2607
- webshims.error('please use WebVTT format. This is the standard');
2608
- complete(null);
2609
- break;
2610
- }
2611
- cue = mediaelement.parseCaptionChunk(cue, i);
2612
- if(cue){
2613
- track.addCue(cue);
2614
- }
2615
- }
2616
- if(startDate < (new Date().getTime()) - 9){
2617
- i++;
2618
- setTimeout(function(){
2619
- startDate = new Date().getTime();
2620
- lazyProcess(i, len);
2621
- }, 90);
2622
-
2623
- break;
2624
- }
2625
- }
2626
- if(i >= len){
2627
- if(!isWEBVTT){
2628
- webshims.error('please use WebVTT format. This is the standard');
2629
- }
2630
- complete(track.cues);
2631
- }
2632
- };
2633
-
2634
- captionData = captionData.replace(/\r\n/g,"\n");
2635
-
2636
- setTimeout(function(){
2637
- captionData = captionData.replace(/\r/g,"\n");
2638
- setTimeout(function(){
2639
- startDate = new Date().getTime();
2640
- captionData = captionData.split(/\n\n+/g);
2641
- lazyProcess(0, captionData.length);
2642
- }, 9);
2643
- }, 9);
2644
-
2645
- } else {
2646
- webshims.error("Required parameter captionData not supplied.");
2647
- }
2648
- };
2649
-
2650
-
2651
- mediaelement.createTrackList = function(mediaelem, baseData){
2652
- baseData = baseData || webshims.data(mediaelem, 'mediaelementBase') || webshims.data(mediaelem, 'mediaelementBase', {});
2653
- if(!baseData.textTracks){
2654
- baseData.textTracks = [];
2655
- webshims.defineProperties(baseData.textTracks, {
2656
- onaddtrack: {value: null},
2657
- onremovetrack: {value: null}
2658
- });
2659
- createEventTarget(baseData.textTracks);
2660
- }
2661
- return baseData.textTracks;
2662
- };
2663
-
2664
- if(!Modernizr.track){
2665
- webshims.defineNodeNamesBooleanProperty(['track'], 'default');
2666
- webshims.reflectProperties(['track'], ['srclang', 'label']);
2667
-
2668
- webshims.defineNodeNameProperties('track', {
2669
- src: {
2670
- //attr: {},
2671
- reflect: true,
2672
- propType: 'src'
2673
- }
2674
- });
2675
- }
2676
-
2677
- webshims.defineNodeNameProperties('track', {
2678
- kind: {
2679
- attr: Modernizr.track ? {
2680
- set: function(value){
2681
- var trackData = webshims.data(this, 'trackData');
2682
- this.setAttribute('data-kind', value);
2683
- if(trackData){
2684
- trackData.attrKind = value;
2685
- }
2686
- },
2687
- get: function(){
2688
- var trackData = webshims.data(this, 'trackData');
2689
- if(trackData && ('attrKind' in trackData)){
2690
- return trackData.attrKind;
2691
- }
2692
- return this.getAttribute('kind');
2693
- }
2694
- } : {},
2695
- reflect: true,
2696
- propType: 'enumarated',
2697
- defaultValue: 'subtitles',
2698
- limitedTo: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata']
2699
- }
2700
- });
2701
-
2702
- webshims.onNodeNamesPropertyModify('track', 'kind', function(){
2703
- var trackData = webshims.data(this, 'trackData');
2704
- if(trackData){
2705
- trackData.track.kind = $.prop(this, 'kind');
2706
- refreshTrack(this, trackData);
2707
- }
2708
- });
2709
-
2710
- webshims.onNodeNamesPropertyModify('track', 'src', function(val){
2711
- if(val){
2712
- var data = webshims.data(this, 'trackData');
2713
- var media;
2714
- if(data){
2715
- media = $(this).closest('video, audio');
2716
- if(media[0]){
2717
- mediaelement.loadTextTrack(media, this, data);
2718
- }
2719
- }
2720
- }
2721
-
2722
- });
2723
-
2724
- //
2725
-
2726
- webshims.defineNodeNamesProperties(['track'], {
2727
- ERROR: {
2728
- value: 3
2729
- },
2730
- LOADED: {
2731
- value: 2
2732
- },
2733
- LOADING: {
2734
- value: 1
2735
- },
2736
- NONE: {
2737
- value: 0
2738
- },
2739
- readyState: {
2740
- get: function(){
2741
- return ($.prop(this, 'track') || {readyState: 0}).readyState;
2742
- },
2743
- writeable: false
2744
- },
2745
- track: {
2746
- get: function(){
2747
- return mediaelement.createTextTrack($(this).closest('audio, video')[0], this);
2748
- },
2749
- writeable: false
2750
- }
2751
- }, 'prop');
2752
-
2753
- webshims.defineNodeNamesProperties(['audio', 'video'], {
2754
- textTracks: {
2755
- get: function(){
2756
-
2757
- var media = this;
2758
- var baseData = webshims.data(media, 'mediaelementBase') || webshims.data(media, 'mediaelementBase', {});
2759
- var tracks = mediaelement.createTrackList(media, baseData);
2760
- if(!baseData.blockTrackListUpdate){
2761
- updateMediaTrackList.call(media, baseData, tracks);
2762
- }
2763
- return tracks;
2764
- },
2765
- writeable: false
2766
- },
2767
- addTextTrack: {
2768
- value: function(kind, label, lang){
2769
- var textTrack = mediaelement.createTextTrack(this, {
2770
- kind: kind || '',
2771
- label: label || '',
2772
- srclang: lang || ''
2773
- });
2774
- var baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {});
2775
- if (!baseData.scriptedTextTracks) {
2776
- baseData.scriptedTextTracks = [];
2777
- }
2778
- baseData.scriptedTextTracks.push(textTrack);
2779
- updateMediaTrackList.call(this);
2780
- return textTrack;
2781
- }
2782
- }
2783
- }, 'prop');
2784
-
2785
-
2786
- $(document).bind('emptied ended updatetracklist', function(e){
2787
- if($(e.target).is('audio, video')){
2788
- var baseData = webshims.data(e.target, 'mediaelementBase');
2789
- if(baseData){
2790
- clearTimeout(baseData.updateTrackListTimer);
2791
- baseData.updateTrackListTimer = setTimeout(function(){
2792
- updateMediaTrackList.call(e.target, baseData);
2793
- }, 0);
2794
- }
2795
- }
2796
- });
2797
-
2798
- var getNativeReadyState = function(trackElem, textTrack){
2799
- return textTrack.readyState || trackElem.readyState;
2800
- };
2801
-
2802
- webshims.addReady(function(context, insertedElement){
2803
- var insertedMedia = insertedElement.filter('video, audio, track').closest('audio, video');
2804
- $('video, audio', context)
2805
- .add(insertedMedia)
2806
- .each(function(){
2807
- updateMediaTrackList.call(this);
2808
- })
2809
- .each(function(){
2810
- if(Modernizr.track){
2811
- var shimedTextTracks = $.prop(this, 'textTracks');
2812
- var origTextTracks = this.textTracks;
2813
- if(shimedTextTracks.length != origTextTracks.length){
2814
- webshims.error("textTracks couldn't be copied");
2815
- }
2816
-
2817
- $('track', this)
2818
- .each(function(){
2819
- var shimedTrack = $.prop(this, 'track');
2820
- var origTrack = this.track;
2821
- var kind;
2822
- var readyState;
2823
- if(origTrack){
2824
- kind = $.prop(this, 'kind');
2825
- readyState = getNativeReadyState(this, origTrack);
2826
- if (origTrack.mode || readyState) {
2827
- shimedTrack.mode = origTrack.mode;
2828
- }
2829
- //disable track from showing + remove UI
2830
- if(kind != 'descriptions'){
2831
- origTrack.mode = (typeof origTrack.mode == 'string') ? 'disabled' : 0;
2832
- this.kind = 'metadata';
2833
- $(this).attr({kind: kind});
2834
- }
2835
-
2836
- }
2837
- })
2838
- .bind('load error', function(e){
2839
- if(e.originalEvent){
2840
- e.stopImmediatePropagation();
2841
- }
2842
- })
2843
- ;
2844
- }
2845
- })
2846
- ;
2847
- insertedMedia.each(function(){
2848
- var media = this;
2849
- var baseData = webshims.data(media, 'mediaelementBase');
2850
- if(baseData){
2851
- clearTimeout(baseData.updateTrackListTimer);
2852
- baseData.updateTrackListTimer = setTimeout(function(){
2853
- updateMediaTrackList.call(media, baseData);
2854
- }, 9);
2855
- }
2856
- });
2857
- });
2858
-
2859
- if(Modernizr.track){
2860
- $('video, audio').trigger('trackapichange');
2861
- }
2862
-
2105
+ });jQuery.webshims.register('track', function($, webshims, window, document, undefined){
2106
+ var mediaelement = webshims.mediaelement;
2107
+ var id = new Date().getTime();
2108
+ //descriptions are not really shown, but they are inserted into the dom
2109
+ var showTracks = {subtitles: 1, captions: 1, descriptions: 1};
2110
+ var notImplemented = function(){
2111
+ webshims.error('not implemented yet');
2112
+ };
2113
+ var supportTrackMod = Modernizr.ES5 && Modernizr.objectAccessor;
2114
+ var createEventTarget = function(obj){
2115
+ var eventList = {};
2116
+ obj.addEventListener = function(name, fn){
2117
+ if(eventList[name]){
2118
+ webshims.error('always use $.bind to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn);
2119
+ }
2120
+ eventList[name] = fn;
2121
+
2122
+ };
2123
+ obj.removeEventListener = function(name, fn){
2124
+ if(eventList[name] && eventList[name] != fn){
2125
+ webshims.error('always use $.bind/$.unbind to the shimed event: '+ name +' already bound fn was: '+ eventList[name] +' your fn was: '+ fn);
2126
+ }
2127
+ if(eventList[name]){
2128
+ delete eventList[name];
2129
+ }
2130
+ };
2131
+ return obj;
2132
+ };
2133
+
2134
+
2135
+ var cueListProto = {
2136
+ getCueById: function(id){
2137
+ var cue = null;
2138
+ for(var i = 0, len = this.length; i < len; i++){
2139
+ if(this[i].id === id){
2140
+ cue = this[i];
2141
+ break;
2142
+ }
2143
+ }
2144
+ return cue;
2145
+ }
2146
+ };
2147
+
2148
+ var textTrackProto = {
2149
+ shimActiveCues: null,
2150
+ _shimActiveCues: null,
2151
+ activeCues: null,
2152
+ cues: null,
2153
+ kind: 'subtitles',
2154
+ label: '',
2155
+ language: '',
2156
+ mode: 'disabled',
2157
+ readyState: 0,
2158
+ oncuechange: null,
2159
+ toString: function() {
2160
+ return "[object TextTrack]";
2161
+ },
2162
+ addCue: function(cue){
2163
+ if(!this.cues){
2164
+ this.cues = mediaelement.createCueList();
2165
+ } else {
2166
+ var lastCue = this.cues[this.cues.length-1];
2167
+ if(lastCue && lastCue.startTime > cue.startTime){
2168
+ webshims.error("cue startTime higher than previous cue's startTime");
2169
+ }
2170
+ }
2171
+ if(cue.track && cue.track.removeCue){
2172
+ cue.track.removeCue(cue);
2173
+ }
2174
+ cue.track = this;
2175
+ this.cues.push(cue);
2176
+ },
2177
+ //ToDo: make it more dynamic
2178
+ removeCue: function(cue){
2179
+ var cues = this.cues || [];
2180
+ var i = 0;
2181
+ var len = cues.length;
2182
+ if(cue.track != this){
2183
+ webshims.error("cue not part of track");
2184
+ return;
2185
+ }
2186
+ for(; i < len; i++){
2187
+ if(cues[i] === cue){
2188
+ cues.splice(i, 1);
2189
+ cue.track = null;
2190
+ break;
2191
+ }
2192
+ }
2193
+ if(cue.track){
2194
+ webshims.error("cue not part of track");
2195
+ return;
2196
+ }
2197
+ },
2198
+ DISABLED: 'disabled',
2199
+ OFF: 'disabled',
2200
+ HIDDEN: 'hidden',
2201
+ SHOWING: 'showing',
2202
+ ERROR: 3,
2203
+ LOADED: 2,
2204
+ LOADING: 1,
2205
+ NONE: 0
2206
+ };
2207
+ var copyProps = ['kind', 'label', 'srclang'];
2208
+ var copyName = {srclang: 'language'};
2209
+
2210
+ var owns = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
2211
+
2212
+ var updateMediaTrackList = function(baseData, trackList){
2213
+ var removed = [];
2214
+ var added = [];
2215
+ var newTracks = [];
2216
+ var i, len;
2217
+ if(!baseData){
2218
+ baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {});
2219
+ }
2220
+
2221
+ if(!trackList){
2222
+ baseData.blockTrackListUpdate = true;
2223
+ trackList = $.prop(this, 'textTracks');
2224
+ baseData.blockTrackListUpdate = false;
2225
+ }
2226
+
2227
+ clearTimeout(baseData.updateTrackListTimer);
2228
+
2229
+ $('track', this).each(function(){
2230
+ var track = $.prop(this, 'track');
2231
+ newTracks.push(track);
2232
+ if(trackList.indexOf(track) == -1){
2233
+ added.push(track);
2234
+ }
2235
+ });
2236
+
2237
+ if(baseData.scriptedTextTracks){
2238
+ for(i = 0, len = baseData.scriptedTextTracks.length; i < len; i++){
2239
+ newTracks.push(baseData.scriptedTextTracks[i]);
2240
+ if(trackList.indexOf(baseData.scriptedTextTracks[i]) == -1){
2241
+ added.push(baseData.scriptedTextTracks[i]);
2242
+ }
2243
+ }
2244
+ }
2245
+
2246
+ for(i = 0, len = trackList.length; i < len; i++){
2247
+ if(newTracks.indexOf(trackList[i]) == -1){
2248
+ removed.push(trackList[i]);
2249
+ }
2250
+ }
2251
+
2252
+ if(removed.length || added.length){
2253
+ trackList.splice(0);
2254
+
2255
+ for(i = 0, len = newTracks.length; i < len; i++){
2256
+ trackList.push(newTracks[i]);
2257
+ }
2258
+ for(i = 0, len = removed.length; i < len; i++){
2259
+ $([trackList]).triggerHandler($.Event({type: 'removetrack', track: trackList, track: removed[i]}));
2260
+ }
2261
+ for(i = 0, len = added.length; i < len; i++){
2262
+ $([trackList]).triggerHandler($.Event({type: 'addtrack', track: trackList, track: added[i]}));
2263
+ }
2264
+ if(baseData.scriptedTextTracks || removed.length){
2265
+ $(this).triggerHandler('updatetrackdisplay');
2266
+ }
2267
+ }
2268
+ };
2269
+
2270
+ var refreshTrack = function(track, trackData){
2271
+ if(!trackData){
2272
+ trackData = webshims.data(track, 'trackData');
2273
+ }
2274
+ if(trackData && !trackData.isTriggering){
2275
+ trackData.isTriggering = true;
2276
+ setTimeout(function(){
2277
+ if(!(trackData.track || {}).readyState){
2278
+ $(track).triggerHandler('checktrackmode');
2279
+ } else {
2280
+ $(track).closest('audio, video').triggerHandler('updatetrackdisplay');
2281
+ }
2282
+ trackData.isTriggering = false;
2283
+ }, 1);
2284
+ }
2285
+ };
2286
+
2287
+ var emptyDiv = $('<div />')[0];
2288
+ window.TextTrackCue = function(startTime, endTime, text){
2289
+ if(arguments.length != 3){
2290
+ webshims.error("wrong arguments.length for TextTrackCue.constructor");
2291
+ }
2292
+
2293
+ this.startTime = startTime;
2294
+ this.endTime = endTime;
2295
+ this.text = text;
2296
+
2297
+ this.id = "";
2298
+ this.pauseOnExit = false;
2299
+
2300
+ createEventTarget(this);
2301
+ };
2302
+
2303
+ window.TextTrackCue.prototype = {
2304
+
2305
+ onenter: null,
2306
+ onexit: null,
2307
+ pauseOnExit: false,
2308
+ getCueAsHTML: function(){
2309
+ var lastText = "";
2310
+ var parsedText = "";
2311
+ var fragment = document.createDocumentFragment();
2312
+ var fn;
2313
+ if(!owns(this, 'getCueAsHTML')){
2314
+ fn = this.getCueAsHTML = function(){
2315
+ var i, len;
2316
+ if(lastText != this.text){
2317
+ lastText = this.text;
2318
+ parsedText = mediaelement.parseCueTextToHTML(lastText);
2319
+ emptyDiv.innerHTML = parsedText;
2320
+
2321
+ for(i = 0, len = emptyDiv.childNodes.length; i < len; i++){
2322
+ fragment.appendChild(emptyDiv.childNodes[i].cloneNode(true));
2323
+ }
2324
+ }
2325
+ return fragment.cloneNode(true);
2326
+ };
2327
+
2328
+ }
2329
+ return fn ? fn.apply(this, arguments) : fragment.cloneNode(true);
2330
+ },
2331
+ track: null,
2332
+
2333
+
2334
+ id: ''
2335
+ //todo-->
2336
+ // ,
2337
+ // snapToLines: true,
2338
+ // line: 'auto',
2339
+ // size: 100,
2340
+ // position: 50,
2341
+ // vertical: '',
2342
+ // align: 'middle'
2343
+ };
2344
+
2345
+
2346
+
2347
+
2348
+
2349
+ mediaelement.createCueList = function(){
2350
+ return $.extend([], cueListProto);
2351
+ };
2352
+
2353
+ mediaelement.parseCueTextToHTML = (function(){
2354
+ var tagSplits = /(<\/?[^>]+>)/ig;
2355
+ var allowedTags = /^(?:c|v|ruby|rt|b|i|u)/;
2356
+ var regEnd = /\<\s*\//;
2357
+ var addToTemplate = function(localName, attribute, tag, html){
2358
+ var ret;
2359
+ if(regEnd.test(html)){
2360
+ ret = '</'+ localName +'>';
2361
+ } else {
2362
+ tag.splice(0, 1);
2363
+ ret = '<'+ localName +' '+ attribute +'="'+ (tag.join(' ').replace(/\"/g, '&#34;')) +'">';
2364
+ }
2365
+ return ret;
2366
+ };
2367
+ var replacer = function(html){
2368
+ var tag = html.replace(/[<\/>]+/ig,"").split(/[\s\.]+/);
2369
+ if(tag[0]){
2370
+ tag[0] = tag[0].toLowerCase();
2371
+ if(allowedTags.test(tag[0])){
2372
+ if(tag[0] == 'c'){
2373
+ html = addToTemplate('span', 'class', tag, html);
2374
+ } else if(tag[0] == 'v'){
2375
+ html = addToTemplate('q', 'title', tag, html);
2376
+ }
2377
+ } else {
2378
+ html = "";
2379
+ }
2380
+ }
2381
+ return html;
2382
+ };
2383
+
2384
+ return function(cueText){
2385
+ return cueText.replace(tagSplits, replacer);
2386
+ };
2387
+ })();
2388
+
2389
+ mediaelement.loadTextTrack = function(mediaelem, track, trackData, _default){
2390
+ var loadEvents = 'play playing timeupdate updatetrackdisplay';
2391
+ var obj = trackData.track;
2392
+ var load = function(){
2393
+ var src = $.prop(track, 'src');
2394
+ var error;
2395
+ var ajax;
2396
+ if(obj.mode != 'disabled' && src && $.attr(track, 'src')){
2397
+ $(mediaelem).unbind(loadEvents, load);
2398
+ $(track).unbind('checktrackmode', load);
2399
+ if(!obj.readyState){
2400
+ error = function(){
2401
+ obj.readyState = 3;
2402
+ obj.cues = null;
2403
+ obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = null;
2404
+ $(track).triggerHandler('error');
2405
+ };
2406
+ obj.readyState = 1;
2407
+ try {
2408
+ obj.cues = mediaelement.createCueList();
2409
+ obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = mediaelement.createCueList();
2410
+ ajax = $.ajax({
2411
+ dataType: 'text',
2412
+ url: src,
2413
+ success: function(text){
2414
+ if(ajax.getResponseHeader('content-type') != 'text/vtt'){
2415
+ webshims.error('set the mime-type of your WebVTT files to text/vtt. see: http://dev.w3.org/html5/webvtt/#text/vtt');
2416
+ }
2417
+ mediaelement.parseCaptions(text, obj, function(cues){
2418
+ if(cues && 'length' in cues){
2419
+ obj.readyState = 2;
2420
+ $(track).triggerHandler('load');
2421
+ $(mediaelem).triggerHandler('updatetrackdisplay');
2422
+ } else {
2423
+ error();
2424
+ }
2425
+ });
2426
+
2427
+ },
2428
+ error: error
2429
+ });
2430
+ } catch(er){
2431
+ error();
2432
+ webshims.warn(er);
2433
+ }
2434
+ }
2435
+ }
2436
+ };
2437
+ obj.readyState = 0;
2438
+ obj.shimActiveCues = null;
2439
+ obj._shimActiveCues = null;
2440
+ obj.activeCues = null;
2441
+ obj.cues = null;
2442
+ $(mediaelem).unbind(loadEvents, load);
2443
+ $(track).unbind('checktrackmode', load);
2444
+ $(mediaelem).bind(loadEvents, load);
2445
+ $(track).bind('checktrackmode', load);
2446
+ if(_default){
2447
+ obj.mode = showTracks[obj.kind] ? 'showing' : 'hidden';
2448
+ load();
2449
+ }
2450
+ };
2451
+
2452
+ mediaelement.createTextTrack = function(mediaelem, track){
2453
+ var obj, trackData;
2454
+ if(track.nodeName){
2455
+ trackData = webshims.data(track, 'trackData');
2456
+
2457
+ if(trackData){
2458
+ refreshTrack(track, trackData);
2459
+ obj = trackData.track;
2460
+ }
2461
+ }
2462
+
2463
+ if(!obj){
2464
+ obj = createEventTarget(webshims.objectCreate(textTrackProto));
2465
+
2466
+ if(!supportTrackMod){
2467
+ copyProps.forEach(function(copyProp){
2468
+ var prop = $.prop(track, copyProp);
2469
+ if(prop){
2470
+ obj[copyName[copyProp] || copyProp] = prop;
2471
+ }
2472
+ });
2473
+ }
2474
+
2475
+
2476
+ if(track.nodeName){
2477
+
2478
+ if(supportTrackMod){
2479
+ copyProps.forEach(function(copyProp){
2480
+ webshims.defineProperty(obj, copyName[copyProp] || copyProp, {
2481
+ get: function(){
2482
+ return $.prop(track, copyProp);
2483
+ }
2484
+ });
2485
+ });
2486
+ }
2487
+
2488
+ trackData = webshims.data(track, 'trackData', {track: obj});
2489
+ mediaelement.loadTextTrack(mediaelem, track, trackData, ($.prop(track, 'default') && $(track).siblings('track[default]').andSelf()[0] == track));
2490
+ } else {
2491
+ if(supportTrackMod){
2492
+ copyProps.forEach(function(copyProp){
2493
+ webshims.defineProperty(obj, copyName[copyProp] || copyProp, {
2494
+ value: track[copyProp],
2495
+ writeable: false
2496
+ });
2497
+ });
2498
+ }
2499
+ obj.cues = mediaelement.createCueList();
2500
+ obj.activeCues = obj._shimActiveCues = obj.shimActiveCues = mediaelement.createCueList();
2501
+ obj.mode = 'hidden';
2502
+ obj.readyState = 2;
2503
+ }
2504
+ }
2505
+ return obj;
2506
+ };
2507
+
2508
+
2509
+ /*
2510
+ taken from:
2511
+ Captionator 0.5.1 [CaptionCrunch]
2512
+ Christopher Giffard, 2011
2513
+ Share and enjoy
2514
+
2515
+ https://github.com/cgiffard/Captionator
2516
+
2517
+ modified for webshims
2518
+ */
2519
+ mediaelement.parseCaptionChunk = (function(){
2520
+ // Set up timestamp parsers
2521
+ var WebVTTTimestampParser = /^(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s+\-\-\>\s+(\d{2})?:?(\d{2}):(\d{2})\.(\d+)\s*(.*)/;
2522
+ var GoogleTimestampParser = /^([\d\.]+)\s+\+([\d\.]+)\s*(.*)/;
2523
+ var WebVTTDEFAULTSCueParser = /^(DEFAULTS|DEFAULT)\s+\-\-\>\s+(.*)/g;
2524
+ var WebVTTSTYLECueParser = /^(STYLE|STYLES)\s+\-\-\>\s*\n([\s\S]*)/g;
2525
+ var WebVTTCOMMENTCueParser = /^(COMMENT|COMMENTS)\s+\-\-\>\s+(.*)/g;
2526
+
2527
+ return function(subtitleElement,objectCount){
2528
+ var cueDefaults = [];
2529
+
2530
+ var subtitleParts, timeIn, timeOut, html, timeData, subtitlePartIndex, cueSettings = "", id, specialCueData;
2531
+ var timestampMatch, tmpCue;
2532
+
2533
+ // WebVTT Special Cue Logic
2534
+ if ((specialCueData = WebVTTDEFAULTSCueParser.exec(subtitleElement))) {
2535
+ // cueDefaults = specialCueData.slice(2).join("");
2536
+ // cueDefaults = cueDefaults.split(/\s+/g).filter(function(def) { return def && !!def.length; });
2537
+ return null;
2538
+ } else if ((specialCueData = WebVTTSTYLECueParser.exec(subtitleElement))) {
2539
+ return null;
2540
+ } else if ((specialCueData = WebVTTCOMMENTCueParser.exec(subtitleElement))) {
2541
+ return null; // At this stage, we don't want to do anything with these.
2542
+ }
2543
+
2544
+ subtitleParts = subtitleElement.split(/\n/g);
2545
+
2546
+ // Trim off any blank lines (logically, should only be max. one, but loop to be sure)
2547
+ while (!subtitleParts[0].replace(/\s+/ig,"").length && subtitleParts.length > 0) {
2548
+ subtitleParts.shift();
2549
+ }
2550
+
2551
+ if (subtitleParts[0].match(/^\s*[a-z0-9-\_]+\s*$/ig)) {
2552
+ // The identifier becomes the cue ID (when *we* load the cues from file. Programatically created cues can have an ID of whatever.)
2553
+ id = String(subtitleParts.shift().replace(/\s*/ig,""));
2554
+ }
2555
+
2556
+ for (subtitlePartIndex = 0; subtitlePartIndex < subtitleParts.length; subtitlePartIndex ++) {
2557
+ var timestamp = subtitleParts[subtitlePartIndex];
2558
+
2559
+ if ((timestampMatch = WebVTTTimestampParser.exec(timestamp))) {
2560
+
2561
+ // WebVTT
2562
+
2563
+ timeData = timestampMatch.slice(1);
2564
+
2565
+ timeIn = parseInt((timeData[0]||0) * 60 * 60,10) + // Hours
2566
+ parseInt((timeData[1]||0) * 60,10) + // Minutes
2567
+ parseInt((timeData[2]||0),10) + // Seconds
2568
+ parseFloat("0." + (timeData[3]||0)); // MS
2569
+
2570
+ timeOut = parseInt((timeData[4]||0) * 60 * 60,10) + // Hours
2571
+ parseInt((timeData[5]||0) * 60,10) + // Minutes
2572
+ parseInt((timeData[6]||0),10) + // Seconds
2573
+ parseFloat("0." + (timeData[7]||0)); // MS
2574
+ /*
2575
+ if (timeData[8]) {
2576
+ cueSettings = timeData[8];
2577
+ }
2578
+ */
2579
+ }
2580
+
2581
+ // We've got the timestamp - return all the other unmatched lines as the raw subtitle data
2582
+ subtitleParts = subtitleParts.slice(0,subtitlePartIndex).concat(subtitleParts.slice(subtitlePartIndex+1));
2583
+ break;
2584
+ }
2585
+
2586
+ if (!timeIn && !timeOut) {
2587
+ // We didn't extract any time information. Assume the cue is invalid!
2588
+ webshims.warn("couldn't extract time information: "+[timeIn, timeOut, subtitleParts.join("\n"), id].join(' ; '));
2589
+ return null;
2590
+ }
2591
+ /*
2592
+ // Consolidate cue settings, convert defaults to object
2593
+ var compositeCueSettings =
2594
+ cueDefaults
2595
+ .reduce(function(previous,current,index,array){
2596
+ previous[current.split(":")[0]] = current.split(":")[1];
2597
+ return previous;
2598
+ },{});
2599
+
2600
+ // Loop through cue settings, replace defaults with cue specific settings if they exist
2601
+ compositeCueSettings =
2602
+ cueSettings
2603
+ .split(/\s+/g)
2604
+ .filter(function(set) { return set && !!set.length; })
2605
+ // Convert array to a key/val object
2606
+ .reduce(function(previous,current,index,array){
2607
+ previous[current.split(":")[0]] = current.split(":")[1];
2608
+ return previous;
2609
+ },compositeCueSettings);
2610
+
2611
+ // Turn back into string like the TextTrackCue constructor expects
2612
+ cueSettings = "";
2613
+ for (var key in compositeCueSettings) {
2614
+ if (compositeCueSettings.hasOwnProperty(key)) {
2615
+ cueSettings += !!cueSettings.length ? " " : "";
2616
+ cueSettings += key + ":" + compositeCueSettings[key];
2617
+ }
2618
+ }
2619
+ */
2620
+ // The remaining lines are the subtitle payload itself (after removing an ID if present, and the time);
2621
+ html = subtitleParts.join("\n");
2622
+ tmpCue = new TextTrackCue(timeIn, timeOut, html);
2623
+ if(id){
2624
+ tmpCue.id = id;
2625
+ }
2626
+ return tmpCue;
2627
+ };
2628
+ })();
2629
+
2630
+ mediaelement.parseCaptions = function(captionData, track, complete) {
2631
+ var subtitles = mediaelement.createCueList();
2632
+ var cue, lazyProcess, regWevVTT;
2633
+ var startDate;
2634
+ var isWEBVTT;
2635
+ if (captionData) {
2636
+
2637
+ regWevVTT = /^WEBVTT(\s*FILE)?/ig;
2638
+
2639
+ lazyProcess = function(i, len){
2640
+
2641
+ for(; i < len; i++){
2642
+ cue = captionData[i];
2643
+ if(regWevVTT.test(cue)){
2644
+ isWEBVTT = true;
2645
+ } else if(cue.replace(/\s*/ig,"").length){
2646
+ if(!isWEBVTT){
2647
+ webshims.error('please use WebVTT format. This is the standard');
2648
+ complete(null);
2649
+ break;
2650
+ }
2651
+ cue = mediaelement.parseCaptionChunk(cue, i);
2652
+ if(cue){
2653
+ track.addCue(cue);
2654
+ }
2655
+ }
2656
+ if(startDate < (new Date().getTime()) - 30){
2657
+ i++;
2658
+ setTimeout(function(){
2659
+ startDate = new Date().getTime();
2660
+ lazyProcess(i, len);
2661
+ }, 90);
2662
+
2663
+ break;
2664
+ }
2665
+ }
2666
+ if(i >= len){
2667
+ if(!isWEBVTT){
2668
+ webshims.error('please use WebVTT format. This is the standard');
2669
+ }
2670
+ complete(track.cues);
2671
+ }
2672
+ };
2673
+
2674
+ captionData = captionData.replace(/\r\n/g,"\n");
2675
+
2676
+ setTimeout(function(){
2677
+ captionData = captionData.replace(/\r/g,"\n");
2678
+ setTimeout(function(){
2679
+ startDate = new Date().getTime();
2680
+ captionData = captionData.split(/\n\n+/g);
2681
+ lazyProcess(0, captionData.length);
2682
+ }, 9);
2683
+ }, 9);
2684
+
2685
+ } else {
2686
+ webshims.error("Required parameter captionData not supplied.");
2687
+ }
2688
+ };
2689
+
2690
+
2691
+ mediaelement.createTrackList = function(mediaelem, baseData){
2692
+ baseData = baseData || webshims.data(mediaelem, 'mediaelementBase') || webshims.data(mediaelem, 'mediaelementBase', {});
2693
+ if(!baseData.textTracks){
2694
+ baseData.textTracks = [];
2695
+ webshims.defineProperties(baseData.textTracks, {
2696
+ onaddtrack: {value: null},
2697
+ onremovetrack: {value: null}
2698
+ });
2699
+ createEventTarget(baseData.textTracks);
2700
+ }
2701
+ return baseData.textTracks;
2702
+ };
2703
+
2704
+ if(!Modernizr.track){
2705
+ webshims.defineNodeNamesBooleanProperty(['track'], 'default');
2706
+ webshims.reflectProperties(['track'], ['srclang', 'label']);
2707
+
2708
+ webshims.defineNodeNameProperties('track', {
2709
+ src: {
2710
+ //attr: {},
2711
+ reflect: true,
2712
+ propType: 'src'
2713
+ }
2714
+ });
2715
+ }
2716
+
2717
+ webshims.defineNodeNameProperties('track', {
2718
+ kind: {
2719
+ attr: Modernizr.track ? {
2720
+ set: function(value){
2721
+ var trackData = webshims.data(this, 'trackData');
2722
+ this.setAttribute('data-kind', value);
2723
+ if(trackData){
2724
+ trackData.attrKind = value;
2725
+ }
2726
+ },
2727
+ get: function(){
2728
+ var trackData = webshims.data(this, 'trackData');
2729
+ if(trackData && ('attrKind' in trackData)){
2730
+ return trackData.attrKind;
2731
+ }
2732
+ return this.getAttribute('kind');
2733
+ }
2734
+ } : {},
2735
+ reflect: true,
2736
+ propType: 'enumarated',
2737
+ defaultValue: 'subtitles',
2738
+ limitedTo: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata']
2739
+ }
2740
+ });
2741
+
2742
+ $.each(copyProps, function(i, copyProp){
2743
+ var name = copyName[copyProp] || copyProp;
2744
+ webshims.onNodeNamesPropertyModify('track', copyProp, function(){
2745
+ var trackData = webshims.data(this, 'trackData');
2746
+ var track = this;
2747
+ if(trackData){
2748
+ if(copyProp == 'kind'){
2749
+ refreshTrack(this, trackData);
2750
+ }
2751
+ if(!supportTrackMod){
2752
+ trackData.track[name] = $.prop(this, copyProp);
2753
+ }
2754
+ clearTimeout(trackData.changedTrackPropTimer);
2755
+ trackData.changedTrackPropTimer = setTimeout(function(){
2756
+ $(track).trigger('updatesubtitlestate');
2757
+ }, 1);
2758
+ }
2759
+ });
2760
+ });
2761
+
2762
+
2763
+ webshims.onNodeNamesPropertyModify('track', 'src', function(val){
2764
+ if(val){
2765
+ var data = webshims.data(this, 'trackData');
2766
+ var media;
2767
+ if(data){
2768
+ media = $(this).closest('video, audio');
2769
+ if(media[0]){
2770
+ mediaelement.loadTextTrack(media, this, data);
2771
+ }
2772
+ }
2773
+ }
2774
+
2775
+ });
2776
+
2777
+ //
2778
+
2779
+ webshims.defineNodeNamesProperties(['track'], {
2780
+ ERROR: {
2781
+ value: 3
2782
+ },
2783
+ LOADED: {
2784
+ value: 2
2785
+ },
2786
+ LOADING: {
2787
+ value: 1
2788
+ },
2789
+ NONE: {
2790
+ value: 0
2791
+ },
2792
+ readyState: {
2793
+ get: function(){
2794
+ return ($.prop(this, 'track') || {readyState: 0}).readyState;
2795
+ },
2796
+ writeable: false
2797
+ },
2798
+ track: {
2799
+ get: function(){
2800
+ return mediaelement.createTextTrack($(this).closest('audio, video')[0], this);
2801
+ },
2802
+ writeable: false
2803
+ }
2804
+ }, 'prop');
2805
+
2806
+ webshims.defineNodeNamesProperties(['audio', 'video'], {
2807
+ textTracks: {
2808
+ get: function(){
2809
+ var media = this;
2810
+ var baseData = webshims.data(media, 'mediaelementBase') || webshims.data(media, 'mediaelementBase', {});
2811
+ var tracks = mediaelement.createTrackList(media, baseData);
2812
+ if(!baseData.blockTrackListUpdate){
2813
+ updateMediaTrackList.call(media, baseData, tracks);
2814
+ }
2815
+ return tracks;
2816
+ },
2817
+ writeable: false
2818
+ },
2819
+ addTextTrack: {
2820
+ value: function(kind, label, lang){
2821
+ var textTrack = mediaelement.createTextTrack(this, {
2822
+ kind: kind || '',
2823
+ label: label || '',
2824
+ srclang: lang || ''
2825
+ });
2826
+ var baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {});
2827
+ if (!baseData.scriptedTextTracks) {
2828
+ baseData.scriptedTextTracks = [];
2829
+ }
2830
+ baseData.scriptedTextTracks.push(textTrack);
2831
+ updateMediaTrackList.call(this);
2832
+ return textTrack;
2833
+ }
2834
+ }
2835
+ }, 'prop');
2836
+
2837
+
2838
+ $(document).bind('emptied ended updatetracklist', function(e){
2839
+ if($(e.target).is('audio, video')){
2840
+ var baseData = webshims.data(e.target, 'mediaelementBase');
2841
+ if(baseData){
2842
+ clearTimeout(baseData.updateTrackListTimer);
2843
+ baseData.updateTrackListTimer = setTimeout(function(){
2844
+ updateMediaTrackList.call(e.target, baseData);
2845
+ }, 0);
2846
+ }
2847
+ }
2848
+ });
2849
+
2850
+ var getNativeReadyState = function(trackElem, textTrack){
2851
+ return textTrack.readyState || trackElem.readyState;
2852
+ };
2853
+
2854
+ webshims.addReady(function(context, insertedElement){
2855
+ var insertedMedia = insertedElement.filter('video, audio, track').closest('audio, video');
2856
+ $('video, audio', context)
2857
+ .add(insertedMedia)
2858
+ .each(function(){
2859
+ updateMediaTrackList.call(this);
2860
+ })
2861
+ .each(function(){
2862
+ if(Modernizr.track){
2863
+ var shimedTextTracks = $.prop(this, 'textTracks');
2864
+ var origTextTracks = this.textTracks;
2865
+ if(shimedTextTracks.length != origTextTracks.length){
2866
+ webshims.error("textTracks couldn't be copied");
2867
+ }
2868
+
2869
+ $('track', this)
2870
+ .each(function(){
2871
+ var shimedTrack = $.prop(this, 'track');
2872
+ var origTrack = this.track;
2873
+ var kind;
2874
+ var readyState;
2875
+ if(origTrack){
2876
+ kind = $.prop(this, 'kind');
2877
+ readyState = getNativeReadyState(this, origTrack);
2878
+ if (origTrack.mode || readyState) {
2879
+ shimedTrack.mode = origTrack.mode;
2880
+ }
2881
+ //disable track from showing + remove UI
2882
+ if(kind != 'descriptions'){
2883
+ origTrack.mode = (typeof origTrack.mode == 'string') ? 'disabled' : 0;
2884
+ this.kind = 'metadata';
2885
+ $(this).attr({kind: kind});
2886
+ }
2887
+
2888
+ }
2889
+ })
2890
+ .bind('load error', function(e){
2891
+ if(e.originalEvent){
2892
+ e.stopImmediatePropagation();
2893
+ }
2894
+ })
2895
+ ;
2896
+ }
2897
+ })
2898
+ ;
2899
+ insertedMedia.each(function(){
2900
+ var media = this;
2901
+ var baseData = webshims.data(media, 'mediaelementBase');
2902
+ if(baseData){
2903
+ clearTimeout(baseData.updateTrackListTimer);
2904
+ baseData.updateTrackListTimer = setTimeout(function(){
2905
+ updateMediaTrackList.call(media, baseData);
2906
+ }, 9);
2907
+ }
2908
+ });
2909
+ });
2910
+
2911
+ if(Modernizr.track){
2912
+ $('video, audio').trigger('trackapichange');
2913
+ }
2914
+
2863
2915
  });