mediaelement_rails 0.5.1 → 0.7.0

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.
@@ -5,7 +5,7 @@
5
5
  * Creates a controller bar for HTML5 <video> add <audio> tags
6
6
  * using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
7
7
  *
8
- * Copyright 2010-2012, John Dyer (http://j.hn/)
8
+ * Copyright 2010-2013, John Dyer (http://j.hn/)
9
9
  * License: MIT
10
10
  *
11
11
  */
@@ -20,6 +20,8 @@ if (typeof jQuery != 'undefined') {
20
20
  mejs.MepDefaults = {
21
21
  // url to poster (to fix iOS 3.x)
22
22
  poster: '',
23
+ // When the video is ended, we can show the poster.
24
+ showPosterWhenEnded: false,
23
25
  // default if the <video width> is not specified
24
26
  defaultVideoWidth: 480,
25
27
  // default if the <video height> is not specified
@@ -33,19 +35,19 @@ if (typeof jQuery != 'undefined') {
33
35
  // default if the user doesn't specify
34
36
  defaultAudioHeight: 30,
35
37
 
36
- // default amount to move back when back key is pressed
38
+ // default amount to move back when back key is pressed
37
39
  defaultSeekBackwardInterval: function(media) {
38
40
  return (media.duration * 0.05);
39
- },
40
- // default amount to move forward when forward key is pressed
41
+ },
42
+ // default amount to move forward when forward key is pressed
41
43
  defaultSeekForwardInterval: function(media) {
42
44
  return (media.duration * 0.05);
43
- },
44
-
45
+ },
46
+
45
47
  // width of audio player
46
48
  audioWidth: -1,
47
49
  // height of audio player
48
- audioHeight: -1,
50
+ audioHeight: -1,
49
51
  // initial volume when the player starts (overrided by user cookie)
50
52
  startVolume: 0.8,
51
53
  // useful for <audio> player loops
@@ -61,7 +63,7 @@ if (typeof jQuery != 'undefined') {
61
63
  showTimecodeFrameCount: false,
62
64
  // used when showTimecodeFrameCount is set to true
63
65
  framesPerSecond: 25,
64
-
66
+
65
67
  // automatically calculate the width of the progress bar based on the sizes of other elements
66
68
  autosizeProgress : true,
67
69
  // Hide controls when playing and mouse is not over the video
@@ -73,20 +75,20 @@ if (typeof jQuery != 'undefined') {
73
75
  // force iPad's native controls
74
76
  iPadUseNativeControls: false,
75
77
  // force iPhone's native controls
76
- iPhoneUseNativeControls: false,
78
+ iPhoneUseNativeControls: false,
77
79
  // force Android's native controls
78
- AndroidUseNativeControls: false,
80
+ AndroidUseNativeControls: false,
79
81
  // features to show
80
82
  features: ['playpause','current','progress','duration','tracks','volume','fullscreen'],
81
83
  // only for dynamic
82
84
  isVideo: true,
83
-
85
+
84
86
  // turns keyboard support on and off for this instance
85
87
  enableKeyboard: true,
86
-
88
+
87
89
  // whenthis player starts, it will pause other players
88
90
  pauseOtherPlayers: true,
89
-
91
+
90
92
  // array of keyboard actions such as play pause
91
93
  keyActions: [
92
94
  {
@@ -96,10 +98,10 @@ if (typeof jQuery != 'undefined') {
96
98
  ],
97
99
  action: function(player, media) {
98
100
  if (media.paused || media.ended) {
99
- media.play();
101
+ player.play();
100
102
  } else {
101
- media.pause();
102
- }
103
+ player.pause();
104
+ }
103
105
  }
104
106
  },
105
107
  {
@@ -127,7 +129,7 @@ if (typeof jQuery != 'undefined') {
127
129
  player.showControls();
128
130
  player.startControlsTimer();
129
131
  }
130
-
132
+
131
133
  // 5%
132
134
  var newTime = Math.max(media.currentTime - player.options.defaultSeekBackwardInterval(media), 0);
133
135
  media.setCurrentTime(newTime);
@@ -138,16 +140,16 @@ if (typeof jQuery != 'undefined') {
138
140
  keys: [
139
141
  39, // RIGHT
140
142
  228 // Google TV forward
141
- ],
143
+ ],
142
144
  action: function(player, media) {
143
145
  if (!isNaN(media.duration) && media.duration > 0) {
144
146
  if (player.isVideo) {
145
147
  player.showControls();
146
148
  player.startControlsTimer();
147
149
  }
148
-
150
+
149
151
  // 5%
150
- var newTime = Math.min(media.currentTime + player.options.defaultSeekForwardInterval(media), media.duration);
152
+ var newTime = Math.min(media.currentTime + player.options.defaultSeekForwardInterval(media), media.duration);
151
153
  media.setCurrentTime(newTime);
152
154
  }
153
155
  }
@@ -163,12 +165,12 @@ if (typeof jQuery != 'undefined') {
163
165
  }
164
166
  }
165
167
  }
166
- }
167
- ]
168
+ }
169
+ ]
168
170
  };
169
171
 
170
172
  mejs.mepIndex = 0;
171
-
173
+
172
174
  mejs.players = {};
173
175
 
174
176
  // wraps a MediaElement object in player controls
@@ -176,14 +178,14 @@ if (typeof jQuery != 'undefined') {
176
178
  // enforce object, even without "new" (via John Resig)
177
179
  if ( !(this instanceof mejs.MediaElementPlayer) ) {
178
180
  return new mejs.MediaElementPlayer(node, o);
179
- }
181
+ }
180
182
 
181
183
  var t = this;
182
-
184
+
183
185
  // these will be reset after the MediaElement.success fires
184
186
  t.$media = t.$node = $(node);
185
- t.node = t.media = t.$media[0];
186
-
187
+ t.node = t.media = t.$media[0];
188
+
187
189
  // check for existing player
188
190
  if (typeof t.node.player != 'undefined') {
189
191
  return t.node.player;
@@ -191,22 +193,22 @@ if (typeof jQuery != 'undefined') {
191
193
  // attach player to DOM node for reference
192
194
  t.node.player = t;
193
195
  }
194
-
195
-
196
+
197
+
196
198
  // try to get options from data-mejsoptions
197
199
  if (typeof o == 'undefined') {
198
- o = t.$node.data('mejsoptions');
200
+ o = t.$node.data('mejsoptions');
199
201
  }
200
-
202
+
201
203
  // extend default options
202
204
  t.options = $.extend({},mejs.MepDefaults,o);
203
-
205
+
204
206
  // unique ID
205
207
  t.id = 'mep_' + mejs.mepIndex++;
206
208
 
207
209
  // add to player array (for focus events)
208
210
  mejs.players[t.id] = t;
209
-
211
+
210
212
  // start up
211
213
  t.init();
212
214
 
@@ -215,11 +217,11 @@ if (typeof jQuery != 'undefined') {
215
217
 
216
218
  // actual player
217
219
  mejs.MediaElementPlayer.prototype = {
218
-
220
+
219
221
  hasFocus: false,
220
-
222
+
221
223
  controlsAreVisible: true,
222
-
224
+
223
225
  init: function() {
224
226
 
225
227
  var
@@ -231,19 +233,19 @@ if (typeof jQuery != 'undefined') {
231
233
  error: function(e) { t.handleError(e);}
232
234
  }),
233
235
  tagName = t.media.tagName.toLowerCase();
234
-
236
+
235
237
  t.isDynamic = (tagName !== 'audio' && tagName !== 'video');
236
-
237
- if (t.isDynamic) {
238
- // get video from src or href?
239
- t.isVideo = t.options.isVideo;
238
+
239
+ if (t.isDynamic) {
240
+ // get video from src or href?
241
+ t.isVideo = t.options.isVideo;
240
242
  } else {
241
243
  t.isVideo = (tagName !== 'audio' && t.options.isVideo);
242
244
  }
243
-
244
- // use native controls in iPad, iPhone, and Android
245
+
246
+ // use native controls in iPad, iPhone, and Android
245
247
  if ((mf.isiPad && t.options.iPadUseNativeControls) || (mf.isiPhone && t.options.iPhoneUseNativeControls)) {
246
-
248
+
247
249
  // add controls and stop
248
250
  t.$media.attr('controls', 'controls');
249
251
 
@@ -253,21 +255,20 @@ if (typeof jQuery != 'undefined') {
253
255
 
254
256
  // override Apple's autoplay override for iPads
255
257
  if (mf.isiPad && t.media.getAttribute('autoplay') !== null) {
256
- t.media.load();
257
- t.media.play();
258
+ t.play();
258
259
  }
259
-
260
+
260
261
  } else if (mf.isAndroid && t.options.AndroidUseNativeControls) {
261
-
262
+
262
263
  // leave default player
263
264
 
264
265
  } else {
265
266
 
266
267
  // DESKTOP: use MediaElementPlayer controls
267
-
268
- // remove native controls
269
- t.$media.removeAttr('controls');
270
-
268
+
269
+ // remove native controls
270
+ t.$media.removeAttr('controls');
271
+
271
272
  // build container
272
273
  t.container =
273
274
  $('<div id="' + t.id + '" class="mejs-container ' + (mejs.MediaFeatures.svg ? 'svg' : 'no-svg') + '">'+
@@ -279,8 +280,8 @@ if (typeof jQuery != 'undefined') {
279
280
  '</div>' +
280
281
  '</div>')
281
282
  .addClass(t.$media[0].className)
282
- .insertBefore(t.$media);
283
-
283
+ .insertBefore(t.$media);
284
+
284
285
  // add classes for user and content
285
286
  t.container.addClass(
286
287
  (mf.isAndroid ? 'mejs-android ' : '') +
@@ -288,89 +289,89 @@ if (typeof jQuery != 'undefined') {
288
289
  (mf.isiPad ? 'mejs-ipad ' : '') +
289
290
  (mf.isiPhone ? 'mejs-iphone ' : '') +
290
291
  (t.isVideo ? 'mejs-video ' : 'mejs-audio ')
291
- );
292
-
292
+ );
293
+
293
294
 
294
295
  // move the <video/video> tag into the right spot
295
296
  if (mf.isiOS) {
296
-
297
+
297
298
  // sadly, you can't move nodes in iOS, so we have to destroy and recreate it!
298
299
  var $newMedia = t.$media.clone();
299
-
300
+
300
301
  t.container.find('.mejs-mediaelement').append($newMedia);
301
-
302
+
302
303
  t.$media.remove();
303
304
  t.$node = t.$media = $newMedia;
304
305
  t.node = t.media = $newMedia[0]
305
-
306
+
306
307
  } else {
307
-
308
+
308
309
  // normal way of moving it into place (doesn't work on iOS)
309
310
  t.container.find('.mejs-mediaelement').append(t.$media);
310
311
  }
311
-
312
+
312
313
  // find parts
313
314
  t.controls = t.container.find('.mejs-controls');
314
315
  t.layers = t.container.find('.mejs-layers');
315
316
 
316
317
  // determine the size
317
-
318
+
318
319
  /* size priority:
319
- (1) videoWidth (forced),
320
+ (1) videoWidth (forced),
320
321
  (2) style="width;height;"
321
322
  (3) width attribute,
322
323
  (4) defaultVideoWidth (for unspecified cases)
323
324
  */
324
-
325
+
325
326
  var tagType = (t.isVideo ? 'video' : 'audio'),
326
327
  capsTagName = tagType.substring(0,1).toUpperCase() + tagType.substring(1);
327
-
328
-
328
+
329
+
329
330
  if (t.options[tagType + 'Width'] > 0 || t.options[tagType + 'Width'].toString().indexOf('%') > -1) {
330
331
  t.width = t.options[tagType + 'Width'];
331
332
  } else if (t.media.style.width !== '' && t.media.style.width !== null) {
332
- t.width = t.media.style.width;
333
+ t.width = t.media.style.width;
333
334
  } else if (t.media.getAttribute('width') !== null) {
334
335
  t.width = t.$media.attr('width');
335
336
  } else {
336
337
  t.width = t.options['default' + capsTagName + 'Width'];
337
338
  }
338
-
339
+
339
340
  if (t.options[tagType + 'Height'] > 0 || t.options[tagType + 'Height'].toString().indexOf('%') > -1) {
340
341
  t.height = t.options[tagType + 'Height'];
341
342
  } else if (t.media.style.height !== '' && t.media.style.height !== null) {
342
343
  t.height = t.media.style.height;
343
344
  } else if (t.$media[0].getAttribute('height') !== null) {
344
- t.height = t.$media.attr('height');
345
+ t.height = t.$media.attr('height');
345
346
  } else {
346
347
  t.height = t.options['default' + capsTagName + 'Height'];
347
348
  }
348
349
 
349
350
  // set the size, while we wait for the plugins to load below
350
351
  t.setPlayerSize(t.width, t.height);
351
-
352
+
352
353
  // create MediaElementShim
353
- meOptions.pluginWidth = t.height;
354
- meOptions.pluginHeight = t.width;
354
+ meOptions.pluginWidth = t.width;
355
+ meOptions.pluginHeight = t.height;
355
356
  }
356
-
357
-
358
357
 
359
358
  // create MediaElement shim
360
359
  mejs.MediaElement(t.$media[0], meOptions);
361
360
 
362
- // controls are shown when loaded
363
- t.container.trigger('controlsshown');
361
+ if (typeof(t.container) != 'undefined' && t.controlsAreVisible){
362
+ // controls are shown when loaded
363
+ t.container.trigger('controlsshown');
364
+ }
364
365
  },
365
-
366
+
366
367
  showControls: function(doAnimation) {
367
368
  var t = this;
368
-
369
+
369
370
  doAnimation = typeof doAnimation == 'undefined' || doAnimation;
370
-
371
+
371
372
  if (t.controlsAreVisible)
372
373
  return;
373
-
374
+
374
375
  if (doAnimation) {
375
376
  t.controls
376
377
  .css('visibility','visible')
@@ -378,84 +379,84 @@ if (typeof jQuery != 'undefined') {
378
379
  t.controlsAreVisible = true;
379
380
  t.container.trigger('controlsshown');
380
381
  });
381
-
382
+
382
383
  // any additional controls people might add and want to hide
383
384
  t.container.find('.mejs-control')
384
385
  .css('visibility','visible')
385
- .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
386
-
386
+ .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
387
+
387
388
  } else {
388
389
  t.controls
389
390
  .css('visibility','visible')
390
391
  .css('display','block');
391
-
392
+
392
393
  // any additional controls people might add and want to hide
393
394
  t.container.find('.mejs-control')
394
395
  .css('visibility','visible')
395
396
  .css('display','block');
396
-
397
+
397
398
  t.controlsAreVisible = true;
398
399
  t.container.trigger('controlsshown');
399
400
  }
400
-
401
+
401
402
  t.setControlsSize();
402
-
403
+
403
404
  },
404
405
 
405
406
  hideControls: function(doAnimation) {
406
407
  var t = this;
407
-
408
+
408
409
  doAnimation = typeof doAnimation == 'undefined' || doAnimation;
409
-
410
- if (!t.controlsAreVisible)
410
+
411
+ if (!t.controlsAreVisible || t.options.alwaysShowControls)
411
412
  return;
412
-
413
+
413
414
  if (doAnimation) {
414
415
  // fade out main controls
415
416
  t.controls.stop(true, true).fadeOut(200, function() {
416
417
  $(this)
417
418
  .css('visibility','hidden')
418
419
  .css('display','block');
419
-
420
+
420
421
  t.controlsAreVisible = false;
421
422
  t.container.trigger('controlshidden');
422
- });
423
-
423
+ });
424
+
424
425
  // any additional controls people might add and want to hide
425
426
  t.container.find('.mejs-control').stop(true, true).fadeOut(200, function() {
426
427
  $(this)
427
428
  .css('visibility','hidden')
428
429
  .css('display','block');
429
- });
430
+ });
430
431
  } else {
431
-
432
+
432
433
  // hide main controls
433
434
  t.controls
434
435
  .css('visibility','hidden')
435
- .css('display','block');
436
-
436
+ .css('display','block');
437
+
437
438
  // hide others
438
439
  t.container.find('.mejs-control')
439
440
  .css('visibility','hidden')
440
441
  .css('display','block');
441
-
442
+
442
443
  t.controlsAreVisible = false;
443
444
  t.container.trigger('controlshidden');
444
445
  }
445
- },
446
+ },
446
447
 
447
448
  controlsTimer: null,
448
449
 
449
450
  startControlsTimer: function(timeout) {
450
451
 
451
452
  var t = this;
452
-
453
+
453
454
  timeout = typeof timeout != 'undefined' ? timeout : 1500;
454
455
 
455
456
  t.killControlsTimer('start');
456
457
 
457
458
  t.controlsTimer = setTimeout(function() {
458
- //console.log('timer fired');
459
+ //
459
460
  t.hideControls();
460
461
  t.killControlsTimer('hide');
461
462
  }, timeout);
@@ -470,31 +471,31 @@ if (typeof jQuery != 'undefined') {
470
471
  delete t.controlsTimer;
471
472
  t.controlsTimer = null;
472
473
  }
473
- },
474
-
474
+ },
475
+
475
476
  controlsEnabled: true,
476
-
477
+
477
478
  disableControls: function() {
478
479
  var t= this;
479
-
480
+
480
481
  t.killControlsTimer();
481
482
  t.hideControls(false);
482
483
  this.controlsEnabled = false;
483
484
  },
484
-
485
+
485
486
  enableControls: function() {
486
487
  var t= this;
487
-
488
+
488
489
  t.showControls(false);
489
-
490
+
490
491
  t.controlsEnabled = true;
491
- },
492
-
492
+ },
493
+
493
494
 
494
495
  // Sets up all controls and events
495
- meReady: function(media, domNode) {
496
-
497
-
496
+ meReady: function(media, domNode) {
497
+
498
+
498
499
  var t = this,
499
500
  mf = mejs.MediaFeatures,
500
501
  autoplayAttr = domNode.getAttribute('autoplay'),
@@ -503,16 +504,17 @@ if (typeof jQuery != 'undefined') {
503
504
  feature;
504
505
 
505
506
  // make sure it can't create itself again if a plugin reloads
506
- if (t.created)
507
+ if (t.created) {
507
508
  return;
508
- else
509
- t.created = true;
509
+ } else {
510
+ t.created = true;
511
+ }
510
512
 
511
513
  t.media = media;
512
514
  t.domNode = domNode;
513
-
514
- if (!(mf.isAndroid && t.options.AndroidUseNativeControls) && !(mf.isiPad && t.options.iPadUseNativeControls) && !(mf.isiPhone && t.options.iPhoneUseNativeControls)) {
515
-
515
+
516
+ if (!(mf.isAndroid && t.options.AndroidUseNativeControls) && !(mf.isiPad && t.options.iPadUseNativeControls) && !(mf.isiPhone && t.options.iPhoneUseNativeControls)) {
517
+
516
518
  // two built in features
517
519
  t.buildposter(t, t.controls, t.layers, t.media);
518
520
  t.buildkeyboard(t, t.controls, t.layers, t.media);
@@ -530,30 +532,30 @@ if (typeof jQuery != 'undefined') {
530
532
  } catch (e) {
531
533
  // TODO: report control error
532
534
  //throw e;
533
- //console.log('error building ' + feature);
534
- //console.log(e);
535
+ //
536
+ //
535
537
  }
536
538
  }
537
539
  }
538
540
 
539
541
  t.container.trigger('controlsready');
540
-
542
+
541
543
  // reset all layers and controls
542
544
  t.setPlayerSize(t.width, t.height);
543
545
  t.setControlsSize();
544
-
546
+
545
547
 
546
548
  // controls fade
547
549
  if (t.isVideo) {
548
-
550
+
549
551
  if (mejs.MediaFeatures.hasTouch) {
550
-
552
+
551
553
  // for touch devices (iOS, Android)
552
554
  // show/hide without animation on touch
553
-
555
+
554
556
  t.$media.bind('touchstart', function() {
555
-
556
-
557
+
558
+
557
559
  // toggle controls
558
560
  if (t.controlsAreVisible) {
559
561
  t.hideControls(false);
@@ -562,28 +564,35 @@ if (typeof jQuery != 'undefined') {
562
564
  t.showControls(false);
563
565
  }
564
566
  }
565
- });
566
-
567
+ });
568
+
567
569
  } else {
568
- // click to play/pause
569
- t.media.addEventListener('click', function() {
570
- if (t.options.clickToPlayPause) {
571
- if (t.media.paused) {
572
- t.media.play();
573
- } else {
574
- t.media.pause();
575
- }
576
- }
577
- });
578
-
570
+
571
+ // create callback here since it needs access to current
572
+ // MediaElement object
573
+ mejs.MediaElementPlayer.prototype.clickToPlayPauseCallback = function() {
574
+ //
575
+
576
+ if (t.options.clickToPlayPause) {
577
+ if (t.media.paused) {
578
+ t.play();
579
+ } else {
580
+ t.pause();
581
+ }
582
+ }
583
+ };
584
+
585
+ // click to play/pause
586
+ t.media.addEventListener('click', t.clickToPlayPauseCallback, false);
587
+
579
588
  // show/hide controls
580
589
  t.container
581
590
  .bind('mouseenter mouseover', function () {
582
591
  if (t.controlsEnabled) {
583
- if (!t.options.alwaysShowControls) {
592
+ if (!t.options.alwaysShowControls) {
584
593
  t.killControlsTimer('enter');
585
594
  t.showControls();
586
- t.startControlsTimer(2500);
595
+ t.startControlsTimer(2500);
587
596
  }
588
597
  }
589
598
  })
@@ -601,7 +610,7 @@ if (typeof jQuery != 'undefined') {
601
610
  .bind('mouseleave', function () {
602
611
  if (t.controlsEnabled) {
603
612
  if (!t.media.paused && !t.options.alwaysShowControls) {
604
- t.startControlsTimer(1000);
613
+ t.startControlsTimer(1000);
605
614
  }
606
615
  }
607
616
  });
@@ -629,25 +638,25 @@ if (typeof jQuery != 'undefined') {
629
638
  }, false);
630
639
  }
631
640
  }
632
-
641
+
633
642
  // EVENTS
634
643
 
635
644
  // FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)
636
645
  media.addEventListener('play', function() {
637
- var playerIndex;
638
-
639
- // go through all other players
640
- for (playerIndex in mejs.players) {
641
- var p = mejs.players[playerIndex];
642
- if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
643
- p.pause();
644
- }
645
- p.hasFocus = false;
646
+ var playerIndex;
647
+
648
+ // go through all other players
649
+ for (playerIndex in mejs.players) {
650
+ var p = mejs.players[playerIndex];
651
+ if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
652
+ p.pause();
646
653
  }
647
-
648
- t.hasFocus = true;
654
+ p.hasFocus = false;
655
+ }
656
+
657
+ t.hasFocus = true;
649
658
  },false);
650
-
659
+
651
660
 
652
661
  // ended for all
653
662
  t.media.addEventListener('ended', function (e) {
@@ -655,23 +664,25 @@ if (typeof jQuery != 'undefined') {
655
664
  try{
656
665
  t.media.setCurrentTime(0);
657
666
  } catch (exp) {
658
-
667
+
659
668
  }
660
669
  }
661
670
  t.media.pause();
662
-
663
- if (t.setProgressRail)
671
+
672
+ if (t.setProgressRail) {
664
673
  t.setProgressRail();
665
- if (t.setCurrentRail)
666
- t.setCurrentRail();
674
+ }
675
+ if (t.setCurrentRail) {
676
+ t.setCurrentRail();
677
+ }
667
678
 
668
679
  if (t.options.loop) {
669
- t.media.play();
680
+ t.play();
670
681
  } else if (!t.options.alwaysShowControls && t.controlsEnabled) {
671
682
  t.showControls();
672
683
  }
673
684
  }, false);
674
-
685
+
675
686
  // resize on the first play
676
687
  t.media.addEventListener('loadedmetadata', function(e) {
677
688
  if (t.updateDuration) {
@@ -680,7 +691,7 @@ if (typeof jQuery != 'undefined') {
680
691
  if (t.updateCurrent) {
681
692
  t.updateCurrent();
682
693
  }
683
-
694
+
684
695
  if (!t.isFullScreen) {
685
696
  t.setPlayerSize(t.width, t.height);
686
697
  t.setControlsSize();
@@ -693,47 +704,46 @@ if (typeof jQuery != 'undefined') {
693
704
  t.setPlayerSize(t.width, t.height);
694
705
  t.setControlsSize();
695
706
  }, 50);
696
-
707
+
697
708
  // adjust controls whenever window sizes (used to be in fullscreen only)
698
709
  t.globalBind('resize', function() {
699
-
700
- // don't resize for fullscreen mode
710
+
711
+ // don't resize for fullscreen mode
701
712
  if ( !(t.isFullScreen || (mejs.MediaFeatures.hasTrueNativeFullScreen && document.webkitIsFullScreen)) ) {
702
713
  t.setPlayerSize(t.width, t.height);
703
714
  }
704
-
715
+
705
716
  // always adjust controls
706
717
  t.setControlsSize();
707
- });
718
+ });
708
719
 
709
720
  // TEMP: needs to be moved somewhere else
710
721
  if (t.media.pluginType == 'youtube') {
711
- t.container.find('.mejs-overlay-play').hide();
722
+ t.container.find('.mejs-overlay-play').hide();
712
723
  }
713
724
  }
714
-
725
+
715
726
  // force autoplay for HTML5
716
727
  if (autoplay && media.pluginType == 'native') {
717
- media.load();
718
- media.play();
728
+ t.play();
719
729
  }
720
730
 
721
731
 
722
732
  if (t.options.success) {
723
-
733
+
724
734
  if (typeof t.options.success == 'string') {
725
- window[t.options.success](t.media, t.domNode, t);
735
+ window[t.options.success](t.media, t.domNode, t);
726
736
  } else {
727
- t.options.success(t.media, t.domNode, t);
737
+ t.options.success(t.media, t.domNode, t);
728
738
  }
729
739
  }
730
740
  },
731
741
 
732
742
  handleError: function(e) {
733
743
  var t = this;
734
-
744
+
735
745
  t.controls.hide();
736
-
746
+
737
747
  // Tell user that the file cannot be played
738
748
  if (t.options.error) {
739
749
  t.options.error(e);
@@ -743,27 +753,29 @@ if (typeof jQuery != 'undefined') {
743
753
  setPlayerSize: function(width,height) {
744
754
  var t = this;
745
755
 
746
- if (typeof width != 'undefined')
756
+ if (typeof width != 'undefined') {
747
757
  t.width = width;
748
-
749
- if (typeof height != 'undefined')
758
+ }
759
+
760
+ if (typeof height != 'undefined') {
750
761
  t.height = height;
762
+ }
763
+
764
+ // detect 100% mode - use currentStyle for IE since css() doesn't return percentages
765
+ if (t.height.toString().indexOf('%') > 0 || t.$node.css('max-width') === '100%' || parseInt(t.$node.css('max-width').replace(/px/,''), 10) / t.$node.offsetParent().width() === 1 || (t.$node[0].currentStyle && t.$node[0].currentStyle.maxWidth === '100%')) {
751
766
 
752
- // detect 100% mode - use currentStyle for IE since css() doesn't return percentages
753
- if (t.height.toString().indexOf('%') > 0 || t.$node.css('max-width') === '100%' || (t.$node[0].currentStyle && t.$node[0].currentStyle.maxWidth === '100%')) {
754
-
755
767
  // do we have the native dimensions yet?
756
- var
768
+ var
757
769
  nativeWidth = t.isVideo ? ((t.media.videoWidth && t.media.videoWidth > 0) ? t.media.videoWidth : t.options.defaultVideoWidth) : t.options.defaultAudioWidth,
758
770
  nativeHeight = t.isVideo ? ((t.media.videoHeight && t.media.videoHeight > 0) ? t.media.videoHeight : t.options.defaultVideoHeight) : t.options.defaultAudioHeight,
759
771
  parentWidth = t.container.parent().closest(':visible').width(),
760
772
  newHeight = t.isVideo || !t.options.autosizeProgress ? parseInt(parentWidth * nativeHeight/nativeWidth, 10) : nativeHeight;
761
-
773
+
762
774
  if (t.container.parent()[0].tagName.toLowerCase() === 'body') { // && t.container.siblings().count == 0) {
763
775
  parentWidth = $(window).width();
764
776
  newHeight = $(window).height();
765
777
  }
766
-
778
+
767
779
  if ( newHeight != 0 && parentWidth != 0 ) {
768
780
  // set outer container size
769
781
  t.container
@@ -775,31 +787,39 @@ if (typeof jQuery != 'undefined') {
775
787
  .width('100%')
776
788
  .height('100%');
777
789
 
778
- // if shim is ready, send the size to the embeded plugin
790
+ // if shim is ready, send the size to the embeded plugin
779
791
  if (t.isVideo) {
780
792
  if (t.media.setVideoSize) {
781
793
  t.media.setVideoSize(parentWidth, newHeight);
782
794
  }
783
795
  }
784
-
796
+
785
797
  // set the layers
786
798
  t.layers.children('.mejs-layer')
787
799
  .width('100%')
788
800
  .height('100%');
789
801
  }
790
-
791
-
802
+
803
+
792
804
  } else {
793
805
 
794
806
  t.container
795
807
  .width(t.width)
796
808
  .height(t.height);
797
-
809
+
798
810
  t.layers.children('.mejs-layer')
799
811
  .width(t.width)
800
812
  .height(t.height);
801
-
813
+
802
814
  }
815
+
816
+ // special case for big play button so it doesn't go over the controls area
817
+ var playLayer = t.layers.find('.mejs-overlay-play'),
818
+ playButton = playLayer.find('.mejs-overlay-button');
819
+
820
+ playLayer.height(t.container.height() - t.controls.height());
821
+ playButton.css('margin-top', '-' + (playButton.height()/2 - t.controls.height()/2).toString() + 'px' );
822
+
803
823
  },
804
824
 
805
825
  setControlsSize: function() {
@@ -811,18 +831,18 @@ if (typeof jQuery != 'undefined') {
811
831
  current = t.controls.find('.mejs-time-current'),
812
832
  loaded = t.controls.find('.mejs-time-loaded'),
813
833
  others = rail.siblings();
814
-
834
+
815
835
 
816
836
  // allow the size to come from custom CSS
817
837
  if (t.options && !t.options.autosizeProgress) {
818
- // Also, frontends devs can be more flexible
838
+ // Also, frontends devs can be more flexible
819
839
  // due the opportunity of absolute positioning.
820
840
  railWidth = parseInt(rail.css('width'));
821
841
  }
822
-
842
+
823
843
  // attempt to autosize
824
844
  if (railWidth === 0 || !railWidth) {
825
-
845
+
826
846
  // find the size of all the other controls besides the rail
827
847
  others.each(function() {
828
848
  var $this = $(this);
@@ -830,7 +850,7 @@ if (typeof jQuery != 'undefined') {
830
850
  usedWidth += $(this).outerWidth(true);
831
851
  }
832
852
  });
833
-
853
+
834
854
  // fit the rail into the remaining space
835
855
  railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.width());
836
856
  }
@@ -839,17 +859,17 @@ if (typeof jQuery != 'undefined') {
839
859
  rail.width(railWidth);
840
860
  // dark space
841
861
  total.width(railWidth - (total.outerWidth(true) - total.width()));
842
-
862
+
843
863
  if (t.setProgressRail)
844
864
  t.setProgressRail();
845
865
  if (t.setCurrentRail)
846
- t.setCurrentRail();
866
+ t.setCurrentRail();
847
867
  },
848
868
 
849
869
 
850
870
  buildposter: function(player, controls, layers, media) {
851
871
  var t = this,
852
- poster =
872
+ poster =
853
873
  $('<div class="mejs-poster mejs-layer">' +
854
874
  '</div>')
855
875
  .appendTo(layers),
@@ -858,8 +878,8 @@ if (typeof jQuery != 'undefined') {
858
878
  // prioriy goes to option (this is useful if you need to support iOS 3.x (iOS completely fails with poster)
859
879
  if (player.options.poster !== '') {
860
880
  posterUrl = player.options.poster;
861
- }
862
-
881
+ }
882
+
863
883
  // second, try the real poster
864
884
  if (posterUrl !== '' && posterUrl != null) {
865
885
  t.setPoster(posterUrl);
@@ -870,18 +890,25 @@ if (typeof jQuery != 'undefined') {
870
890
  media.addEventListener('play',function() {
871
891
  poster.hide();
872
892
  }, false);
893
+
894
+ if(player.options.showPosterWhenEnded && player.options.autoRewind){
895
+ media.addEventListener('ended',function() {
896
+ poster.show();
897
+ }, false);
898
+ }
873
899
  },
874
-
900
+
875
901
  setPoster: function(url) {
876
902
  var t = this,
877
903
  posterDiv = t.container.find('.mejs-poster'),
878
904
  posterImg = posterDiv.find('img');
879
-
905
+
880
906
  if (posterImg.length == 0) {
881
907
  posterImg = $('<img width="100%" height="100%" />').appendTo(posterDiv);
882
- }
883
-
908
+ }
909
+
884
910
  posterImg.attr('src', url);
911
+ posterDiv.css({'background-image' : 'url(' + url + ')'});
885
912
  },
886
913
 
887
914
  buildoverlays: function(player, controls, layers, media) {
@@ -889,42 +916,40 @@ if (typeof jQuery != 'undefined') {
889
916
  if (!player.isVideo)
890
917
  return;
891
918
 
892
- var
893
- loading =
919
+ var
920
+ loading =
894
921
  $('<div class="mejs-overlay mejs-layer">'+
895
922
  '<div class="mejs-overlay-loading"><span></span></div>'+
896
923
  '</div>')
897
924
  .hide() // start out hidden
898
925
  .appendTo(layers),
899
- error =
926
+ error =
900
927
  $('<div class="mejs-overlay mejs-layer">'+
901
928
  '<div class="mejs-overlay-error"></div>'+
902
929
  '</div>')
903
930
  .hide() // start out hidden
904
931
  .appendTo(layers),
905
932
  // this needs to come last so it's on top
906
- bigPlay =
933
+ bigPlay =
907
934
  $('<div class="mejs-overlay mejs-layer mejs-overlay-play">'+
908
935
  '<div class="mejs-overlay-button"></div>'+
909
936
  '</div>')
910
937
  .appendTo(layers)
911
- .click(function() {
912
- if (t.options.clickToPlayPause) {
913
- if (media.paused) {
914
- media.play();
915
- } else {
916
- media.pause();
917
- }
918
- }
938
+ .bind('click touchstart', function() {
939
+ if (t.options.clickToPlayPause) {
940
+ if (media.paused) {
941
+ t.play();
942
+ }
943
+ }
919
944
  });
920
-
945
+
921
946
  /*
922
947
  if (mejs.MediaFeatures.isiOS || mejs.MediaFeatures.isAndroid) {
923
948
  bigPlay.remove();
924
949
  loading.remove();
925
950
  }
926
951
  */
927
-
952
+
928
953
 
929
954
  // show/hide big play button
930
955
  media.addEventListener('play',function() {
@@ -932,13 +957,13 @@ if (typeof jQuery != 'undefined') {
932
957
  loading.hide();
933
958
  controls.find('.mejs-time-buffering').hide();
934
959
  error.hide();
935
- }, false);
936
-
960
+ }, false);
961
+
937
962
  media.addEventListener('playing', function() {
938
963
  bigPlay.hide();
939
964
  loading.hide();
940
965
  controls.find('.mejs-time-buffering').hide();
941
- error.hide();
966
+ error.hide();
942
967
  }, false);
943
968
 
944
969
  media.addEventListener('seeking', function() {
@@ -950,32 +975,32 @@ if (typeof jQuery != 'undefined') {
950
975
  loading.hide();
951
976
  controls.find('.mejs-time-buffering').hide();
952
977
  }, false);
953
-
978
+
954
979
  media.addEventListener('pause',function() {
955
980
  if (!mejs.MediaFeatures.isiPhone) {
956
981
  bigPlay.show();
957
982
  }
958
983
  }, false);
959
-
984
+
960
985
  media.addEventListener('waiting', function() {
961
- loading.show();
986
+ loading.show();
962
987
  controls.find('.mejs-time-buffering').show();
963
- }, false);
964
-
965
-
966
- // show/hide loading
988
+ }, false);
989
+
990
+
991
+ // show/hide loading
967
992
  media.addEventListener('loadeddata',function() {
968
993
  // for some reason Chrome is firing this event
969
994
  //if (mejs.MediaFeatures.isChrome && media.getAttribute && media.getAttribute('preload') === 'none')
970
995
  // return;
971
-
996
+
972
997
  loading.show();
973
998
  controls.find('.mejs-time-buffering').show();
974
- }, false);
999
+ }, false);
975
1000
  media.addEventListener('canplay',function() {
976
1001
  loading.hide();
977
1002
  controls.find('.mejs-time-buffering').hide();
978
- }, false);
1003
+ }, false);
979
1004
 
980
1005
  // error handling
981
1006
  media.addEventListener('error',function() {
@@ -983,42 +1008,42 @@ if (typeof jQuery != 'undefined') {
983
1008
  controls.find('.mejs-time-buffering').hide();
984
1009
  error.show();
985
1010
  error.find('mejs-overlay-error').html("Error loading this resource");
986
- }, false);
1011
+ }, false);
987
1012
  },
988
-
1013
+
989
1014
  buildkeyboard: function(player, controls, layers, media) {
990
1015
 
991
1016
  var t = this;
992
-
1017
+
993
1018
  // listen for key presses
994
1019
  t.globalBind('keydown', function(e) {
995
-
1020
+
996
1021
  if (player.hasFocus && player.options.enableKeyboard) {
997
-
1022
+
998
1023
  // find a matching key
999
1024
  for (var i=0, il=player.options.keyActions.length; i<il; i++) {
1000
1025
  var keyAction = player.options.keyActions[i];
1001
-
1026
+
1002
1027
  for (var j=0, jl=keyAction.keys.length; j<jl; j++) {
1003
1028
  if (e.keyCode == keyAction.keys[j]) {
1004
1029
  e.preventDefault();
1005
1030
  keyAction.action(player, media, e.keyCode);
1006
1031
  return false;
1007
- }
1032
+ }
1008
1033
  }
1009
1034
  }
1010
1035
  }
1011
-
1036
+
1012
1037
  return true;
1013
1038
  });
1014
-
1039
+
1015
1040
  // check if someone clicked outside a player region, then kill its focus
1016
1041
  t.globalBind('click', function(event) {
1017
1042
  if ($(event.target).closest('.mejs-container').length == 0) {
1018
1043
  player.hasFocus = false;
1019
1044
  }
1020
1045
  });
1021
-
1046
+
1022
1047
  },
1023
1048
 
1024
1049
  findTracks: function() {
@@ -1028,9 +1053,9 @@ if (typeof jQuery != 'undefined') {
1028
1053
  // store for use by plugins
1029
1054
  t.tracks = [];
1030
1055
  tracktags.each(function(index, track) {
1031
-
1056
+
1032
1057
  track = $(track);
1033
-
1058
+
1034
1059
  t.tracks.push({
1035
1060
  srclang: (track.attr('srclang')) ? track.attr('srclang').toLowerCase() : '',
1036
1061
  src: track.attr('src'),
@@ -1047,13 +1072,20 @@ if (typeof jQuery != 'undefined') {
1047
1072
  this.setControlsSize();
1048
1073
  },
1049
1074
  play: function() {
1075
+ this.load();
1050
1076
  this.media.play();
1051
1077
  },
1052
1078
  pause: function() {
1053
- this.media.pause();
1079
+ try {
1080
+ this.media.pause();
1081
+ } catch (e) {}
1054
1082
  },
1055
1083
  load: function() {
1056
- this.media.load();
1084
+ if (!this.isLoaded) {
1085
+ this.media.load();
1086
+ }
1087
+
1088
+ this.isLoaded = true;
1057
1089
  },
1058
1090
  setMuted: function(muted) {
1059
1091
  this.media.setMuted(muted);
@@ -1075,7 +1107,7 @@ if (typeof jQuery != 'undefined') {
1075
1107
  },
1076
1108
  remove: function() {
1077
1109
  var t = this, featureIndex, feature;
1078
-
1110
+
1079
1111
  // invoke features cleanup
1080
1112
  for (featureIndex in t.options.features) {
1081
1113
  feature = t.options.features[featureIndex];
@@ -1085,37 +1117,34 @@ if (typeof jQuery != 'undefined') {
1085
1117
  } catch (e) {
1086
1118
  // TODO: report control error
1087
1119
  //throw e;
1088
- //console.log('error building ' + feature);
1089
- //console.log(e);
1120
+ //
1121
+ //
1090
1122
  }
1091
1123
  }
1092
1124
  }
1093
1125
 
1094
- if (t.media.pluginType === 'native') {
1126
+ // grab video and put it back in place
1127
+ if (!t.isDynamic) {
1095
1128
  t.$media.prop('controls', true);
1129
+ // detach events from the video
1130
+ // TODO: detach event listeners better than this;
1131
+ // also detach ONLY the events attached by this plugin!
1132
+ t.$node.clone().show().insertBefore(t.container);
1133
+ t.$node.remove();
1096
1134
  } else {
1097
- t.media.remove();
1135
+ t.$node.insertBefore(t.container);
1098
1136
  }
1099
-
1100
- // grab video and put it back in place
1101
- if (!t.isDynamic) {
1102
- if (t.media.pluginType === 'native') {
1103
- // detach events from the video
1104
- // TODO: detach event listeners better than this;
1105
- // also detach ONLY the events attached by this plugin!
1106
- //t.$node.clone().insertBefore(t.container);
1107
- //t.$node.remove();
1108
- }
1109
- /*else*/ t.$node.insertBefore(t.container)
1137
+
1138
+ if (t.media.pluginType !== 'native') {
1139
+ t.media.remove();
1110
1140
  }
1111
1141
 
1112
- // Remove the player from the mejs.players array so that pauseOtherPlayers doesn't blow up when trying to pause a non existance flash api.
1113
- mejs.players.splice( $.inArray( t, mejs.players ), 1);
1114
-
1142
+ // Remove the player from the mejs.players object so that pauseOtherPlayers doesn't blow up when trying to pause a non existance flash api.
1143
+ delete mejs.players[t.id];
1144
+
1115
1145
  t.container.remove();
1116
1146
  t.globalUnbind();
1117
1147
  delete t.node.player;
1118
- delete mejs.players[t.id];
1119
1148
  }
1120
1149
  };
1121
1150
 
@@ -1126,7 +1155,14 @@ if (typeof jQuery != 'undefined') {
1126
1155
  // add player ID as an event namespace so it's easier to unbind them all later
1127
1156
  var ret = {d: [], w: []};
1128
1157
  $.each((events || '').split(' '), function(k, v){
1129
- ret[rwindow.test(v) ? 'w' : 'd'].push(v + '.' + id);
1158
+ var eventname = v + '.' + id;
1159
+ if (eventname.indexOf('.') === 0) {
1160
+ ret.d.push(eventname);
1161
+ ret.w.push(eventname);
1162
+ }
1163
+ else {
1164
+ ret[rwindow.test(v) ? 'w' : 'd'].push(eventname);
1165
+ }
1130
1166
  });
1131
1167
  ret.d = ret.d.join(' ');
1132
1168
  ret.w = ret.w.join(' ');
@@ -1168,12 +1204,12 @@ if (typeof jQuery != 'undefined') {
1168
1204
  return this;
1169
1205
  };
1170
1206
  }
1171
-
1207
+
1172
1208
  $(document).ready(function() {
1173
1209
  // auto enable using JSON attribute
1174
1210
  $('.mejs-player').mediaelementplayer();
1175
1211
  });
1176
-
1212
+
1177
1213
  // push out to window
1178
1214
  window.MediaElementPlayer = mejs.MediaElementPlayer;
1179
1215
 
@@ -1182,7 +1218,7 @@ if (typeof jQuery != 'undefined') {
1182
1218
  (function($) {
1183
1219
 
1184
1220
  $.extend(mejs.MepDefaults, {
1185
- playpauseText: 'Play/Pause'
1221
+ playpauseText: mejs.i18n.t('Play/Pause')
1186
1222
  });
1187
1223
 
1188
1224
  // PLAY/pause BUTTON
@@ -1192,7 +1228,7 @@ if (typeof jQuery != 'undefined') {
1192
1228
  t = this,
1193
1229
  play =
1194
1230
  $('<div class="mejs-button mejs-playpause-button mejs-play" >' +
1195
- '<button type="button" aria-controls="' + t.id + '" title="' + t.options.playpauseText + '"></button>' +
1231
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.playpauseText + '" aria-label="' + t.options.playpauseText + '"></button>' +
1196
1232
  '</div>')
1197
1233
  .appendTo(controls)
1198
1234
  .click(function(e) {
@@ -1225,6 +1261,7 @@ if (typeof jQuery != 'undefined') {
1225
1261
  });
1226
1262
 
1227
1263
  })(mejs.$);
1264
+
1228
1265
  (function($) {
1229
1266
 
1230
1267
  $.extend(mejs.MepDefaults, {
@@ -1237,7 +1274,7 @@ if (typeof jQuery != 'undefined') {
1237
1274
  var t = this,
1238
1275
  stop =
1239
1276
  $('<div class="mejs-button mejs-stop-button mejs-stop">' +
1240
- '<button type="button" aria-controls="' + t.id + '" title="' + t.options.stopText + '"></button>' +
1277
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.stopText + '" aria-label="' + t.options.stopText + '"></button>' +
1241
1278
  '</div>')
1242
1279
  .appendTo(controls)
1243
1280
  .click(function() {
@@ -1258,6 +1295,7 @@ if (typeof jQuery != 'undefined') {
1258
1295
  });
1259
1296
 
1260
1297
  })(mejs.$);
1298
+
1261
1299
  (function($) {
1262
1300
  // progress/loaded bar
1263
1301
  $.extend(MediaElementPlayer.prototype, {
@@ -1437,7 +1475,7 @@ if (typeof jQuery != 'undefined') {
1437
1475
  // options
1438
1476
  $.extend(mejs.MepDefaults, {
1439
1477
  duration: -1,
1440
- timeAndDurationSeparator: ' <span> | </span> '
1478
+ timeAndDurationSeparator: '<span> | </span>'
1441
1479
  });
1442
1480
 
1443
1481
 
@@ -1516,10 +1554,11 @@ if (typeof jQuery != 'undefined') {
1516
1554
  });
1517
1555
 
1518
1556
  })(mejs.$);
1557
+
1519
1558
  (function($) {
1520
1559
 
1521
1560
  $.extend(mejs.MepDefaults, {
1522
- muteText: 'Mute Toggle',
1561
+ muteText: mejs.i18n.t('Mute Toggle'),
1523
1562
  hideVolumeOnTouchDevices: true,
1524
1563
 
1525
1564
  audioVolume: 'horizontal',
@@ -1539,7 +1578,7 @@ if (typeof jQuery != 'undefined') {
1539
1578
 
1540
1579
  // horizontal version
1541
1580
  $('<div class="mejs-button mejs-volume-button mejs-mute">'+
1542
- '<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '"></button>'+
1581
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '" aria-label="' + t.options.muteText + '"></button>'+
1543
1582
  '</div>' +
1544
1583
  '<div class="mejs-horizontal-volume-slider">'+ // outer background
1545
1584
  '<div class="mejs-horizontal-volume-total"></div>'+ // line background
@@ -1551,7 +1590,7 @@ if (typeof jQuery != 'undefined') {
1551
1590
 
1552
1591
  // vertical version
1553
1592
  $('<div class="mejs-button mejs-volume-button mejs-mute">'+
1554
- '<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '"></button>'+
1593
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '" aria-label="' + t.options.muteText + '"></button>'+
1555
1594
  '<div class="mejs-volume-slider">'+ // outer background
1556
1595
  '<div class="mejs-volume-total"></div>'+ // line background
1557
1596
  '<div class="mejs-volume-current"></div>'+ // current volume
@@ -1756,8 +1795,6 @@ if (typeof jQuery != 'undefined') {
1756
1795
 
1757
1796
  isNativeFullScreen: false,
1758
1797
 
1759
- docStyleOverflow: null,
1760
-
1761
1798
  isInIframe: false,
1762
1799
 
1763
1800
  buildfullscreen: function(player, controls, layers, media) {
@@ -1772,16 +1809,17 @@ if (typeof jQuery != 'undefined') {
1772
1809
 
1773
1810
  // chrome doesn't alays fire this in an iframe
1774
1811
  var func = function(e) {
1775
-
1776
- if (mejs.MediaFeatures.isFullScreen()) {
1777
- player.isNativeFullScreen = true;
1778
- // reset the controls once we are fully in full screen
1779
- player.setControlsSize();
1780
- } else {
1781
- player.isNativeFullScreen = false;
1782
- // when a user presses ESC
1783
- // make sure to put the player back into place
1784
- player.exitFullScreen();
1812
+ if (player.isFullScreen) {
1813
+ if (mejs.MediaFeatures.isFullScreen()) {
1814
+ player.isNativeFullScreen = true;
1815
+ // reset the controls once we are fully in full screen
1816
+ player.setControlsSize();
1817
+ } else {
1818
+ player.isNativeFullScreen = false;
1819
+ // when a user presses ESC
1820
+ // make sure to put the player back into place
1821
+ player.exitFullScreen();
1822
+ }
1785
1823
  }
1786
1824
  };
1787
1825
 
@@ -1798,7 +1836,7 @@ if (typeof jQuery != 'undefined') {
1798
1836
  container = player.container,
1799
1837
  fullscreenBtn =
1800
1838
  $('<div class="mejs-button mejs-fullscreen-button">' +
1801
- '<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
1839
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '" aria-label="' + t.options.fullscreenText + '"></button>' +
1802
1840
  '</div>')
1803
1841
  .appendTo(controls);
1804
1842
 
@@ -1835,7 +1873,7 @@ if (typeof jQuery != 'undefined') {
1835
1873
  return !!supports;
1836
1874
  })();
1837
1875
 
1838
- //console.log('supportsPointerEvents', supportsPointerEvents);
1876
+ //
1839
1877
 
1840
1878
  if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(
1841
1879
 
@@ -1852,89 +1890,116 @@ if (typeof jQuery != 'undefined') {
1852
1890
  restoreControls = function() {
1853
1891
  if (fullscreenIsDisabled) {
1854
1892
  // hide the hovers
1855
- videoHoverDiv.hide();
1856
- controlsLeftHoverDiv.hide();
1857
- controlsRightHoverDiv.hide();
1893
+ for (var i in hoverDivs) {
1894
+ hoverDivs[i].hide();
1895
+ }
1858
1896
 
1859
1897
  // restore the control bar
1860
1898
  fullscreenBtn.css('pointer-events', '');
1861
1899
  t.controls.css('pointer-events', '');
1862
1900
 
1901
+ // prevent clicks from pausing video
1902
+ t.media.removeEventListener('click', t.clickToPlayPauseCallback);
1903
+
1863
1904
  // store for later
1864
1905
  fullscreenIsDisabled = false;
1865
1906
  }
1866
1907
  },
1867
- videoHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1868
- controlsLeftHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1869
- controlsRightHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1908
+ hoverDivs = {},
1909
+ hoverDivNames = ['top', 'left', 'right', 'bottom'],
1910
+ i, len,
1870
1911
  positionHoverDivs = function() {
1871
- var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
1872
- videoHoverDiv.css(style);
1873
- controlsLeftHoverDiv.css(style);
1874
- controlsRightHoverDiv.css(style);
1912
+ var fullScreenBtnOffsetLeft = fullscreenBtn.offset().left - t.container.offset().left,
1913
+ fullScreenBtnOffsetTop = fullscreenBtn.offset().top - t.container.offset().top,
1914
+ fullScreenBtnWidth = fullscreenBtn.outerWidth(true),
1915
+ fullScreenBtnHeight = fullscreenBtn.outerHeight(true),
1916
+ containerWidth = t.container.width(),
1917
+ containerHeight = t.container.height();
1918
+
1919
+ for (i in hoverDivs) {
1920
+ hoverDivs[i].css({position: 'absolute', top: 0, left: 0}); //, backgroundColor: '#f00'});
1921
+ }
1875
1922
 
1876
1923
  // over video, but not controls
1877
- videoHoverDiv
1878
- .width( t.container.width() )
1879
- .height( t.container.height() - t.controls.height() );
1924
+ hoverDivs['top']
1925
+ .width( containerWidth )
1926
+ .height( fullScreenBtnOffsetTop );
1880
1927
 
1881
1928
  // over controls, but not the fullscreen button
1882
- var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
1883
- fullScreenBtnWidth = fullscreenBtn.outerWidth(true);
1884
-
1885
- controlsLeftHoverDiv
1886
- .width( fullScreenBtnOffset )
1887
- .height( t.controls.height() )
1888
- .css({top: t.container.height() - t.controls.height()});
1929
+ hoverDivs['left']
1930
+ .width( fullScreenBtnOffsetLeft )
1931
+ .height( fullScreenBtnHeight )
1932
+ .css({top: fullScreenBtnOffsetTop});
1889
1933
 
1890
1934
  // after the fullscreen button
1891
- controlsRightHoverDiv
1892
- .width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
1893
- .height( t.controls.height() )
1894
- .css({top: t.container.height() - t.controls.height(),
1895
- left: fullScreenBtnOffset + fullScreenBtnWidth});
1935
+ hoverDivs['right']
1936
+ .width( containerWidth - fullScreenBtnOffsetLeft - fullScreenBtnWidth )
1937
+ .height( fullScreenBtnHeight )
1938
+ .css({top: fullScreenBtnOffsetTop,
1939
+ left: fullScreenBtnOffsetLeft + fullScreenBtnWidth});
1940
+
1941
+ // under the fullscreen button
1942
+ hoverDivs['bottom']
1943
+ .width( containerWidth )
1944
+ .height( containerHeight - fullScreenBtnHeight - fullScreenBtnOffsetTop )
1945
+ .css({top: fullScreenBtnOffsetTop + fullScreenBtnHeight});
1896
1946
  };
1897
1947
 
1898
1948
  t.globalBind('resize', function() {
1899
1949
  positionHoverDivs();
1900
1950
  });
1901
1951
 
1952
+ for (i = 0, len = hoverDivNames.length; i < len; i++) {
1953
+ hoverDivs[hoverDivNames[i]] = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls).hide();
1954
+ }
1955
+
1902
1956
  // on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
1903
- fullscreenBtn
1904
- .mouseover(function() {
1957
+ fullscreenBtn.on('mouseover',function() {
1905
1958
 
1906
- if (!t.isFullScreen) {
1959
+ if (!t.isFullScreen) {
1907
1960
 
1908
- var buttonPos = fullscreenBtn.offset(),
1909
- containerPos = player.container.offset();
1961
+ var buttonPos = fullscreenBtn.offset(),
1962
+ containerPos = player.container.offset();
1910
1963
 
1911
- // move the button in Flash into place
1912
- media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);
1964
+ // move the button in Flash into place
1965
+ media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);
1913
1966
 
1914
- // allows click through
1915
- fullscreenBtn.css('pointer-events', 'none');
1916
- t.controls.css('pointer-events', 'none');
1967
+ // allows click through
1968
+ fullscreenBtn.css('pointer-events', 'none');
1969
+ t.controls.css('pointer-events', 'none');
1917
1970
 
1918
- // show the divs that will restore things
1919
- videoHoverDiv.show();
1920
- controlsRightHoverDiv.show();
1921
- controlsLeftHoverDiv.show();
1922
- positionHoverDivs();
1971
+ // restore click-to-play
1972
+ t.media.addEventListener('click', t.clickToPlayPauseCallback);
1923
1973
 
1924
- fullscreenIsDisabled = true;
1974
+ // show the divs that will restore things
1975
+ for (i in hoverDivs) {
1976
+ hoverDivs[i].show();
1925
1977
  }
1926
1978
 
1927
- });
1979
+ positionHoverDivs();
1980
+
1981
+ fullscreenIsDisabled = true;
1982
+ }
1983
+
1984
+ });
1928
1985
 
1929
1986
  // restore controls anytime the user enters or leaves fullscreen
1930
1987
  media.addEventListener('fullscreenchange', function(e) {
1988
+ t.isFullScreen = !t.isFullScreen;
1989
+ // don't allow plugin click to pause video - messes with
1990
+ // plugin's controls
1991
+ if (t.isFullScreen) {
1992
+ t.media.removeEventListener('click', t.clickToPlayPauseCallback);
1993
+ } else {
1994
+ t.media.addEventListener('click', t.clickToPlayPauseCallback);
1995
+ }
1931
1996
  restoreControls();
1932
1997
  });
1933
1998
 
1934
1999
 
1935
2000
  // the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
1936
2001
  // so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
1937
- /*
2002
+
1938
2003
  t.globalBind('mousemove', function(e) {
1939
2004
 
1940
2005
  // if the mouse is anywhere but the fullsceen button, then restore it all
@@ -1954,7 +2019,7 @@ if (typeof jQuery != 'undefined') {
1954
2019
  }
1955
2020
  }
1956
2021
  });
1957
- */
2022
+
1958
2023
 
1959
2024
 
1960
2025
  } else {
@@ -1962,7 +2027,7 @@ if (typeof jQuery != 'undefined') {
1962
2027
  // the hover state will show the fullscreen button in Flash to hover up and click
1963
2028
 
1964
2029
  fullscreenBtn
1965
- .mouseover(function() {
2030
+ .on('mouseover', function() {
1966
2031
 
1967
2032
  if (hideTimeout !== null) {
1968
2033
  clearTimeout(hideTimeout);
@@ -1975,7 +2040,7 @@ if (typeof jQuery != 'undefined') {
1975
2040
  media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);
1976
2041
 
1977
2042
  })
1978
- .mouseout(function() {
2043
+ .on('mouseout', function() {
1979
2044
 
1980
2045
  if (hideTimeout !== null) {
1981
2046
  clearTimeout(hideTimeout);
@@ -2005,6 +2070,8 @@ if (typeof jQuery != 'undefined') {
2005
2070
  player.exitFullScreen();
2006
2071
  },
2007
2072
 
2073
+ containerSizeTimeout: null,
2074
+
2008
2075
  enterFullScreen: function() {
2009
2076
 
2010
2077
  var t = this;
@@ -2016,10 +2083,8 @@ if (typeof jQuery != 'undefined') {
2016
2083
  return;
2017
2084
  }
2018
2085
 
2019
- // store overflow
2020
- docStyleOverflow = document.documentElement.style.overflow;
2021
2086
  // set it to not show scroll bars so 100% will work
2022
- document.documentElement.style.overflow = 'hidden';
2087
+ $(document.documentElement).addClass('mejs-fullscreen');
2023
2088
 
2024
2089
  // store sizing
2025
2090
  normalHeight = t.container.height();
@@ -2097,13 +2162,13 @@ if (typeof jQuery != 'undefined') {
2097
2162
  // Only needed for safari 5.1 native full screen, can cause display issues elsewhere
2098
2163
  // Actually, it seems to be needed for IE8, too
2099
2164
  //if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
2100
- setTimeout(function() {
2165
+ t.containerSizeTimeout = setTimeout(function() {
2101
2166
  t.container.css({width: '100%', height: '100%'});
2102
2167
  t.setControlsSize();
2103
2168
  }, 500);
2104
2169
  //}
2105
2170
 
2106
- if (t.pluginType === 'native') {
2171
+ if (t.media.pluginType === 'native') {
2107
2172
  t.$media
2108
2173
  .width('100%')
2109
2174
  .height('100%');
@@ -2135,6 +2200,9 @@ if (typeof jQuery != 'undefined') {
2135
2200
 
2136
2201
  var t = this;
2137
2202
 
2203
+ // Prevent container from attempting to stretch a second time
2204
+ clearTimeout(t.containerSizeTimeout);
2205
+
2138
2206
  // firefox can't adjust plugins
2139
2207
  if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
2140
2208
  t.media.setFullscreen(false);
@@ -2148,7 +2216,7 @@ if (typeof jQuery != 'undefined') {
2148
2216
  }
2149
2217
 
2150
2218
  // restore scroll bars to document
2151
- document.documentElement.style.overflow = docStyleOverflow;
2219
+ $(document.documentElement).removeClass('mejs-fullscreen');
2152
2220
 
2153
2221
  t.container
2154
2222
  .removeClass('mejs-container-fullscreen')
@@ -2156,12 +2224,12 @@ if (typeof jQuery != 'undefined') {
2156
2224
  .height(normalHeight);
2157
2225
  //.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});
2158
2226
 
2159
- if (t.pluginType === 'native') {
2227
+ if (t.media.pluginType === 'native') {
2160
2228
  t.$media
2161
2229
  .width(normalWidth)
2162
2230
  .height(normalHeight);
2163
2231
  } else {
2164
- t.container.find('object embed')
2232
+ t.container.find('.mejs-shim')
2165
2233
  .width(normalWidth)
2166
2234
  .height(normalHeight);
2167
2235
 
@@ -2190,7 +2258,7 @@ if (typeof jQuery != 'undefined') {
2190
2258
  // this will automatically turn on a <track>
2191
2259
  startLanguage: '',
2192
2260
 
2193
- tracksText: 'Captions/Subtitles',
2261
+ tracksText: mejs.i18n.t('Captions/Subtitles'),
2194
2262
 
2195
2263
  // option to remove the [cc] button when no <track kind="subtitles"> are present
2196
2264
  hideCaptionsButtonWhenEmpty: true,
@@ -2207,9 +2275,6 @@ if (typeof jQuery != 'undefined') {
2207
2275
  hasChapters: false,
2208
2276
 
2209
2277
  buildtracks: function(player, controls, layers, media) {
2210
- if (!player.isVideo)
2211
- return;
2212
-
2213
2278
  if (player.tracks.length == 0)
2214
2279
  return;
2215
2280
 
@@ -2217,6 +2282,11 @@ if (typeof jQuery != 'undefined') {
2217
2282
  i,
2218
2283
  options = '';
2219
2284
 
2285
+ if (t.domNode.textTracks) { // if browser will do native captions, prefer mejs captions, loop through tracks and hide
2286
+ for (var i = t.domNode.textTracks.length - 1; i >= 0; i--) {
2287
+ t.domNode.textTracks[i].mode = "hidden";
2288
+ }
2289
+ }
2220
2290
  player.chapters =
2221
2291
  $('<div class="mejs-chapters mejs-layer"></div>')
2222
2292
  .prependTo(layers).hide();
@@ -2226,12 +2296,12 @@ if (typeof jQuery != 'undefined') {
2226
2296
  player.captionsText = player.captions.find('.mejs-captions-text');
2227
2297
  player.captionsButton =
2228
2298
  $('<div class="mejs-button mejs-captions-button">'+
2229
- '<button type="button" aria-controls="' + t.id + '" title="' + t.options.tracksText + '"></button>'+
2299
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.tracksText + '" aria-label="' + t.options.tracksText + '"></button>'+
2230
2300
  '<div class="mejs-captions-selector">'+
2231
2301
  '<ul>'+
2232
2302
  '<li>'+
2233
2303
  '<input type="radio" name="' + player.id + '_captions" id="' + player.id + '_captions_none" value="none" checked="checked" />' +
2234
- '<label for="' + player.id + '_captions_none">None</label>'+
2304
+ '<label for="' + player.id + '_captions_none">' + mejs.i18n.t('None') +'</label>'+
2235
2305
  '</li>' +
2236
2306
  '</ul>'+
2237
2307
  '</div>'+
@@ -2562,7 +2632,7 @@ if (typeof jQuery != 'undefined') {
2562
2632
 
2563
2633
  if (!img.is(':visible') && !img.is(':animated')) {
2564
2634
 
2565
- console.log('showing existing slide');
2635
+ //
2566
2636
 
2567
2637
  img.fadeIn()
2568
2638
  .siblings(':visible')
@@ -2879,9 +2949,9 @@ $.extend(mejs.MepDefaults,
2879
2949
  return null;
2880
2950
 
2881
2951
  if (player.isFullScreen) {
2882
- return "Turn off Fullscreen";
2952
+ return mejs.i18n.t('Turn off Fullscreen');
2883
2953
  } else {
2884
- return "Go Fullscreen";
2954
+ return mejs.i18n.t('Go Fullscreen');
2885
2955
  }
2886
2956
  },
2887
2957
  click: function(player) {
@@ -2897,9 +2967,9 @@ $.extend(mejs.MepDefaults,
2897
2967
  {
2898
2968
  render: function(player) {
2899
2969
  if (player.media.muted) {
2900
- return "Unmute";
2970
+ return mejs.i18n.t('Unmute');
2901
2971
  } else {
2902
- return "Mute";
2972
+ return mejs.i18n.t('Mute');
2903
2973
  }
2904
2974
  },
2905
2975
  click: function(player) {
@@ -2918,7 +2988,7 @@ $.extend(mejs.MepDefaults,
2918
2988
  // demo of simple download video
2919
2989
  {
2920
2990
  render: function(player) {
2921
- return "Download Video";
2991
+ return mejs.i18n.t('Download Video');
2922
2992
  },
2923
2993
  click: function(player) {
2924
2994
  window.location.href = player.media.currentSrc;
@@ -2949,7 +3019,7 @@ $.extend(mejs.MepDefaults,
2949
3019
  });
2950
3020
  player.contextMenu.bind('mouseleave', function() {
2951
3021
 
2952
- //console.log('context hover out');
3022
+ //
2953
3023
  player.startContextMenuTimer();
2954
3024
 
2955
3025
  });
@@ -2969,7 +3039,7 @@ $.extend(mejs.MepDefaults,
2969
3039
 
2970
3040
  contextMenuTimeout: null,
2971
3041
  startContextMenuTimer: function() {
2972
- //console.log('startContextMenuTimer');
3042
+ //
2973
3043
 
2974
3044
  var t = this;
2975
3045
 
@@ -2983,7 +3053,7 @@ $.extend(mejs.MepDefaults,
2983
3053
  killContextMenuTimer: function() {
2984
3054
  var timer = this.contextMenuTimer;
2985
3055
 
2986
- //console.log('killContextMenuTimer', timer);
3056
+ //
2987
3057
 
2988
3058
  if (timer != null) {
2989
3059
  clearTimeout(timer);