webshims-rails 1.12.3 → 1.12.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/lib/webshims-rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/webshims/polyfiller.js +75 -31
  4. data/vendor/assets/javascripts/webshims/shims/color-picker.js +14 -14
  5. data/vendor/assets/javascripts/webshims/shims/combos/1.js +83 -459
  6. data/vendor/assets/javascripts/webshims/shims/combos/10.js +92 -69
  7. data/vendor/assets/javascripts/webshims/shims/combos/11.js +90 -54
  8. data/vendor/assets/javascripts/webshims/shims/combos/12.js +104 -494
  9. data/vendor/assets/javascripts/webshims/shims/combos/13.js +66 -228
  10. data/vendor/assets/javascripts/webshims/shims/combos/14.js +2 -0
  11. data/vendor/assets/javascripts/webshims/shims/combos/15.js +42 -40
  12. data/vendor/assets/javascripts/webshims/shims/combos/16.js +105 -494
  13. data/vendor/assets/javascripts/webshims/shims/combos/17.js +90 -54
  14. data/vendor/assets/javascripts/webshims/shims/combos/18.js +90 -54
  15. data/vendor/assets/javascripts/webshims/shims/combos/19.js +123 -471
  16. data/vendor/assets/javascripts/webshims/shims/combos/2.js +85 -474
  17. data/vendor/assets/javascripts/webshims/shims/combos/20.js +85 -205
  18. data/vendor/assets/javascripts/webshims/shims/combos/21.js +103 -45
  19. data/vendor/assets/javascripts/webshims/shims/combos/22.js +41 -40
  20. data/vendor/assets/javascripts/webshims/shims/combos/23.js +63 -454
  21. data/vendor/assets/javascripts/webshims/shims/combos/24.js +52 -36
  22. data/vendor/assets/javascripts/webshims/shims/combos/25.js +123 -471
  23. data/vendor/assets/javascripts/webshims/shims/combos/26.js +2 -15
  24. data/vendor/assets/javascripts/webshims/shims/combos/27.js +38 -266
  25. data/vendor/assets/javascripts/webshims/shims/combos/28.js +20 -20
  26. data/vendor/assets/javascripts/webshims/shims/combos/3.js +24 -20
  27. data/vendor/assets/javascripts/webshims/shims/combos/30.js +24 -20
  28. data/vendor/assets/javascripts/webshims/shims/combos/31.js +22 -20
  29. data/vendor/assets/javascripts/webshims/shims/combos/4.js +4 -15
  30. data/vendor/assets/javascripts/webshims/shims/combos/5.js +90 -54
  31. data/vendor/assets/javascripts/webshims/shims/combos/6.js +90 -54
  32. data/vendor/assets/javascripts/webshims/shims/combos/7.js +87 -474
  33. data/vendor/assets/javascripts/webshims/shims/combos/8.js +87 -474
  34. data/vendor/assets/javascripts/webshims/shims/combos/9.js +92 -69
  35. data/vendor/assets/javascripts/webshims/shims/combos/99.js +1724 -0
  36. data/vendor/assets/javascripts/webshims/shims/dom-extend.js +2 -15
  37. data/vendor/assets/javascripts/webshims/shims/form-core.js +19 -4
  38. data/vendor/assets/javascripts/webshims/shims/form-datalist-lazy.js +39 -5
  39. data/vendor/assets/javascripts/webshims/shims/form-message.js +2 -0
  40. data/vendor/assets/javascripts/webshims/shims/form-number-date-ui.js +69 -37
  41. data/vendor/assets/javascripts/webshims/shims/form-shim-extend.js +18 -20
  42. data/vendor/assets/javascripts/webshims/shims/form-shim-extend2.js +34 -16
  43. data/vendor/assets/javascripts/webshims/shims/form-validation.js +12 -9
  44. data/vendor/assets/javascripts/webshims/shims/form-validators.js +21 -5
  45. data/vendor/assets/javascripts/webshims/shims/forms-picker.js +16 -13
  46. data/vendor/assets/javascripts/webshims/shims/geolocation.js +3 -3
  47. data/vendor/assets/javascripts/webshims/shims/jajax.js +1262 -0
  48. data/vendor/assets/javascripts/webshims/shims/jme/b.js +576 -0
  49. data/vendor/assets/javascripts/webshims/shims/jme/c.js +1148 -0
  50. data/vendor/assets/javascripts/webshims/shims/jme/controls.css +373 -0
  51. data/vendor/assets/javascripts/webshims/shims/jme/controls.scss +711 -0
  52. data/vendor/assets/javascripts/webshims/shims/jme/jme.eot +0 -0
  53. data/vendor/assets/javascripts/webshims/shims/jme/jme.svg +36 -0
  54. data/vendor/assets/javascripts/webshims/shims/jme/jme.ttf +0 -0
  55. data/vendor/assets/javascripts/webshims/shims/jme/jme.woff +0 -0
  56. data/vendor/assets/javascripts/webshims/shims/jpicker/jpicker.css +16 -18
  57. data/vendor/assets/javascripts/webshims/shims/mediaelement-core.js +25 -188
  58. data/vendor/assets/javascripts/webshims/shims/mediaelement-jaris.js +58 -2
  59. data/vendor/assets/javascripts/webshims/shims/mediaelement-native-fix.js +130 -66
  60. data/vendor/assets/javascripts/webshims/shims/range-ui.js +21 -17
  61. data/vendor/assets/javascripts/webshims/shims/sizzle.js +1634 -1613
  62. data/vendor/assets/javascripts/webshims/shims/styles/forms-ext.css +5 -5
  63. data/vendor/assets/javascripts/webshims/shims/styles/scss/shim.scss +5 -1
  64. data/vendor/assets/javascripts/webshims/shims/styles/shim.css +13 -9
  65. data/vendor/assets/javascripts/webshims/shims/swfmini-embed.js +136 -0
  66. data/vendor/assets/javascripts/webshims/shims/swfmini.js +38 -266
  67. data/vendor/assets/javascripts/webshims/shims/track-ui.js +1 -3
  68. data/vendor/assets/javascripts/webshims/shims/track.js +41 -40
  69. metadata +13 -2
@@ -616,7 +616,7 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
616
616
  $.each({ Height: "getHeight", Width: "getWidth" }, function(name, type){
617
617
  var body = document.body;
618
618
  var doc = document.documentElement;
619
- docObserve[type] = function(){
619
+ docObserve[type] = function (){
620
620
  return Math.max(
621
621
  body[ "scroll" + name ], doc[ "scroll" + name ],
622
622
  body[ "offset" + name ], doc[ "offset" + name ],
@@ -631,24 +631,11 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
631
631
  this._create();
632
632
  this.height = docObserve.getHeight();
633
633
  this.width = docObserve.getWidth();
634
- setInterval(this.test, 600);
634
+ setInterval(this.test, 999);
635
635
  $(this.test);
636
636
  webshims.ready('WINDOWLOAD', this.test);
637
637
  $(document).on('updatelayout.webshim pageinit popupafteropen panelbeforeopen tabsactivate collapsibleexpand shown.bs.modal shown.bs.collapse slid.bs.carousel', this.handler);
638
638
  $(window).on('resize', this.handler);
639
- (function(){
640
- var oldAnimate = $.fn.animate;
641
- var animationTimer;
642
-
643
- $.fn.animate = function(){
644
- clearTimeout(animationTimer);
645
- animationTimer = setTimeout(function(){
646
- docObserve.test();
647
- }, 99);
648
-
649
- return oldAnimate.apply(this, arguments);
650
- };
651
- })();
652
639
  }
653
640
  }
654
641
  };
@@ -1144,8 +1131,8 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
1144
1131
  })();
1145
1132
  });
1146
1133
  ;(function($){
1147
-
1148
- var id = 0;
1134
+ "use strict";
1135
+
1149
1136
  var isNumber = function(string){
1150
1137
  return (typeof string == 'number' || (string && string == string * 1));
1151
1138
  };
@@ -1160,7 +1147,7 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
1160
1147
  _create: function(){
1161
1148
  var i;
1162
1149
 
1163
- this.element.addClass('ws-range').attr({role: 'slider'}).append('<span class="ws-range-min ws-range-progress" /><span class="ws-range-rail ws-range-track"><span class="ws-range-thumb"><span><span data-value="" data-valuetext="" /></span></span></span>');
1150
+ this.element.addClass(this.options.baseClass || 'ws-range').attr({role: 'slider'}).append('<span class="ws-range-min ws-range-progress" /><span class="ws-range-rail ws-range-track"><span class="ws-range-thumb"><span><span data-value="" data-valuetext="" /></span></span></span>');
1164
1151
  this.trail = $('.ws-range-track', this.element);
1165
1152
  this.range = $('.ws-range-progress', this.element);
1166
1153
  this.thumb = $('.ws-range-thumb', this.trail);
@@ -1345,10 +1332,12 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
1345
1332
  },
1346
1333
  min: function(val){
1347
1334
  this.options.min = retDefault(val, 0);
1335
+ this.element.attr('aria-valuemin', this.options.min);
1348
1336
  this.value(this.options.value, true);
1349
1337
  },
1350
1338
  max: function(val){
1351
1339
  this.options.max = retDefault(val, 100);
1340
+ this.element.attr('aria-valuemax', this.options.max);
1352
1341
  this.value(this.options.value, true);
1353
1342
  },
1354
1343
  step: function(val){
@@ -1521,8 +1510,6 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
1521
1510
  if(e.target == window){remove();}
1522
1511
  };
1523
1512
  var add = function(e){
1524
- var outerWidth;
1525
-
1526
1513
  if(isActive || (e.type == 'touchstart' && (!e.originalEvent || !e.originalEvent.touches || e.originalEvent.touches.length != 1))){
1527
1514
  return;
1528
1515
  }
@@ -1537,7 +1524,6 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
1537
1524
  leftOffset = that.element.offset();
1538
1525
  widgetUnits = that.element[that.dirs.innerWidth]();
1539
1526
  if(!widgetUnits || !leftOffset){return;}
1540
- outerWidth = that.thumb[that.dirs.outerWidth]();
1541
1527
  leftOffset = leftOffset[that.dirs.pos];
1542
1528
  widgetUnits = 100 / widgetUnits;
1543
1529
 
@@ -1654,8 +1640,13 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
1654
1640
  webshims.ready('WINDOWLOAD', function(){
1655
1641
  webshims.ready('dom-support', function(){
1656
1642
  if ($.fn.onWSOff) {
1657
- that.element.onWSOff('updateshadowdom', function(){
1643
+ var timer;
1644
+ var update = function(){
1658
1645
  that.updateMetrics();
1646
+ };
1647
+ that.element.onWSOff('updateshadowdom', function(){
1648
+ clearTimeout(timer);
1649
+ timer = setTimeout(update, 100);
1659
1650
  });
1660
1651
  }
1661
1652
  });
@@ -1666,26 +1657,26 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
1666
1657
  }
1667
1658
  },
1668
1659
  posCenter: function(elem, outerWidth){
1669
- var temp;
1660
+ var temp, eS;
1661
+
1670
1662
  if(this.options.calcCenter && (!this._init || this.element[0].offsetWidth)){
1671
1663
  if(!elem){
1672
1664
  elem = this.thumb;
1673
1665
  }
1666
+ eS = elem[0].style;
1674
1667
  if(!outerWidth){
1675
1668
  outerWidth = elem[this.dirs.outerWidth]();
1676
1669
  }
1677
1670
  outerWidth = outerWidth / -2;
1678
- elem.css(this.dirs.marginLeft, outerWidth);
1679
-
1671
+ eS[this.dirs.marginLeft] = outerWidth +'px';
1672
+
1680
1673
  if(this.options.calcTrail && elem[0] == this.thumb[0]){
1681
1674
  temp = this.element[this.dirs.innerHeight]();
1682
- elem.css(this.dirs.marginTop, (elem[this.dirs.outerHeight]() - temp) / -2);
1683
- this.range.css(this.dirs.marginTop, (this.range[this.dirs.outerHeight]() - temp) / -2 );
1675
+ eS[this.dirs.marginTop] = ((elem[this.dirs.outerHeight]() - temp) / -2) + 'px';
1676
+ this.range[0].style[this.dirs.marginTop] = ((this.range[this.dirs.outerHeight]() - temp) / -2 ) +'px';
1684
1677
  outerWidth *= -1;
1685
- this.trail
1686
- .css(this.dirs.left, outerWidth)
1687
- .css(this.dirs.right, outerWidth)
1688
- ;
1678
+ this.trail[0].style[this.dirs.left] = outerWidth +'px';
1679
+ this.trail[0].style[this.dirs.right] = outerWidth +'px';
1689
1680
  }
1690
1681
  }
1691
1682
  },
@@ -1729,7 +1720,7 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
1729
1720
  value: 50,
1730
1721
  input: $.noop,
1731
1722
  change: $.noop,
1732
- _change: $.noop,
1723
+ _change: $.noop,
1733
1724
  showLabels: true,
1734
1725
  options: {},
1735
1726
  calcCenter: true,
@@ -1759,7 +1750,7 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
1759
1750
  if(!curCfg[selectName]){
1760
1751
  var labels = curCfg.date[opts.monthNames] || monthDigits;
1761
1752
  curCfg[selectName] = ('<option value=""></option>')+$.map(monthDigits, function(val, i){
1762
- return '<option value="'+val+'"]>'+labels[i]+'</option>';
1753
+ return '<option value="'+val+'">'+labels[i]+'</option>';
1763
1754
  }).join('');
1764
1755
  }
1765
1756
  return curCfg[selectName];
@@ -2163,8 +2154,12 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
2163
2154
  var names;
2164
2155
  var p = val.split('-');
2165
2156
  if(p[0] && p[1]){
2166
- names = curCfg.date[options.monthNames] || curCfg.date.monthNames;
2167
- p[1] = names[(p[1] * 1) - 1];
2157
+
2158
+ if(!options || !options.monthSelect){
2159
+ names = curCfg.date[options.monthNames] || curCfg.date.monthNames;
2160
+ p[1] = names[(p[1] * 1) - 1];
2161
+ }
2162
+
2168
2163
  if(options && options.splitInput){
2169
2164
  val = [p[0] || '', p[1] || ''];
2170
2165
  } else if(p[1]){
@@ -2357,6 +2352,10 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
2357
2352
  var type = (typeof val == 'object') ? 'valueAsDate' : 'valueAsNumber';
2358
2353
  return input.prop(type, val).prop('value');
2359
2354
  },
2355
+ asDate: function(val){
2356
+ var type = (typeof val == 'number') ? 'valueAsNumber' : 'value';
2357
+ return input.prop(type, val).prop('valueAsDate');
2358
+ },
2360
2359
  isValid: function(val, attrs){
2361
2360
  if(attrs && (attrs.nodeName || attrs.jquery)){
2362
2361
  attrs = {
@@ -2630,6 +2629,7 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
2630
2629
  this.asNumber = helper.asNumber;
2631
2630
  this.asValue = helper.asValue;
2632
2631
  this.isValid = helper.isValid;
2632
+ this.asDate = helper.asDate;
2633
2633
 
2634
2634
 
2635
2635
  wsWidgetProto._create.apply(this, arguments);
@@ -3228,53 +3228,75 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
3228
3228
  return $.css(this, 'display') != 'none';
3229
3229
  };
3230
3230
  var sizeInput = function(data){
3231
- var init;
3231
+ var init, parent, lastWidth, left, right, isRtl, hasButtons;
3232
+ var oriStyleO = data.orig.style;
3233
+ var styleO = data.element[0].style;
3234
+ if($.support.boxSizing == null && !$.isReady){
3235
+ $(function(){
3236
+ parent = data.orig.parentNode;
3237
+ });
3238
+ } else {
3239
+ parent = data.orig.parentNode;
3240
+ }
3232
3241
  var updateStyles = function(){
3233
- $(data.orig).removeClass('ws-important-hide');
3234
- $.style( data.orig, 'display', '' );
3235
- var hasButtons, marginR, marginL, left, right, isRtl;
3242
+ var curWidth, marginR, marginL, assignWidth;
3236
3243
  var correctWidth = 0.8;
3237
- if(!init || data.orig.offsetWidth){
3238
- hasButtons = data.buttonWrapper && data.buttonWrapper.filter(isVisible).length;
3239
-
3240
- isRtl = hasButtons && data.buttonWrapper.css('direction') == 'rtl';
3241
- if(isRtl){
3242
- left = 'Right';
3243
- right = 'Left';
3244
- } else {
3245
- left = 'Left';
3246
- right = 'Right';
3244
+
3245
+ if(parent){
3246
+ curWidth = parent.offsetWidth;
3247
+ }
3248
+
3249
+ if(!init || (curWidth && curWidth != lastWidth)){
3250
+ lastWidth = curWidth;
3251
+ oriStyleO.display = '';
3252
+ styleO.display = 'none';
3253
+
3254
+ if(!init){
3255
+ hasButtons = data.buttonWrapper && data.buttonWrapper.filter(isVisible).length;
3256
+ isRtl = hasButtons && data.buttonWrapper.css('direction') == 'rtl';
3257
+ if(isRtl){
3258
+ left = 'Right';
3259
+ right = 'Left';
3260
+ } else {
3261
+ left = 'Left';
3262
+ right = 'Right';
3263
+ }
3264
+ if(hasButtons){
3265
+ data.buttonWrapper[isRtl ? 'addClass' : 'removeClass']('ws-is-rtl');
3266
+ }
3247
3267
  }
3248
-
3268
+
3249
3269
  marginR = $.css( data.orig, 'margin'+right);
3250
-
3251
- data.element
3252
- .css('margin'+left, $.css( data.orig, 'margin'+left))
3253
- .css('margin'+right, hasButtons ? 0 : marginR)
3254
- ;
3270
+
3271
+ styleO['margin'+left] = $.css( data.orig, 'margin'+left);
3272
+ styleO['margin'+right] = hasButtons ? '0px' : marginR;
3273
+
3255
3274
 
3256
3275
  if(hasButtons){
3257
- data.buttonWrapper[isRtl ? 'addClass' : 'removeClass']('ws-is-rtl');
3276
+
3258
3277
  marginL = (parseInt(data.buttonWrapper.css('margin'+left), 10) || 0);
3259
- data.element.css('padding'+right, '');
3260
-
3278
+ styleO['padding'+right] = '';
3279
+
3261
3280
  if(marginL < 0){
3262
3281
  marginR = (parseInt(marginR, 10) || 0) + ((data.buttonWrapper.outerWidth() + marginL) * -1);
3263
- data.buttonWrapper.css('margin'+right, marginR);
3264
- data.element
3265
- .css('padding'+right, '')
3266
- .css('padding'+right, (parseInt( data.element.css('padding'+right), 10) || 0) + data.buttonWrapper.outerWidth())
3267
- ;
3282
+ data.buttonWrapper[0].style['margin'+right] = marginR+'px';
3283
+
3284
+ styleO['padding'+right] = ((parseInt( data.element.css('padding'+right), 10) || 0) + data.buttonWrapper.outerWidth()) +'px';
3285
+
3268
3286
  } else {
3269
- data.buttonWrapper.css('margin'+right, marginR);
3287
+ data.buttonWrapper[0].style['margin'+right] = marginR;
3270
3288
  correctWidth = data.buttonWrapper.outerWidth(true) + correctWidth;
3271
3289
  }
3272
3290
  }
3273
-
3274
- data.element.outerWidth( $(data.orig).outerWidth() - correctWidth );
3291
+
3292
+ assignWidth = $(data.orig).outerWidth() - correctWidth;
3293
+
3294
+ styleO.display = '';
3295
+ data.element.outerWidth(assignWidth);
3296
+ oriStyleO.display = 'none';
3297
+ init = true;
3275
3298
  }
3276
- init = true;
3277
- $(data.orig).addClass('ws-important-hide');
3299
+
3278
3300
  };
3279
3301
  data.element.onWSOff('updateshadowdom', updateStyles, true);
3280
3302
  };
@@ -3338,6 +3360,7 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
3338
3360
  cNames = $.prop(this, 'className');
3339
3361
  if(opts.classes){
3340
3362
  cNames += ' '+opts.classes;
3363
+ $(this).addClass(opts.classes);
3341
3364
  }
3342
3365
 
3343
3366
  if(opts.splitInput || type == 'range'){
@@ -3410,7 +3433,7 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
3410
3433
  if(opts.calculateWidth){
3411
3434
  sizeInput(data.shim);
3412
3435
  } else {
3413
- $(this).addClass('ws-important-hide');
3436
+ $(this).css('display', 'none');
3414
3437
  }
3415
3438
  }
3416
3439
 
@@ -0,0 +1,1724 @@
1
+ webshims.register('jme', function($, webshims, window, doc, undefined, options){
2
+ "use strict";
3
+ var props = {};
4
+
5
+ var fns = {};
6
+ var allowPreload = false;
7
+ $(window).on('load', function(){
8
+ allowPreload = true;
9
+ var scrollTimer;
10
+ var allow = function(){
11
+ allowPreload = true;
12
+ };
13
+ $(window).on('scroll', function(){
14
+ allowPreload = false;
15
+ clearTimeout(scrollTimer);
16
+ scrollTimer = setTimeout(allow, 999);
17
+ });
18
+ });
19
+
20
+
21
+
22
+ $.jme = {
23
+ version: '2.0.9',
24
+ classNS: '',
25
+ options: {},
26
+ plugins: {},
27
+ data: function(elem, name, value){
28
+ var data = $(elem).data(ns+'jme') || $.data(elem, ns+'jme', {});
29
+ if(value === undefined){
30
+ return (name) ? data[name] : data;
31
+ } else {
32
+ data[name] = value;
33
+ }
34
+ },
35
+ registerPlugin: function(name, plugin){
36
+ this.plugins[name] = plugin;
37
+ if(!plugin.nodeName){
38
+ plugin.nodeName = '';
39
+ }
40
+ if(!plugin.className){
41
+ plugin.className = name;
42
+ }
43
+ },
44
+ defineMethod: function(name, fn){
45
+ fns[name] = fn;
46
+ },
47
+ defineProp: function(name, desc){
48
+ if(!desc){
49
+ desc = {};
50
+ }
51
+ if(!desc.set){
52
+ if(desc.readonly){
53
+ desc.set = function(){
54
+ throw(name +' is readonly');
55
+ };
56
+ } else {
57
+ desc.set = $.noop;
58
+ }
59
+ }
60
+ if(!desc.get){
61
+ desc.get = function(elem){
62
+ return $.jme.data(elem, name);
63
+ };
64
+ }
65
+ props[name] = desc;
66
+ },
67
+ prop: function(elem, name, value){
68
+ if(!props[name]){
69
+ return $.prop(elem, name, value);
70
+ }
71
+ if(value === undefined){
72
+ return props[name].get( elem );
73
+ } else {
74
+ var setValue = props[name].set(elem, value);
75
+ if(setValue === undefined){
76
+ setValue = value;
77
+ }
78
+ if(setValue != 'noDataSet'){
79
+ $.jme.data(elem, name, setValue);
80
+ }
81
+ }
82
+ },
83
+ setText: function(name, text){
84
+ var obj = name;
85
+ if(name && text){
86
+ obj = {};
87
+ obj[name] = text;
88
+ }
89
+ $.each(obj, function(name, text){
90
+ if($.jme.plugins[name]){
91
+ $.jme.plugins[name].text = text;
92
+ }
93
+ });
94
+ }
95
+ };
96
+
97
+ $.fn.jmeProp = function(name, value){
98
+ return $.access( this, $.jme.prop, name, value, arguments.length > 1 );
99
+ };
100
+
101
+ $.fn.jmeFn = function(fn){
102
+ var args = Array.prototype.slice.call( arguments, 1 );
103
+ var ret;
104
+ this.each(function(){
105
+ ret = (fns[fn] || $.prop(this, fn)).apply(this, args);
106
+ if(ret !== undefined){
107
+ return false;
108
+ }
109
+ });
110
+ return (ret !== undefined) ? ret : this;
111
+ };
112
+
113
+
114
+ options = $.extend({selector: '.mediaplayer'}, webshims.cfg.mediaelement.jme);
115
+ webshims.cfg.mediaelement.jme = options;
116
+ var baseSelector = options.selector;
117
+ var pluginSelectors = [];
118
+ var ns = '';
119
+
120
+
121
+ $.jme.initJME = function(context, insertedElement){
122
+ $(baseSelector, context).add(insertedElement.filter(baseSelector)).jmePlayer();
123
+ };
124
+
125
+ var idlStates = {
126
+ emptied: 1,
127
+ pause: 1
128
+ };
129
+
130
+ $.jme.getDOMList = function(attr){
131
+ var list = [];
132
+ if(!attr){
133
+ attr = [];
134
+ }
135
+ if(typeof attr == 'string'){
136
+ attr = attr.split(' ');
137
+ }
138
+ $.each(attr, function(i, id){
139
+ if(id){
140
+ id = document.getElementById(id);
141
+ if(id){
142
+ list.push(id);
143
+ }
144
+ }
145
+ });
146
+ return list;
147
+ };
148
+
149
+ webshims.ready('dom-support', function(){
150
+ if($('<input />').prop('labels')){return;}
151
+ webshims.defineNodeNamesProperty('button, input, keygen, meter, output, progress, select, textarea', 'labels', {
152
+ prop: {
153
+ get: function(){
154
+ var labels = [];
155
+ var id = this.id;
156
+ if(id){
157
+ labels = $('label[for="'+ id +'"]');
158
+ }
159
+ if(!labels[0]) {
160
+ labels = $(this).closest('label', this.form);
161
+ }
162
+ return labels.get();
163
+ },
164
+ writeable: false
165
+ }
166
+ });
167
+ });
168
+
169
+
170
+ $.jme.getButtonText = function(button, classes){
171
+
172
+ var btnTextElem = $('span.jme-text, +label span.jme-text', button);
173
+ var btnLabelElem = button.prop('labels');
174
+
175
+ btnLabelElem = (btnLabelElem && btnLabelElem[0]) ? $(btnLabelElem).eq(0) : false;
176
+
177
+ if(!btnTextElem[0]){
178
+ btnTextElem = btnLabelElem || button;
179
+ }
180
+
181
+ var txt = btnTextElem.text().split('/');
182
+ var title = button.prop('title').split('/');
183
+
184
+ var isCheckbox;
185
+ var doText;
186
+ var doTitle;
187
+ var lastState;
188
+ var txtChangeFn = function(state){
189
+ if(lastState === state){return;}
190
+ lastState = state;
191
+ if(doText){
192
+ btnTextElem.text(txt[state || 0]);
193
+ }
194
+ if(doTitle){
195
+ button.prop('title', txt[state || 0]);
196
+ if (btnLabelElem) {
197
+ btnLabelElem.prop('title', txt[state || 0]);
198
+ }
199
+ }
200
+
201
+ if(classes){
202
+ button
203
+ .removeClass(classes[(state) ? 0 : 1])
204
+ .addClass(classes[state])
205
+ ;
206
+ }
207
+ if(isCheckbox){
208
+ button.prop('checked', !!state);
209
+ (button.data('checkboxradio') || {refresh: $.noop}).refresh();
210
+ }
211
+ };
212
+
213
+ if(txt.length == 2){
214
+ txt[0] = txt[0].trim();
215
+ txt[1] = txt[1].trim();
216
+ doText = true;
217
+ }
218
+ if(title.length == 2){
219
+ title[0] = title[0].trim();
220
+ title[1] = title[1].trim();
221
+ doTitle = true;
222
+ }
223
+
224
+ if (button.is('[type="checkbox"], [type="radio"]')){
225
+ button.prop('checked', function(){
226
+ return this.defaultChecked;
227
+ });
228
+ isCheckbox = true;
229
+ } else if(button.is('a')){
230
+ button.on('click', function(e){
231
+ e.preventDefault();
232
+ });
233
+ }
234
+
235
+ return txtChangeFn;
236
+ };
237
+
238
+ $.fn.jmePlayer = function(opts){
239
+
240
+ return this.each(function(){
241
+ if(opts){
242
+ $.jme.data(this, $.extend(true, {}, opts));
243
+ }
244
+
245
+ var mediaUpdateFn, init, canPlay, removeCanPlay, canplayTimer, needPreload, playerSize;
246
+ var media = $('audio, video', this).filter(':first');
247
+ var base = $(this);
248
+
249
+ var jmeData = $.jme.data(this);
250
+ var mediaData = $.jme.data(media[0]);
251
+
252
+
253
+ base.addClass(media.prop('nodeName').toLowerCase()+'player');
254
+ mediaData.player = base;
255
+ mediaData.media = media;
256
+ if(!jmeData.media){
257
+ init = true;
258
+ needPreload = !media.prop('autoplay');
259
+
260
+ removeCanPlay = function(){
261
+ media.off('canplay', canPlay);
262
+ clearTimeout(canplayTimer);
263
+ };
264
+ canPlay = function(){
265
+ var state = ($.prop(this, 'paused')) ? 'idle' : 'playing';
266
+ base.attr('data-state', state);
267
+ };
268
+ mediaUpdateFn = function(e){
269
+ var state = e.type;
270
+ var readyState;
271
+ var paused;
272
+
273
+ removeCanPlay();
274
+
275
+ if(state == 'ended' || $.prop(this, 'ended')){
276
+ state = 'ended';
277
+ } else if(state == 'waiting'){
278
+
279
+ if($.prop(this, 'readyState') > 2){
280
+ state = '';
281
+ } else {
282
+ canplayTimer = setTimeout(function(){
283
+ if(media.prop('readyState') > 2){
284
+ canPlay();
285
+ }
286
+ }, 9);
287
+ media.on('canPlay', canPlay);
288
+ }
289
+
290
+ } else if(idlStates[state]){
291
+ state = 'idle';
292
+ } else {
293
+ readyState = $.prop(this, 'readyState');
294
+ paused = $.prop(this, 'paused');
295
+ if(!paused && readyState < 3){
296
+ state = 'waiting';
297
+ } else if(!paused && readyState > 2){
298
+ state = 'playing';
299
+ } else {
300
+ state = 'idle';
301
+ }
302
+ }
303
+
304
+ if(state == 'idle' && base._seekpause){
305
+ state = false;
306
+ }
307
+ if(state){
308
+ base.attr('data-state', state);
309
+ }
310
+ };
311
+
312
+ playerSize = (function(){
313
+ var lastSize;
314
+ var sizes = [
315
+ {size: 380, name: 'x-small'},
316
+ {size: 490, name: 'small'},
317
+ {size: 756, name: 'medium'},
318
+ {size: 1024, name: 'large'}
319
+ ];
320
+
321
+ var len = sizes.length;
322
+ return function(){
323
+ var size = 'x-large';
324
+ var i = 0;
325
+ var width = base.outerWidth();
326
+ for(; i < len; i++){
327
+ if(sizes[i].size >= width){
328
+ size = sizes[i].name;
329
+ break;
330
+ }
331
+ }
332
+ if(lastSize != size){
333
+ lastSize = size;
334
+ base.attr('data-playersize', size);
335
+ }
336
+ };
337
+ })();
338
+ jmeData.media = media;
339
+ jmeData.player = base;
340
+ media
341
+ .on('ended', function(){
342
+ removeCanPlay();
343
+ media.jmeFn('pause');
344
+ if(!media.prop('autoplay') && !media.prop('loop') && !media.hasClass('no-reload')){
345
+ media.jmeFn('load');
346
+ }
347
+ })
348
+ .on('emptied waiting canplay canplaythrough playing ended pause mediaerror', mediaUpdateFn)
349
+ .on('volumechange updateJMEState', function(){
350
+ var volume = $.prop(this, 'volume');
351
+ base[!volume || $.prop(this, 'muted') ? 'addClass' : 'removeClass'](ns +'state-muted');
352
+
353
+ if(volume < 0.01){
354
+ volume = 'no';
355
+ } else if(volume < 0.36){
356
+ volume = 'low';
357
+ } else if(volume < 0.7){
358
+ volume = 'medium';
359
+ } else {
360
+ volume = 'high';
361
+ }
362
+ base.attr('data-volume', volume);
363
+ })
364
+ .on('emptied', function(e){
365
+ if(e.type == 'emptied'){
366
+ needPreload = !media.prop('autoplay');
367
+ }
368
+ })
369
+ ;
370
+
371
+ base
372
+ .on({
373
+ useractive: function(){
374
+ base.attr('data-useractivity', 'true');
375
+ }
376
+ })
377
+ .on('userinactive', {idletime: 3500}, function(){
378
+ base.attr('data-useractivity', 'false');
379
+ })
380
+ .triggerHandler('userinactive')
381
+ ;
382
+
383
+ playerSize();
384
+ webshims.ready('dom-support', function(){
385
+ base.onWSOff('updateshadowdom', playerSize);
386
+ webshims.addShadowDom();
387
+ });
388
+ if(mediaUpdateFn){
389
+ media.on('updateJMEState', mediaUpdateFn).triggerHandler('updateJMEState');
390
+ }
391
+ }
392
+ });
393
+ };
394
+
395
+
396
+ $.jme.defineProp('isPlaying', {
397
+ get: function(elem){
398
+ return (!$.prop(elem, 'ended') && !$.prop(elem, 'paused') && $.prop(elem, 'readyState') > 1 && !$.data(elem, 'mediaerror'));
399
+ },
400
+ readonly: true
401
+ });
402
+
403
+ $.jme.defineProp('player', {
404
+ readonly: true
405
+ });
406
+
407
+ $.jme.defineProp('media', {
408
+ readonly: true
409
+ });
410
+
411
+ $.jme.defineProp('srces', {
412
+ get: function(elem){
413
+ var srces;
414
+ var data = $.jme.data(elem);
415
+ var src = data.media.prop('src');
416
+ if(src){
417
+ return [{src: src}];
418
+ }
419
+ srces = $.map($('source', data.media).get(), function(source){
420
+ var src = {
421
+ src: $.prop(source, 'src')
422
+ };
423
+ var tmp = $.attr(source, 'media');
424
+ if(tmp){
425
+ src.media = tmp;
426
+ }
427
+ tmp = $.attr(source, 'type');
428
+ if(tmp){
429
+ src.type = tmp;
430
+ }
431
+ return src;
432
+ });
433
+ return srces;
434
+ },
435
+ set: function(elem, srces){
436
+ var data = $.jme.data(elem);
437
+
438
+ var setSrc = function(i, src){
439
+ if(typeof src == 'string'){
440
+ src = {src: src};
441
+ }
442
+ $(document.createElement('source')).attr(src).appendTo(data.media);
443
+ };
444
+ data.media.removeAttr('src').find('source').remove();
445
+ if($.isArray(srces)){
446
+ $.each(srces, setSrc);
447
+ } else {
448
+ setSrc(0, srces);
449
+ }
450
+ data.media.jmeFn('load');
451
+ return 'noDataSet';
452
+ }
453
+ });
454
+
455
+ $.jme.defineMethod('togglePlay', function(){
456
+ $(this).jmeFn( ( props.isPlaying.get(this) ) ? 'pause' : 'play' );
457
+ });
458
+
459
+
460
+ $.jme.defineMethod('addControls', function(controls){
461
+ var data = $.jme.data(this) || {};
462
+
463
+ if(!data.media){return;}
464
+ var oldControls = $.jme.data(data.player[0], 'controlElements') || $([]);
465
+ controls = $(controls);
466
+ $.each($.jme.plugins, function(name, plugin){
467
+ controls
468
+ .filter('.'+plugin.className)
469
+ .add(controls.find('.'+plugin.className))
470
+ .each(function(){
471
+ var control = $(this);
472
+ var options = $.jme.data(this);
473
+ options.player = data.player;
474
+ options.media = data.media;
475
+ if(options.rendered){return;}
476
+ options.rendered = true;
477
+ if(plugin.options){
478
+ $.each(plugin.options, function(option, value){
479
+ if(!(option in options)){
480
+ options[option] = value;
481
+ }
482
+ });
483
+ }
484
+ plugin._create(control, data.media, data.player, options);
485
+ control = null;
486
+ })
487
+ ;
488
+ });
489
+
490
+ $.jme.data(data.player[0], 'controlElements', oldControls.add(controls));
491
+
492
+ data.player.triggerHandler('controlsadded');
493
+ });
494
+
495
+
496
+
497
+
498
+ (function(){
499
+ var activity = {
500
+ add: function(elem, cfg, name){
501
+ var data = $.data(elem, 'jmeuseractivity') || $.data(elem, 'jmeuseractivity', {idletime: 2500, idle: true, trigger: {}}),
502
+ jElm = $(elem),
503
+ setInactive = function(){
504
+ if(!data.idle){
505
+ data.idle = true;
506
+ if ( data.trigger.userinactive ) {
507
+ jElm.trigger('userinactive');
508
+ }
509
+ }
510
+ },
511
+ x, y,
512
+ setActive = function(e){
513
+ if(!e || (e.type === 'mousemove' && e.pageX === x && e.pageY === y)){return;}
514
+ if(e.type === 'mousemove'){
515
+ x = e.pageX;
516
+ y = e.pageY;
517
+ }
518
+ if(data.idleTimer){
519
+ clearTimeout(data.idleTimer);
520
+ }
521
+ data.idleTimer = setTimeout(setInactive, data.idletime);
522
+ if(data.idle){
523
+ data.idle = false;
524
+ if( data.trigger.useractive ){
525
+ jElm.trigger('useractive');
526
+ }
527
+ }
528
+ }
529
+ ;
530
+
531
+ data.idletime = (cfg || {}).idletime || data.idletime;
532
+ if(cfg && 'idle' in cfg){
533
+ data.idle = cfg.idle;
534
+ }
535
+ data.trigger[name] = true;
536
+
537
+ if(!data.bound){
538
+ jElm
539
+ .on('mouseleave.jmeuseractivity', setInactive)
540
+ .on('mousemove.jmeuseractivity focusin.jmeuseractivity mouseenter.jmeuseractivity keydown.jmeuseractivity keyup.jmeuseractivity mousedown.jmeuseractivity', setActive)
541
+ ;
542
+ data.bound = true;
543
+ }
544
+ if(!data.idle){
545
+ setActive({type: 'initunidled'});
546
+ }
547
+ },
548
+ remove: function(elem, name){
549
+ var data = $.data(elem, 'jmeuseractivity') || $.data(elem, 'jmeuseractivity', {idletime: 2500, idle: true, trigger: {}});
550
+ data.trigger[name] = false;
551
+ if(!data.trigger.useractive && !data.trigger.userinactive){
552
+ $(elem).off('.jmeuseractivity');
553
+ data.bound = false;
554
+ }
555
+ }
556
+ };
557
+ $.each(['useractive', 'userinactive'], function(i, name){
558
+ $.event.special[name] = {
559
+ setup: function(cfg){
560
+ activity.add(this, cfg, name);
561
+ },
562
+ teardown: function(){
563
+ activity.remove(this, name);
564
+ }
565
+ };
566
+ });
567
+ })();
568
+
569
+
570
+ webshims.ready('mediaelement', function(){
571
+ webshims.addReady($.jme.initJME);
572
+ });
573
+ });
574
+
575
+
576
+
577
+ ;webshims.register('mediacontrols', function($, webshims, window, doc, undefined, options){
578
+ "use strict";
579
+ var pseudoClasses = 'pseudoClasses';
580
+ var baseSelector = webshims.cfg.mediaelement.jme.selector;
581
+
582
+ var playStates = {
583
+ play: 1,
584
+ playing: 1
585
+ };
586
+
587
+ var pauseStates = {
588
+ pause: 1,
589
+ ended: 1
590
+ };
591
+
592
+ var loadRange = function(){
593
+ webshims.loader.loadList(['range-ui']);
594
+ };
595
+ var onSliderReady = function(fn){
596
+ loadRange();
597
+ webshims.ready('range-ui', fn);
598
+ };
599
+
600
+ var btnStructure = '<button class="{%class%}" type="button" aria-label="{%text%}"></button>';
601
+ var defaultStructure = '<div class="{%class%}"></div>';
602
+ var slideStructure = '<div class="{%class%}"></div>';
603
+ var ns = $.jme.classNS;
604
+ var noVolumeClass = (function(){
605
+ var audio;
606
+ var ret = '';
607
+ if(typeof window.Audio == 'function'){
608
+ audio = new Audio();
609
+ audio.volume = 0.55;
610
+ ret = audio.volume = 0.55 ? '' : ' no-volume-api';
611
+ }
612
+ return ret;
613
+ })();
614
+
615
+
616
+
617
+
618
+ $.jme.defineProp('controlbar', {
619
+ set: function(elem, value){
620
+ value = !!value;
621
+ var data = $.jme.data(elem);
622
+ var controlBar = $('div.jme-mediaoverlay, div.jme-controlbar', data.player);
623
+ var mediaControls = $.jme.plugins["media-controls"] ;
624
+ var structure = '';
625
+ var controls;
626
+ if(value && !controlBar[0]){
627
+ if(data._controlbar){
628
+ data._controlbar.appendTo(data.player);
629
+ } else {
630
+ data.media.prop('controls', false);
631
+ $.each(mediaControls.pluginOrder, function(i, name){
632
+ var plugin = $.jme.plugins[name];
633
+ if(plugin && plugin.structure){
634
+ structure += plugin.structure.replace('{%class%}', ns+name).replace('{%text%}', plugin.text || '');
635
+ } else if(name){
636
+ structure += name;
637
+ }
638
+ });
639
+ data._controlbar = $( mediaControls.barStructure );
640
+ controlBar = data._controlbar.find('div.jme-cb-box').addClass(ns+'media-controls');
641
+ controls = data._controlbar.filter('.jme-media-overlay').addClass(ns+'play-pause');
642
+ controls = controls.add( controlBar );
643
+ controls = controls.add( $(structure).appendTo(controlBar) );
644
+ data._controlbar.appendTo(data.player);
645
+ data.player.jmeFn('addControls', controls);
646
+ }
647
+
648
+ } else if(!value) {
649
+ controlBar.detach();
650
+ }
651
+ controlBar = null;
652
+ controls = null;
653
+ return value;
654
+ }
655
+ });
656
+
657
+ $.jme.defineMethod('updateControlbar', function(){
658
+ var timeSlider = $('.'+ $.jme.classNS +'time-slider', this);
659
+ if(timeSlider[0] && timeSlider.css('position') !== 'absolute'){
660
+ var width;
661
+ var elemWidths = 0;
662
+
663
+ width = Math.floor(timeSlider.parent().width()) - 0.2;
664
+ timeSlider
665
+ .siblings()
666
+ .each(function(){
667
+ if(this !== timeSlider[0] && $.css(this, 'position') !== 'absolute' && $.css(this, 'display') !== 'none'){
668
+ elemWidths += Math.ceil($(this).outerWidth(true)) + 0.1;
669
+ }
670
+ })
671
+ ;
672
+ timeSlider.width(Math.floor(width - elemWidths - Math.ceil(timeSlider.outerWidth(true) - timeSlider.width()) - 0.3));
673
+ }
674
+ });
675
+
676
+ $.jme.registerPlugin('media-controls', {
677
+ options: {
678
+ calculateTimerange: false
679
+ },
680
+ pluginOrder: ['<div class="play-pause-container">', 'play-pause', '</div>', '<div class="currenttime-container">', 'currenttime-display', '</div>', '<div class="progress-container">', 'time-slider', '</div>', '<div class="duration-container">', 'duration-display', '</div>', '<div class="mute-container">', 'mute-unmute', '</div>', '<div class="volume-container">', 'volume-slider', '</div>', '<div class="subtitle-container">', '<div class="subtitle-controls">', 'captions', '</div>', '</div>', '<div class="fullscreen-container">', 'fullscreen', '</div>'],
681
+ barStructure: '<div class="jme-media-overlay"></div><div class="jme-controlbar'+ noVolumeClass +'" tabindex="-1"><div class="jme-cb-box"></div></div>',
682
+ _create: function(control, media, base, options){
683
+ var timer;
684
+ var update = function(){
685
+ clearTimeout(timer);
686
+ control.jmeFn('updateControlbar');
687
+ timer = setTimeout(function(){
688
+ control.jmeFn('updateControlbar');
689
+ }, 9);
690
+ };
691
+ if(options.calculateTimerange){
692
+ setTimeout(function(){
693
+ media.on('loadedmetadata volumechange play pause ended emptied', update);
694
+ base.on('updatetimeformat controlsadded controlschanged playerdimensionchange', update);
695
+ $(window).on('resize emchange', update);
696
+ }, 1);
697
+ update();
698
+ }
699
+ }
700
+ });
701
+
702
+ $.jme.registerPlugin('play-pause', {
703
+ pseudoClasses: {
704
+ play: 'state-paused',
705
+ pause: 'state-playing'
706
+ },
707
+ structure: btnStructure,
708
+ text: 'play / pause',
709
+ _create: function(control, media){
710
+ var textFn = $.jme.getButtonText(control, [this[pseudoClasses].play, this[pseudoClasses].pause]);
711
+
712
+ media
713
+ .on('play playing ended pause updateJMEState', function(e){
714
+ var state = e.type;
715
+ if(playStates[state]){
716
+ state = 1;
717
+ } else if(pauseStates[state]) {
718
+ state = 0;
719
+ } else {
720
+ state = (media.jmeProp('isPlaying') )? 1 : 0;
721
+ }
722
+ textFn(state);
723
+ })
724
+ .triggerHandler('updateJMEState')
725
+ ;
726
+ control.on((control.is('select')) ? 'change' : 'click', function(e){
727
+ media.jmeFn('togglePlay');
728
+ e.stopPropagation();
729
+ });
730
+
731
+ }
732
+ });
733
+
734
+ $.jme.registerPlugin('mute-unmute', {
735
+ pseudoClasses: {
736
+ mute: 'state-mute',
737
+ unmute: 'state-unmute'
738
+ },
739
+ structure: btnStructure,
740
+ text: 'mute / unmute',
741
+ _create: function(control, media, base){
742
+ var textFn = $.jme.getButtonText(control, [this[pseudoClasses].mute, this[pseudoClasses].unmute]);
743
+ media
744
+ .on('volumechange updateJMEState', function(e){
745
+ textFn(media.prop('muted') ? 1 : 0);
746
+ })
747
+ .triggerHandler('updateJMEState')
748
+ ;
749
+
750
+ control.on((control.is('select')) ? 'change' : 'click', function(e){
751
+ media.prop('muted', !media.prop('muted'));
752
+ e.stopPropagation();
753
+ });
754
+
755
+ }
756
+ });
757
+
758
+ function createGetSetHandler(fns){
759
+ var throttleTimer;
760
+ var blocked;
761
+
762
+ if(fns.release === true){
763
+ fns.release = fns.set;
764
+ }
765
+ var getSetHelper = {
766
+ start: function(){
767
+ if(!blocked){
768
+ blocked = true;
769
+ if(fns.start){
770
+ fns.start();
771
+ }
772
+ }
773
+ },
774
+ release: function(){
775
+ if(blocked){
776
+ blocked = false;
777
+
778
+ if(fns.release){
779
+ fns.release();
780
+ }
781
+ }
782
+ },
783
+ get: function(){
784
+ if(blocked){return;}
785
+ return fns.get.apply(this, arguments);
786
+ },
787
+ set: function(){
788
+
789
+ var that = this;
790
+ var args = arguments;
791
+ getSetHelper.start();
792
+ clearTimeout(throttleTimer);
793
+ throttleTimer = setTimeout(function(){
794
+ fns.set.apply(that, args);
795
+ }, 33);
796
+ }
797
+ };
798
+ getSetHelper.fns = fns;
799
+ return getSetHelper;
800
+ }
801
+
802
+ $.jme.registerPlugin('volume-slider', {
803
+ structure: slideStructure,
804
+
805
+ _create: function(control, media, base){
806
+
807
+ var createFn = function(){
808
+ var api, volume;
809
+
810
+ volume = createGetSetHandler({
811
+ get: function(){
812
+ var volume = media.prop('volume');
813
+ if(volume !== undefined){
814
+ api.value(volume);
815
+ }
816
+ },
817
+ set: function(){
818
+ media.prop({
819
+ muted: false,
820
+ volume: api.options.value
821
+ });
822
+ },
823
+ release: true
824
+ });
825
+
826
+ api = control
827
+ .rangeUI({
828
+ min: 0,
829
+ max: 1,
830
+ //animate: true,
831
+ step: 'any',
832
+ input: volume.set,
833
+ change: volume.release,
834
+ baseClass: 'media-range'
835
+ })
836
+ .data('rangeUi')
837
+ ;
838
+ media.on('volumechange', volume.get);
839
+ };
840
+
841
+ onSliderReady(createFn);
842
+ }
843
+ });
844
+
845
+ $.jme.registerPlugin('time-slider', {
846
+ structure: slideStructure,
847
+ pseudoClasses: {
848
+ no: 'no-duration'
849
+ },
850
+ options: {
851
+ format: ['mm', 'ss']
852
+ },
853
+ _create: function(control, media, base){
854
+
855
+ var module = this;
856
+
857
+ var createFn = function(){
858
+ var time, durationChange, api, timeShow, wasPaused;
859
+ var hasDuration = $.jme.classNS+'has-duration';
860
+ var duration = media.prop('duration');
861
+
862
+ time = createGetSetHandler({
863
+ get: function(){
864
+ var time = media.prop('currentTime');
865
+ if(!isNaN(time)){
866
+ try {
867
+ api.value(time);
868
+ } catch(er){}
869
+ }
870
+
871
+ },
872
+ set: function(){
873
+ try {
874
+ media.prop('currentTime', api.options.value).triggerHandler('timechanged', [api.options.value]);
875
+ } catch(er){}
876
+ },
877
+ start: function(){
878
+ if(wasPaused == null){
879
+ wasPaused = media.prop('paused');
880
+ if(!wasPaused){
881
+ base._seekpause = true;
882
+ media.pause();
883
+ } else {
884
+ base._seekpause = false;
885
+ }
886
+ }
887
+ },
888
+ release: function(){
889
+ time.fns.set();
890
+ if(wasPaused === false){
891
+ media.play();
892
+ }
893
+ if('_seekpause' in base){
894
+ delete base._seekpause;
895
+ }
896
+ wasPaused = null;
897
+ }
898
+ });
899
+
900
+ durationChange = function(){
901
+ duration = media.prop('duration');
902
+ hasDuration = duration && isFinite(duration) && !isNaN(duration);
903
+ if(hasDuration){
904
+ api.disabled(false);
905
+ api.max(duration);
906
+
907
+ base.removeClass(module[pseudoClasses].no);
908
+ } else {
909
+ api.disabled(true);
910
+ api.max(Number.MAX_VALUE);
911
+ base.addClass(module[pseudoClasses].no);
912
+ }
913
+ };
914
+
915
+ api = control
916
+ .rangeUI({
917
+ min: 0,
918
+ value: media.prop('currentTime') || 0,
919
+ step: 'any',
920
+ input: time.set,
921
+ change: time.release,
922
+ textValue: function(val){
923
+ return media.jmeFn('formatTime', val);
924
+ },
925
+ baseClass: 'media-range'
926
+ })
927
+ .data('rangeUi')
928
+ ;
929
+
930
+ timeShow = $('<span class="'+ $.jme.classNS +'time-select" />').appendTo(control);
931
+
932
+ control
933
+ .on({
934
+ 'mouseenter': function(e){
935
+ if(hasDuration){
936
+ var widgetLeft = (control.offset() || {left: 0}).left;
937
+ var widgetWidth = control.innerWidth();
938
+ var posLeft = function(x){
939
+ var perc = (x - widgetLeft) / widgetWidth * 100;
940
+ timeShow
941
+ .html(media.jmeFn('formatTime', duration * perc / 100))
942
+ .css({left: perc+'%'})
943
+ ;
944
+ };
945
+
946
+ posLeft(e.pageX);
947
+ timeShow.addClass($.jme.classNS +'show-time-select');
948
+ control
949
+ .off('.jmetimeselect')
950
+ .on('mousemove.jmetimeselect', function(e){
951
+ posLeft(e.pageX);
952
+ })
953
+ ;
954
+ }
955
+ },
956
+ mouseleave: function(){
957
+ timeShow.removeClass($.jme.classNS +'show-time-select');
958
+ control.off('.jmetimeselect');
959
+ }
960
+ })
961
+ ;
962
+
963
+
964
+ media.on({
965
+ timeupdate: time.get,
966
+ emptied: function(){
967
+ durationChange();
968
+ api.value(0);
969
+ },
970
+ durationchange: durationChange
971
+ });
972
+
973
+ base.jmeFn('addControls', $('<div class="'+ $.jme.classNS +'buffer-progress" />').prependTo(control) );
974
+ durationChange();
975
+ };
976
+
977
+ onSliderReady(createFn);
978
+ }
979
+ });
980
+
981
+
982
+ $.jme.defineMethod('concerningRange', function(type, time){
983
+ var elem = this;
984
+ var ret = {start: 0, end: 0};
985
+ if(!type){
986
+ type = 'buffered';
987
+ }
988
+ type = $.prop(elem, type);
989
+
990
+ if(time == null){
991
+ time = $.prop(elem, 'currentTime');
992
+ }
993
+ if(!type || !('length' in type)){return ret;}
994
+ for(var i = 0, len = type.length; i < len; i++){
995
+ ret.start = type.start(i);
996
+ ret.end = type.end(i);
997
+ if(ret.start <= time && ret.end >= time){
998
+ break;
999
+ }
1000
+ }
1001
+ return ret;
1002
+ });
1003
+
1004
+ $.jme.defineProp('progress', {
1005
+ get: function(elem){
1006
+ var data = $.jme.data(elem);
1007
+ if(!data.media){return 0;}
1008
+ var progress = data.media.jmeFn('concerningRange').end / data.media.prop('duration') * 100;
1009
+ if(progress > 99.4){
1010
+ progress = 100;
1011
+ }
1012
+ return progress || 0;
1013
+ },
1014
+ readonly: true
1015
+ });
1016
+
1017
+ $.jme.registerPlugin('buffer-progress', {
1018
+ _create: function(control, media, base, options){
1019
+ var indicator = $('<div class="'+ $.jme.classNS +'buffer-progress-indicator" />').appendTo(control);
1020
+ var drawBufferProgress = function(){
1021
+ var progress = media.jmeProp('progress');
1022
+
1023
+
1024
+ if(options.progress !== progress){
1025
+ options.progress = progress;
1026
+ indicator.css('width', progress +'%');
1027
+ }
1028
+ };
1029
+ media.on({
1030
+ progress: drawBufferProgress,
1031
+ emptied: function(){
1032
+ indicator.css('width', 0);
1033
+ options.progress = 0;
1034
+ },
1035
+ playing: drawBufferProgress
1036
+ });
1037
+ drawBufferProgress();
1038
+ }
1039
+ });
1040
+
1041
+ var times = {
1042
+ hh: 60000,
1043
+ mm: 60,
1044
+ ss: 1,
1045
+ ms: 1/1000
1046
+ };
1047
+ var formatTime = function(sec, format){
1048
+ var data;
1049
+ if(!format){
1050
+ format = ['mm', 'ss'];
1051
+ }
1052
+ if(sec == null){
1053
+ data = $.jme.data(this);
1054
+ sec = $.prop(data.media, 'duration');
1055
+ }
1056
+ if(!sec){
1057
+ sec = 0;
1058
+ }
1059
+ var formated = [];
1060
+ var frac;
1061
+ for(var i = 0, len = format.length; i < len; i++){
1062
+ if(format[i] == 'ms' && i == len -1 ){
1063
+ frac = Math.round( (sec / times[format[i]]) / 10);
1064
+ } else {
1065
+ frac = parseInt(sec / times[format[i]], 10);
1066
+ sec = sec % times[format[i]];
1067
+ }
1068
+ if(frac < 10){
1069
+ frac = '0'+frac;
1070
+ }
1071
+ formated.push( frac );
1072
+ }
1073
+
1074
+ return formated.join(':');
1075
+ };
1076
+ $.jme.defineMethod('formatTime', formatTime);
1077
+
1078
+ $.jme.defineProp('format', {
1079
+ set: function(elem, format){
1080
+ if(!$.isArray(format)){
1081
+ format = format.split(':');
1082
+ }
1083
+ var data = $.jme.data(elem);
1084
+ data.format = format;
1085
+ $(elem).triggerHandler('updatetimeformat');
1086
+ data.player.triggerHandler('updatetimeformat');
1087
+ return 'noDataSet';
1088
+ }
1089
+ });
1090
+
1091
+ $.jme.registerPlugin('duration-display', {
1092
+ structure: defaultStructure,
1093
+ options: {
1094
+ format: "mm:ss"
1095
+ },
1096
+ _create: function(control, media, base, options){
1097
+ if(typeof options.format == 'string'){
1098
+ options.format = options.format.split(':');
1099
+ }
1100
+ var showDuration = function(){
1101
+ control.html(formatTime(media.prop('duration'), options.format));
1102
+ };
1103
+ media.on('durationchange emptied', showDuration);
1104
+
1105
+ control
1106
+ .on('updatetimeformat', showDuration)
1107
+ .jmeProp('format', options.format)
1108
+ ;
1109
+ }
1110
+ });
1111
+
1112
+ $.jme.defineProp('countdown', {
1113
+ set: function(elem, value){
1114
+
1115
+ var data = $.jme.data(elem);
1116
+ data.countdown = !!value;
1117
+ $(elem).triggerHandler('updatetimeformat');
1118
+ data.player.triggerHandler('updatetimeformat');
1119
+ return 'noDataSet';
1120
+ }
1121
+ });
1122
+
1123
+ $.jme.registerPlugin('currenttime-display', {
1124
+ structure: defaultStructure,
1125
+ options: {
1126
+ format: "mm:ss",
1127
+ countdown: false
1128
+ },
1129
+ _create: function(control, media, base, options){
1130
+ if(typeof options.format == 'string'){
1131
+ options.format = options.format.split(':');
1132
+ }
1133
+
1134
+ var showTime = function(e){
1135
+ var currentTime = media.prop('currentTime');
1136
+ if(options.countdown){
1137
+ currentTime = (media.prop('duration') || 0) - currentTime;
1138
+ if(currentTime < 0.7){
1139
+ currentTime = 0;
1140
+ }
1141
+ }
1142
+ control.html(formatTime(currentTime, options.format));
1143
+ };
1144
+ media.on('timeupdate emptied durationchange', showTime);
1145
+
1146
+ control
1147
+ .on('updatetimeformat', showTime)
1148
+ .jmeProp('format', options.format)
1149
+ ;
1150
+ }
1151
+ });
1152
+
1153
+
1154
+ /**
1155
+ * Added Poster Plugin
1156
+ * @author mderting
1157
+ */
1158
+
1159
+ /*
1160
+ * the old technique wasn't fully bullet proof
1161
+ * beside this, jme2 adovactes to use the new improved state-classes to handle visual effect on specific state (see CSS change)
1162
+ */
1163
+ $.jme.registerPlugin('poster-display', {
1164
+ structure: '<div />',
1165
+ options: {
1166
+ },
1167
+ _create: function(control, media, base, options){
1168
+
1169
+ /* Empty span element used for vertical centering in IE7 - thanks to Bruno Fassino.
1170
+ * @see http://www.brunildo.org/test/img_center.html
1171
+ */
1172
+ var updatePoster = function(){
1173
+ var poster = media.prop('poster');
1174
+ if(poster){
1175
+ control.html('<span></span><img src="'+ poster +'" class="'+ $.jme.classNS +'poster-image" />');
1176
+ } else {
1177
+ control.empty();
1178
+ }
1179
+ };
1180
+ media.on('emptied', updatePoster);
1181
+ updatePoster();
1182
+ }
1183
+ });
1184
+
1185
+ //taken from http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/
1186
+ $.jme.fullscreen = (function() {
1187
+ var parentData;
1188
+ var frameData;
1189
+ var doc = document.documentElement;
1190
+
1191
+ var fullScreenApi = {
1192
+ supportsFullScreen: Modernizr.prefixed('fullscreenEnabled', document, false) || Modernizr.prefixed('fullScreenEnabled', document, false),
1193
+ isFullScreen: function() { return false; },
1194
+ requestFullScreen: function(elem){
1195
+ var tmpData;
1196
+ parentData = [];
1197
+ $(elem).parentsUntil('body').each(function(){
1198
+ var pos = $.css(this, 'position');
1199
+ var left = this.scrollLeft;
1200
+ var top = this.scrollTop;
1201
+ var changed;
1202
+ tmpData = {elemStyle: this.style, elem: this};
1203
+ if(pos !== 'static'){
1204
+ changed = true;
1205
+ tmpData.pos = tmpData.elemStyle.position;
1206
+ this.style.position = 'static';
1207
+ }
1208
+ if(left){
1209
+ changed = true;
1210
+ tmpData.left = left;
1211
+ }
1212
+ if(top){
1213
+ changed = true;
1214
+ tmpData.top = top;
1215
+ }
1216
+ if(changed){
1217
+ parentData.push(tmpData);
1218
+ }
1219
+ });
1220
+ frameData = false;
1221
+ try {
1222
+ frameData = {elemStyle: frameElement.style, elem: frameElement, css: {}};
1223
+ frameData.css.position = frameData.elemStyle.position;
1224
+ frameData.elemStyle.position = 'fixed';
1225
+ $.each(['top', 'left', 'right', 'bottom'], function(i, name){
1226
+ frameData.css[name] = frameData.elemStyle[name];
1227
+ frameData.elemStyle[name] = '0px';
1228
+ });
1229
+ $.each(['height', 'width'], function(i, name){
1230
+ frameData.css[name] = frameData.elemStyle[name];
1231
+ frameData.elemStyle[name] = '100%';
1232
+ });
1233
+ } catch(er){
1234
+ frameData = false;
1235
+ }
1236
+
1237
+ tmpData = null;
1238
+ },
1239
+ cancelFullScreen: function(){
1240
+ if(parentData){
1241
+ $.each(parentData, function(i, data){
1242
+ if('pos' in data){
1243
+ data.elemStyle.position = data.pos;
1244
+ }
1245
+ if(data.left){
1246
+ data.elem.scrollLeft = data.left;
1247
+ }
1248
+ if(data.top){
1249
+ data.elem.scrollTop = data.top;
1250
+ }
1251
+ data = null;
1252
+ });
1253
+ parentData = [];
1254
+ }
1255
+ if(frameData){
1256
+ $.each(frameData.css, function(name, value){
1257
+ frameData.elemStyle[name] = value;
1258
+ });
1259
+ frameData = false;
1260
+ }
1261
+ },
1262
+ eventName: 'fullscreenchange',
1263
+ exitName: 'exitFullscreen',
1264
+ requestName: 'requestFullscreen',
1265
+ elementName: 'fullscreenElement',
1266
+ enabledName: ''
1267
+ };
1268
+
1269
+ fullScreenApi.cancelFullWindow = fullScreenApi.cancelFullScreen;
1270
+ fullScreenApi.requestFullWindow = fullScreenApi.requestFullScreen;
1271
+
1272
+ // update methods to do something useful
1273
+ if (fullScreenApi.supportsFullScreen) {
1274
+ fullScreenApi.enabledName = fullScreenApi.supportsFullScreen;
1275
+ fullScreenApi.exitName = Modernizr.prefixed("exitFullscreen", document, false) || Modernizr.prefixed("cancelFullScreen", document, false);
1276
+ fullScreenApi.elementName = Modernizr.prefixed("fullscreenElement", document, false) || Modernizr.prefixed("fullScreenElement", document, false);
1277
+ fullScreenApi.supportsFullScreen = !!fullScreenApi.supportsFullScreen;
1278
+ if(fullScreenApi.elementName != 'fullscreenElement' || fullScreenApi.exitName != 'exitFullscreen' || fullScreenApi.enabledName != 'fullscreenEnabled'){
1279
+ $.each(Modernizr._domPrefixes, function(i, prefix){
1280
+ var requestName = prefix+'RequestFullscreen';
1281
+ if((requestName in doc) || ((requestName = prefix+'RequestFullScreen') && (requestName in doc))){
1282
+ fullScreenApi.eventName = prefix + 'fullscreenchange';
1283
+ fullScreenApi.requestName = requestName;
1284
+ return false;
1285
+ }
1286
+ });
1287
+ }
1288
+
1289
+ fullScreenApi.isFullScreen = function() {
1290
+ return document[fullScreenApi.elementName];
1291
+ };
1292
+ fullScreenApi.requestFullScreen = function(el) {
1293
+ return el[fullScreenApi.requestName]();
1294
+ };
1295
+ fullScreenApi.cancelFullScreen = function() {
1296
+ return document[fullScreenApi.exitName]();
1297
+ };
1298
+ }
1299
+
1300
+ if(!window.Modernizr || !('fullscreen' in Modernizr)){
1301
+ $('html').addClass(fullScreenApi.supportsFullScreen ? 'fullscreen' : 'no-fullscreen');
1302
+ }
1303
+
1304
+ if(window.parent != window){
1305
+ (function(){
1306
+ try{
1307
+ var frame = window.frameElement;
1308
+ if (fullScreenApi.supportsFullScreen) {
1309
+ if('allowfullscreen' in frame && !frame.allowfullscreen) {
1310
+ frame.allowfullscreen = true;
1311
+ } else {
1312
+ if(frame.getAttribute('webkitallowfullscreen') == null){
1313
+ frame.setAttribute('webkitallowfullscreen', '');
1314
+ }
1315
+ if(frame.getAttribute('allowfullscreen') == null){
1316
+ frame.setAttribute('allowfullscreen', 'allowfullscreen');
1317
+ }
1318
+ }
1319
+ }
1320
+ } catch(er){
1321
+ if(!fullScreenApi.supportsFullScreen){
1322
+ $('html').addClass('no-fullwindow');
1323
+ }
1324
+ }
1325
+ })();
1326
+
1327
+ }
1328
+
1329
+
1330
+ return fullScreenApi;
1331
+ })();
1332
+
1333
+ $.jme.defineProp('fullscreen', {
1334
+ set: function(elem, value){
1335
+ var data = $.jme.data(elem);
1336
+
1337
+ if((!data || !data.player) && !$(elem).hasClass($.jme.classNS+'player-fullscreen')){return 'noDataSet';}
1338
+ if(value){
1339
+ if(data.player.hasClass($.jme.classNS+'player-fullscreen')){return 'noDataSet';}
1340
+
1341
+ data.scrollPos = {
1342
+ top: $(window).scrollTop(),
1343
+ left: $(window).scrollLeft()
1344
+ };
1345
+
1346
+ $(document)
1347
+ .off('.jmefullscreen')
1348
+ .on('keydown.jmefullscreen', function(e){
1349
+ if(e.keyCode == 27){
1350
+ data.player.jmeProp('fullscreen', false);
1351
+ return false;
1352
+ }
1353
+ if(e.keyCode === 32 && !('form' in e.target)){
1354
+ data.media.jmeFn('togglePlay');
1355
+ return false;
1356
+ }
1357
+ })
1358
+ ;
1359
+
1360
+
1361
+ if(value == 'fullwindow'){
1362
+ $.jme.fullscreen.requestFullWindow(data.player[0]);
1363
+ } else {
1364
+ try {
1365
+ $.jme.fullscreen.requestFullScreen(data.player[0]);
1366
+ } catch(er){}
1367
+ }
1368
+
1369
+
1370
+ $('html').addClass($.jme.classNS+'has-media-fullscreen');
1371
+
1372
+ data.player.addClass($.jme.classNS+'player-fullscreen');
1373
+
1374
+ data.media.addClass($.jme.classNS+'media-fullscreen');
1375
+
1376
+ $('button.play-pause', data.player).focus();
1377
+
1378
+ if($.jme.fullscreen.supportsFullScreen){
1379
+ $(document)
1380
+ .on($.jme.fullscreen.eventName+'.jmefullscreen', function(e){
1381
+ var fullScreenElem = $.jme.fullscreen.isFullScreen();
1382
+ if(fullScreenElem && elem == fullScreenElem){
1383
+ data.media.trigger('playerdimensionchange', ['fullscreen']);
1384
+ } else {
1385
+ data.player.jmeProp('fullscreen', false);
1386
+ }
1387
+ })
1388
+ ;
1389
+
1390
+ }
1391
+ data.media.trigger('playerdimensionchange', ['fullwindow']);
1392
+
1393
+ } else {
1394
+ if(data.player && !data.player.hasClass($.jme.classNS+'player-fullscreen')){return 'noDataSet';}
1395
+ $(document).off('.jmefullscreen');
1396
+ $('html').removeClass($.jme.classNS+'has-media-fullscreen');
1397
+ if(data.player && data.media){
1398
+ data.player.removeClass($.jme.classNS+'player-fullscreen');
1399
+ data.media.removeClass($.jme.classNS+'media-fullscreen');
1400
+ }
1401
+ if($.jme.fullscreen.isFullScreen()){
1402
+ try {
1403
+ $.jme.fullscreen.cancelFullScreen();
1404
+ } catch(er){}
1405
+ } else {
1406
+ $.jme.fullscreen.cancelFullWindow();
1407
+ }
1408
+
1409
+ if(data.scrollPos){
1410
+ $(window).scrollTop(data.scrollPos.top);
1411
+ $(window).scrollLeft(data.scrollPos.left);
1412
+ delete data.scrollPos;
1413
+ }
1414
+ if(data.media){
1415
+ data.media.trigger('playerdimensionchange');
1416
+ }
1417
+ }
1418
+ return 'noDataSet';
1419
+ },
1420
+ get: function(elem){
1421
+ var data = $.jme.data(elem);
1422
+ if(!data || !data.player){return;}
1423
+ var fs = data.player.hasClass($.jme.classNS+'player-fullscreen');
1424
+ if(!fs){return false;}
1425
+ return $.jme.fullscreen.isFullScreen() || 'fullwindow';
1426
+ }
1427
+ });
1428
+
1429
+ $.jme.defineProp('autoplayfs');
1430
+
1431
+ $.jme.registerPlugin('fullscreen', {
1432
+ pseudoClasses: {
1433
+ enter: 'state-enterfullscreen',
1434
+ exit: 'state-exitfullscreen'
1435
+ },
1436
+ options: {
1437
+ fullscreen: true,
1438
+ autoplayfs: false
1439
+ },
1440
+ structure: btnStructure,
1441
+ text: 'enter fullscreen / exit fullscreen',
1442
+ _create: function(control, media, base){
1443
+ var textFn = $.jme.getButtonText(control, [this[pseudoClasses].enter, this[pseudoClasses].exit]);
1444
+ var updateControl = function(){
1445
+ textFn(base.hasClass($.jme.classNS+'player-fullscreen') ? 1 : 0);
1446
+ };
1447
+ var options = this.options;
1448
+ var addDoubbleClick = function(){
1449
+ $(base.data('jme').controlElements)
1450
+ .filter('.jme-media-overlay')
1451
+ .off('.dblfullscreen')
1452
+ .on('dblclick.dblfullscreen', function(e){
1453
+ base.jmeProp('fullscreen', !base.jmeProp('fullscreen'));
1454
+ })
1455
+ ;
1456
+ };
1457
+
1458
+ base.on('controlsadded', addDoubbleClick);
1459
+
1460
+ base.on('playerdimensionchange', updateControl);
1461
+
1462
+ control.on((control.is('select')) ? 'change' : 'click', function(){
1463
+ var value = base.hasClass($.jme.classNS+'player-fullscreen') ? false : options.fullscreen;
1464
+ base.jmeProp('fullscreen', value);
1465
+ if(value && options.autoplayfs){
1466
+ media.jmeFn('play');
1467
+ }
1468
+ });
1469
+ addDoubbleClick();
1470
+ updateControl();
1471
+ }
1472
+ });
1473
+
1474
+
1475
+ $.jme.ButtonMenu = function(button, menu, clickHandler){
1476
+
1477
+ this.button = $(button).attr({'aria-haspopup': 'true'});
1478
+
1479
+ this.clickHandler = clickHandler;
1480
+
1481
+ this.toggle = $.proxy(this, 'toggle');
1482
+ this.keyIndex = $.proxy(this, 'keyIndex');
1483
+ this._buttonClick = $.proxy(this, '_buttonClick');
1484
+
1485
+
1486
+ this.addMenu(menu);
1487
+ this._closeFocusOut();
1488
+ this.button.on('click', this.toggle);
1489
+
1490
+ };
1491
+
1492
+ $.jme.ButtonMenu.prototype = {
1493
+ addMenu: function(menu){
1494
+ if(this.menu){
1495
+ this.menu.remove();
1496
+ }
1497
+ this.menu = $(menu);
1498
+ this.buttons = $('button', this.menu);
1499
+ this.menu.insertAfter(this.button);
1500
+ this.menu
1501
+ .on('keydown', this.keyIndex)
1502
+ .delegate('button', 'click', this._buttonClick)
1503
+ ;
1504
+ },
1505
+ _closeFocusOut: function(){
1506
+ var that = this;
1507
+ var timer;
1508
+ var stopFocusOut = function(){
1509
+ clearTimeout(timer);
1510
+ setTimeout(function(){
1511
+ clearTimeout(timer);
1512
+ }, 9);
1513
+ };
1514
+ this.menu
1515
+ .parent()
1516
+ .on('focusin', stopFocusOut)
1517
+ .on('mousedown', stopFocusOut)
1518
+ .on('focusout', function(e){
1519
+ timer = setTimeout(function(){
1520
+ that.hide();
1521
+ }, 40);
1522
+ })
1523
+ ;
1524
+ },
1525
+ _buttonClick: function(e){
1526
+ this.clickHandler(this.buttons.index(e.currentTarget), e.currentTarget);
1527
+ this.hide();
1528
+ },
1529
+ keyIndex: function(e){
1530
+ var dir = (e.keyCode == 40) ? 1 : (e.keyCode == 38) ? -1 : 0;
1531
+ if(dir){
1532
+ var buttons = this.buttons.not(':disabled');
1533
+ var activeButton = buttons.filter(':focus');
1534
+
1535
+ activeButton = buttons[buttons.index(activeButton) + dir] || buttons.filter(dir > 0 ? ':first' : ':last');
1536
+ activeButton.focus();
1537
+ e.preventDefault();
1538
+ }
1539
+ },
1540
+ show: function(){
1541
+ if(this.isVisible){return;}
1542
+ var buttons = this.buttons.not(':disabled');
1543
+ this.isVisible = true;
1544
+ this.menu.addClass('visible-menu');
1545
+ try {
1546
+ this.activeElement = document.activeElement || this.button[0];
1547
+ } catch(er){
1548
+ this.activeElement = this.button[0];
1549
+ }
1550
+
1551
+ setTimeout(function(){
1552
+ $(buttons.filter('[aria-checked="true"]')[0] || buttons[0]).focus();
1553
+ }, 60);
1554
+ },
1555
+ toggle: function(){
1556
+ this[this.isVisible ? 'hide' : 'show']();
1557
+ },
1558
+ hide: function(){
1559
+ if(!this.isVisible){return;}
1560
+ this.isVisible = false;
1561
+ this.menu.removeClass('visible-menu');
1562
+ if(this.activeElement){
1563
+ try {
1564
+ this.activeElement.focus();
1565
+ } catch(er){}
1566
+ }
1567
+ this.activeElement = false;
1568
+ }
1569
+ };
1570
+
1571
+ var showKinds = {subtitles: 1, caption: 1};
1572
+ var getTrackMenu = function(tracks){
1573
+ var items = $.map(tracks, function(track){
1574
+ var className = (track.kind == 'caption') ? 'caption-type' : 'subtitle-type';
1575
+ var lang = track.language;
1576
+ lang = (lang) ? ' <span class="track-lang">'+ lang +'</span>' : '';
1577
+ return '<li class="'+ className +'" role="presentation"><button role="menuitemcheckbox">'+ track.label + lang +'</button></li>';
1578
+ })
1579
+ ;
1580
+ return '<div><ul>' + items.join('') +'</ul></div>';
1581
+ };
1582
+
1583
+
1584
+ $.jme.registerPlugin('captions', {
1585
+ pseudoClasses: {
1586
+ menu: 'subtitle-menu'
1587
+ },
1588
+ structure: btnStructure,
1589
+ text: 'subtitles',
1590
+ _create: function(control, media, base, options){
1591
+ var that = this;
1592
+
1593
+ var trackElems = media.find('track');
1594
+ var checkbox = $(control).clone().attr({role: 'checkbox'}).insertBefore(control);
1595
+
1596
+ base.attr('data-tracks', trackElems.length > 1 ? 'many' : trackElems.length);
1597
+ control.attr('aria-haspopup', 'true');
1598
+
1599
+ webshims.ready('track', function(){
1600
+ var menuObj, throttledUpdateMode;
1601
+ var tracks = [];
1602
+ var textTracks = media.prop('textTracks');
1603
+
1604
+ var throttledUpdate = (function(){
1605
+ var timer;
1606
+ var triggerTimer;
1607
+ return function(e){
1608
+ clearTimeout(timer);
1609
+ clearTimeout(triggerTimer);
1610
+ if(e.type == 'updatesubtitlestate'){
1611
+ triggerTimer = setTimeout(function(){
1612
+ media.trigger('updatetracklist');
1613
+ }, 0);
1614
+ }
1615
+ timer = setTimeout(updateTrackMenu, 19);
1616
+ };
1617
+ })();
1618
+
1619
+ function createSubtitleMenu(menu){
1620
+ var menuClick;
1621
+
1622
+ if(!menuObj){
1623
+ menuClick = function(index, button){
1624
+ if($.attr(button, 'aria-checked') == 'true'){
1625
+ tracks[index].mode = 'disabled';
1626
+ } else {
1627
+ $.each(tracks, function(i, track){
1628
+ track.mode = (i == index) ? 'showing' : 'disabled';
1629
+ });
1630
+ }
1631
+ media.prop('textTracks');
1632
+ updateMode();
1633
+ };
1634
+
1635
+ menuObj = new $.jme.ButtonMenu(control, menu, menuClick);
1636
+ checkbox.on('click', function(){
1637
+ menuClick(0, this);
1638
+ return false;
1639
+ });
1640
+ } else {
1641
+ menuObj.addMenu(menu);
1642
+ }
1643
+
1644
+ updateMode();
1645
+ }
1646
+
1647
+ function updateMode(){
1648
+ $('button', menuObj.menu).each(function(i){
1649
+ var checked = (tracks[i].mode == 'showing') ? 'true' : 'false';
1650
+ if(!i){
1651
+ checkbox.attr('aria-checked', checked);
1652
+ }
1653
+ $.attr(this, 'aria-checked', checked);
1654
+ });
1655
+ }
1656
+
1657
+ function updateTrackMenu(){
1658
+ tracks = [];
1659
+ $.each(textTracks, function(i, track){
1660
+ if(showKinds[track.kind] && track.readyState != 3){
1661
+ tracks.push(track);
1662
+ }
1663
+ });
1664
+
1665
+ base.attr('data-tracks', tracks.length > 1 ? 'many' : tracks.length);
1666
+
1667
+ if(tracks.length){
1668
+ createSubtitleMenu('<div class="'+that[pseudoClasses].menu +'" >'+ (getTrackMenu(tracks)) +'</div>');
1669
+
1670
+ $('span.jme-text, +label span.jme-text', checkbox).text((tracks[0].label || ' ') + (tracks[0].lang || ''));
1671
+
1672
+ if(!base.hasClass(that[pseudoClasses].hasTrack) || base.hasClass(that[pseudoClasses].noTrack)){
1673
+ control.prop('disabled', false);
1674
+ base.triggerHandler('controlschanged');
1675
+ }
1676
+
1677
+ } else if(!base.hasClass(that[pseudoClasses].noTrack) || base.hasClass(that[pseudoClasses].hasTrack)){
1678
+ control.prop('disabled', true);
1679
+ base
1680
+ .triggerHandler('controlschanged')
1681
+ ;
1682
+ }
1683
+ }
1684
+
1685
+ if(!textTracks){
1686
+ textTracks = [];
1687
+ updateTrackMenu();
1688
+ } else {
1689
+ throttledUpdateMode = (function(){
1690
+ var timer;
1691
+ return function(){
1692
+ clearTimeout(timer);
1693
+ timer = setTimeout(updateMode, 20);
1694
+ };
1695
+ })();
1696
+
1697
+ updateTrackMenu();
1698
+
1699
+ $([textTracks])
1700
+ .on('addtrack removetrack', throttledUpdate)
1701
+ .on('change', throttledUpdateMode)
1702
+ ;
1703
+
1704
+ base.on('updatesubtitlestate', throttledUpdate);
1705
+ media.on('updatetrackdisplay', throttledUpdateMode);
1706
+ }
1707
+
1708
+ });
1709
+ }
1710
+ });
1711
+
1712
+ $('.mediaplayer').each(function(){
1713
+ if(($.data(this, 'jme')|| {}).controlbar){
1714
+ $(this).jmeProp('controlbar', true);
1715
+ }
1716
+ });
1717
+
1718
+ webshims.ready('mediaelement', function(){
1719
+ webshims.addReady(function(context, insertedElement){
1720
+ $(baseSelector, context).add(insertedElement.filter(baseSelector)).jmeProp('controlbar', true);
1721
+ });
1722
+ });
1723
+ webshims.ready('WINDOWLOAD', loadRange);
1724
+ });