mediaelement_rails 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,7 +6,7 @@
6
6
  * using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
7
7
  *
8
8
  * Copyright 2010-2012, John Dyer (http://j.hn/)
9
- * Dual licensed under the MIT or GPL Version 2 licenses.
9
+ * License: MIT
10
10
  *
11
11
  */
12
12
  if (typeof jQuery != 'undefined') {
@@ -14,1082 +14,1098 @@ if (typeof jQuery != 'undefined') {
14
14
  } else if (typeof ender != 'undefined') {
15
15
  mejs.$ = ender;
16
16
  }
17
- (function ($) {
18
-
19
- // default player values
20
- mejs.MepDefaults = {
21
- // url to poster (to fix iOS 3.x)
22
- poster: '',
23
- // default if the <video width> is not specified
24
- defaultVideoWidth: 480,
25
- // default if the <video height> is not specified
26
- defaultVideoHeight: 270,
27
- // if set, overrides <video width>
28
- videoWidth: -1,
29
- // if set, overrides <video height>
30
- videoHeight: -1,
31
- // default if the user doesn't specify
32
- defaultAudioWidth: 400,
33
- // default if the user doesn't specify
34
- defaultAudioHeight: 30,
35
-
36
- // default amount to move back when back key is pressed
37
- defaultSeekBackwardInterval: function(media) {
38
- return (media.duration * 0.05);
39
- },
40
- // default amount to move forward when forward key is pressed
41
- defaultSeekForwardInterval: function(media) {
42
- return (media.duration * 0.05);
43
- },
44
-
45
- // width of audio player
46
- audioWidth: -1,
47
- // height of audio player
48
- audioHeight: -1,
49
- // initial volume when the player starts (overrided by user cookie)
50
- startVolume: 0.8,
51
- // useful for <audio> player loops
52
- loop: false,
53
- // resize to media dimensions
54
- enableAutosize: true,
55
- // forces the hour marker (##:00:00)
56
- alwaysShowHours: false,
57
-
58
- // show framecount in timecode (##:00:00:00)
59
- showTimecodeFrameCount: false,
60
- // used when showTimecodeFrameCount is set to true
61
- framesPerSecond: 25,
62
-
63
- // automatically calculate the width of the progress bar based on the sizes of other elements
64
- autosizeProgress : true,
65
- // Hide controls when playing and mouse is not over the video
66
- alwaysShowControls: false,
67
- // force iPad's native controls
68
- iPadUseNativeControls: false,
69
- // force iPhone's native controls
70
- iPhoneUseNativeControls: false,
71
- // force Android's native controls
72
- AndroidUseNativeControls: false,
73
- // features to show
74
- features: ['playpause','current','progress','duration','tracks','volume','fullscreen'],
75
- // only for dynamic
76
- isVideo: true,
77
-
78
- // turns keyboard support on and off for this instance
79
- enableKeyboard: true,
80
-
81
- // whenthis player starts, it will pause other players
82
- pauseOtherPlayers: true,
83
-
84
- // array of keyboard actions such as play pause
85
- keyActions: [
86
- {
87
- keys: [
88
- 32, // SPACE
89
- 179 // GOOGLE play/pause button
90
- ],
91
- action: function(player, media) {
92
- if (media.paused || media.ended) {
93
- media.play();
94
- } else {
95
- media.pause();
96
- }
97
- }
98
- },
99
- {
100
- keys: [38], // UP
101
- action: function(player, media) {
102
- var newVolume = Math.min(media.volume + 0.1, 1);
103
- media.setVolume(newVolume);
104
- }
105
- },
106
- {
107
- keys: [40], // DOWN
108
- action: function(player, media) {
109
- var newVolume = Math.max(media.volume - 0.1, 0);
110
- media.setVolume(newVolume);
111
- }
112
- },
113
- {
114
- keys: [
115
- 37, // LEFT
116
- 227 // Google TV rewind
117
- ],
118
- action: function(player, media) {
119
- if (!isNaN(media.duration) && media.duration > 0) {
120
- if (player.isVideo) {
121
- player.showControls();
122
- player.startControlsTimer();
123
- }
124
-
125
- // 5%
126
- var newTime = Math.max(media.currentTime - player.options.defaultSeekBackwardInterval(media), 0);
127
- media.setCurrentTime(newTime);
128
- }
129
- }
130
- },
131
- {
132
- keys: [
133
- 39, // RIGHT
134
- 228 // Google TV forward
135
- ],
136
- action: function(player, media) {
137
- if (!isNaN(media.duration) && media.duration > 0) {
138
- if (player.isVideo) {
139
- player.showControls();
140
- player.startControlsTimer();
141
- }
142
-
143
- // 5%
144
- var newTime = Math.min(media.currentTime + player.options.defaultSeekForwardInterval(media), media.duration);
145
- media.setCurrentTime(newTime);
146
- }
147
- }
148
- },
149
- {
150
- keys: [70], // f
151
- action: function(player, media) {
152
- if (typeof player.enterFullScreen != 'undefined') {
153
- if (player.isFullScreen) {
154
- player.exitFullScreen();
155
- } else {
156
- player.enterFullScreen();
157
- }
158
- }
159
- }
160
- }
161
- ]
162
- };
163
-
164
- mejs.mepIndex = 0;
165
-
166
- mejs.players = [];
167
-
168
- // wraps a MediaElement object in player controls
169
- mejs.MediaElementPlayer = function(node, o) {
170
- // enforce object, even without "new" (via John Resig)
171
- if ( !(this instanceof mejs.MediaElementPlayer) ) {
172
- return new mejs.MediaElementPlayer(node, o);
173
- }
174
-
175
- var t = this;
176
-
177
- // these will be reset after the MediaElement.success fires
178
- t.$media = t.$node = $(node);
179
- t.node = t.media = t.$media[0];
180
-
181
- // check for existing player
182
- if (typeof t.node.player != 'undefined') {
183
- return t.node.player;
184
- } else {
185
- // attach player to DOM node for reference
186
- t.node.player = t;
187
- }
188
-
189
-
190
- // try to get options from data-mejsoptions
191
- if (typeof o == 'undefined') {
192
- o = t.$node.data('mejsoptions');
193
- }
194
-
195
- // extend default options
196
- t.options = $.extend({},mejs.MepDefaults,o);
197
-
198
- // add to player array (for focus events)
199
- mejs.players.push(t);
200
-
201
- // start up
202
- t.init();
203
-
204
- return t;
205
- };
206
-
207
- // actual player
208
- mejs.MediaElementPlayer.prototype = {
209
-
210
- hasFocus: false,
211
-
212
- controlsAreVisible: true,
213
-
214
- init: function() {
215
-
216
- var
217
- t = this,
218
- mf = mejs.MediaFeatures,
219
- // options for MediaElement (shim)
220
- meOptions = $.extend(true, {}, t.options, {
221
- success: function(media, domNode) { t.meReady(media, domNode); },
222
- error: function(e) { t.handleError(e);}
223
- }),
224
- tagName = t.media.tagName.toLowerCase();
225
-
226
- t.isDynamic = (tagName !== 'audio' && tagName !== 'video');
227
-
228
- if (t.isDynamic) {
229
- // get video from src or href?
230
- t.isVideo = t.options.isVideo;
231
- } else {
232
- t.isVideo = (tagName !== 'audio' && t.options.isVideo);
233
- }
234
-
235
- // use native controls in iPad, iPhone, and Android
236
- if ((mf.isiPad && t.options.iPadUseNativeControls) || (mf.isiPhone && t.options.iPhoneUseNativeControls)) {
237
-
238
- // add controls and stop
239
- t.$media.attr('controls', 'controls');
240
-
241
- // attempt to fix iOS 3 bug
242
- //t.$media.removeAttr('poster');
243
- // no Issue found on iOS3 -ttroxell
244
-
245
- // override Apple's autoplay override for iPads
246
- if (mf.isiPad && t.media.getAttribute('autoplay') !== null) {
247
- t.media.load();
248
- t.media.play();
249
- }
250
-
251
- } else if (mf.isAndroid && t.AndroidUseNativeControls) {
252
-
253
- // leave default player
254
-
255
- } else {
256
-
257
- // DESKTOP: use MediaElementPlayer controls
258
-
259
- // remove native controls
260
- t.$media.removeAttr('controls');
261
-
262
- // unique ID
263
- t.id = 'mep_' + mejs.mepIndex++;
264
-
265
- // build container
266
- t.container =
267
- $('<div id="' + t.id + '" class="mejs-container">'+
268
- '<div class="mejs-inner">'+
269
- '<div class="mejs-mediaelement"></div>'+
270
- '<div class="mejs-layers"></div>'+
271
- '<div class="mejs-controls"></div>'+
272
- '<div class="mejs-clear"></div>'+
273
- '</div>' +
274
- '</div>')
275
- .addClass(t.$media[0].className)
276
- .insertBefore(t.$media);
277
-
278
- // add classes for user and content
279
- t.container.addClass(
280
- (mf.isAndroid ? 'mejs-android ' : '') +
281
- (mf.isiOS ? 'mejs-ios ' : '') +
282
- (mf.isiPad ? 'mejs-ipad ' : '') +
283
- (mf.isiPhone ? 'mejs-iphone ' : '') +
284
- (t.isVideo ? 'mejs-video ' : 'mejs-audio ')
285
- );
286
-
287
-
288
- // move the <video/video> tag into the right spot
289
- if (mf.isiOS) {
290
-
291
- // sadly, you can't move nodes in iOS, so we have to destroy and recreate it!
292
- var $newMedia = t.$media.clone();
293
-
294
- t.container.find('.mejs-mediaelement').append($newMedia);
295
-
296
- t.$media.remove();
297
- t.$node = t.$media = $newMedia;
298
- t.node = t.media = $newMedia[0]
299
-
300
- } else {
301
-
302
- // normal way of moving it into place (doesn't work on iOS)
303
- t.container.find('.mejs-mediaelement').append(t.$media);
304
- }
305
-
306
- // find parts
307
- t.controls = t.container.find('.mejs-controls');
308
- t.layers = t.container.find('.mejs-layers');
309
-
310
- // determine the size
311
-
312
- /* size priority:
313
- (1) videoWidth (forced),
314
- (2) style="width;height;"
315
- (3) width attribute,
316
- (4) defaultVideoWidth (for unspecified cases)
317
- */
318
-
319
- var tagType = (t.isVideo ? 'video' : 'audio'),
320
- capsTagName = tagType.substring(0,1).toUpperCase() + tagType.substring(1);
321
-
322
-
323
- if (t.options[tagType + 'Width'] > 0 || t.options[tagType + 'Width'].toString().indexOf('%') > -1) {
324
- t.width = t.options[tagType + 'Width'];
325
- } else if (t.media.style.width !== '' && t.media.style.width !== null) {
326
- t.width = t.media.style.width;
327
- } else if (t.media.getAttribute('width') !== null) {
328
- t.width = t.$media.attr('width');
329
- } else {
330
- t.width = t.options['default' + capsTagName + 'Width'];
331
- }
332
-
333
- if (t.options[tagType + 'Height'] > 0 || t.options[tagType + 'Height'].toString().indexOf('%') > -1) {
334
- t.height = t.options[tagType + 'Height'];
335
- } else if (t.media.style.height !== '' && t.media.style.height !== null) {
336
- t.height = t.media.style.height;
337
- } else if (t.$media[0].getAttribute('height') !== null) {
338
- t.height = t.$media.attr('height');
339
- } else {
340
- t.height = t.options['default' + capsTagName + 'Height'];
341
- }
342
-
343
- // set the size, while we wait for the plugins to load below
344
- t.setPlayerSize(t.width, t.height);
345
-
346
- // create MediaElementShim
347
- meOptions.pluginWidth = t.height;
348
- meOptions.pluginHeight = t.width;
349
- }
350
-
351
-
352
-
353
- // create MediaElement shim
354
- mejs.MediaElement(t.$media[0], meOptions);
355
- },
356
-
357
- showControls: function(doAnimation) {
358
- var t = this;
359
-
360
- doAnimation = typeof doAnimation == 'undefined' || doAnimation;
361
-
362
- if (t.controlsAreVisible)
363
- return;
364
-
365
- if (doAnimation) {
366
- t.controls
367
- .css('visibility','visible')
368
- .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
369
-
370
- // any additional controls people might add and want to hide
371
- t.container.find('.mejs-control')
372
- .css('visibility','visible')
373
- .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
374
-
375
- } else {
376
- t.controls
377
- .css('visibility','visible')
378
- .css('display','block');
379
-
380
- // any additional controls people might add and want to hide
381
- t.container.find('.mejs-control')
382
- .css('visibility','visible')
383
- .css('display','block');
384
-
385
- t.controlsAreVisible = true;
386
- }
387
-
388
- t.setControlsSize();
389
-
390
- },
391
-
392
- hideControls: function(doAnimation) {
393
- var t = this;
394
-
395
- doAnimation = typeof doAnimation == 'undefined' || doAnimation;
396
-
397
- if (!t.controlsAreVisible)
398
- return;
399
-
400
- if (doAnimation) {
401
- // fade out main controls
402
- t.controls.stop(true, true).fadeOut(200, function() {
403
- $(this)
404
- .css('visibility','hidden')
405
- .css('display','block');
406
-
407
- t.controlsAreVisible = false;
408
- });
409
-
410
- // any additional controls people might add and want to hide
411
- t.container.find('.mejs-control').stop(true, true).fadeOut(200, function() {
412
- $(this)
413
- .css('visibility','hidden')
414
- .css('display','block');
415
- });
416
- } else {
417
-
418
- // hide main controls
419
- t.controls
420
- .css('visibility','hidden')
421
- .css('display','block');
422
-
423
- // hide others
424
- t.container.find('.mejs-control')
425
- .css('visibility','hidden')
426
- .css('display','block');
427
-
428
- t.controlsAreVisible = false;
429
- }
430
- },
431
-
432
- controlsTimer: null,
433
-
434
- startControlsTimer: function(timeout) {
435
-
436
- var t = this;
437
-
438
- timeout = typeof timeout != 'undefined' ? timeout : 1500;
439
-
440
- t.killControlsTimer('start');
441
-
442
- t.controlsTimer = setTimeout(function() {
443
- //console.log('timer fired');
444
- t.hideControls();
445
- t.killControlsTimer('hide');
446
- }, timeout);
447
- },
448
-
449
- killControlsTimer: function(src) {
450
-
451
- var t = this;
452
-
453
- if (t.controlsTimer !== null) {
454
- clearTimeout(t.controlsTimer);
455
- delete t.controlsTimer;
456
- t.controlsTimer = null;
457
- }
458
- },
459
-
460
- controlsEnabled: true,
461
-
462
- disableControls: function() {
463
- var t= this;
464
-
465
- t.killControlsTimer();
466
- t.hideControls(false);
467
- this.controlsEnabled = false;
468
- },
469
-
470
- enableControls: function() {
471
- var t= this;
472
-
473
- t.showControls(false);
474
-
475
- t.controlsEnabled = true;
476
- },
477
-
478
-
479
- // Sets up all controls and events
480
- meReady: function(media, domNode) {
481
-
482
-
483
- var t = this,
484
- mf = mejs.MediaFeatures,
485
- autoplayAttr = domNode.getAttribute('autoplay'),
486
- autoplay = !(typeof autoplayAttr == 'undefined' || autoplayAttr === null || autoplayAttr === 'false'),
487
- featureIndex,
488
- feature;
489
-
490
- // make sure it can't create itself again if a plugin reloads
491
- if (t.created)
492
- return;
493
- else
494
- t.created = true;
495
-
496
- t.media = media;
497
- t.domNode = domNode;
498
-
499
- if (!(mf.isAndroid && t.options.AndroidUseNativeControls) && !(mf.isiPad && t.options.iPadUseNativeControls) && !(mf.isiPhone && t.options.iPhoneUseNativeControls)) {
500
-
501
- // two built in features
502
- t.buildposter(t, t.controls, t.layers, t.media);
503
- t.buildkeyboard(t, t.controls, t.layers, t.media);
504
- t.buildoverlays(t, t.controls, t.layers, t.media);
505
-
506
- // grab for use by features
507
- t.findTracks();
508
-
509
- // add user-defined features/controls
510
- for (featureIndex in t.options.features) {
511
- feature = t.options.features[featureIndex];
512
- if (t['build' + feature]) {
513
- try {
514
- t['build' + feature](t, t.controls, t.layers, t.media);
515
- } catch (e) {
516
- // TODO: report control error
517
- //throw e;
518
- //console.log('error building ' + feature);
519
- //console.log(e);
520
- }
521
- }
522
- }
523
-
524
- t.container.trigger('controlsready');
525
-
526
- // reset all layers and controls
527
- t.setPlayerSize(t.width, t.height);
528
- t.setControlsSize();
529
-
530
-
531
- // controls fade
532
- if (t.isVideo) {
533
-
534
- if (mejs.MediaFeatures.hasTouch) {
535
-
536
- // for touch devices (iOS, Android)
537
- // show/hide without animation on touch
538
-
539
- t.$media.bind('touchstart', function() {
540
-
541
-
542
- // toggle controls
543
- if (t.controlsAreVisible) {
544
- t.hideControls(false);
545
- } else {
546
- if (t.controlsEnabled) {
547
- t.showControls(false);
548
- }
549
- }
550
- });
551
-
552
- } else {
553
- // click controls
554
- var clickElement = (t.media.pluginType == 'native') ? t.$media : $(t.media.pluginElement);
555
-
556
- // click to play/pause
557
- clickElement.click(function() {
558
- if (media.paused) {
559
- media.play();
560
- } else {
561
- media.pause();
562
- }
563
- });
564
-
565
-
566
- // show/hide controls
567
- t.container
568
- .bind('mouseenter mouseover', function () {
569
- if (t.controlsEnabled) {
570
- if (!t.options.alwaysShowControls) {
571
- t.killControlsTimer('enter');
572
- t.showControls();
573
- t.startControlsTimer(2500);
574
- }
575
- }
576
- })
577
- .bind('mousemove', function() {
578
- if (t.controlsEnabled) {
579
- if (!t.controlsAreVisible) {
580
- t.showControls();
581
- }
582
- //t.killControlsTimer('move');
583
- if (!t.options.alwaysShowControls) {
584
- t.startControlsTimer(2500);
585
- }
586
- }
587
- })
588
- .bind('mouseleave', function () {
589
- if (t.controlsEnabled) {
590
- if (!t.media.paused && !t.options.alwaysShowControls) {
591
- t.startControlsTimer(1000);
592
- }
593
- }
594
- });
595
- }
596
-
597
- // check for autoplay
598
- if (autoplay && !t.options.alwaysShowControls) {
599
- t.hideControls();
600
- }
601
-
602
- // resizer
603
- if (t.options.enableAutosize) {
604
- t.media.addEventListener('loadedmetadata', function(e) {
605
- // if the <video height> was not set and the options.videoHeight was not set
606
- // then resize to the real dimensions
607
- if (t.options.videoHeight <= 0 && t.domNode.getAttribute('height') === null && !isNaN(e.target.videoHeight)) {
608
- t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);
609
- t.setControlsSize();
610
- t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);
611
- }
612
- }, false);
613
- }
614
- }
615
-
616
- // EVENTS
617
-
618
- // FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)
619
- media.addEventListener('play', function() {
620
-
621
- // go through all other players
622
- for (var i=0, il=mejs.players.length; i<il; i++) {
623
- var p = mejs.players[i];
624
- if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
625
- p.pause();
626
- }
627
- p.hasFocus = false;
628
- }
629
-
630
- t.hasFocus = true;
631
- },false);
632
-
633
-
634
- // ended for all
635
- t.media.addEventListener('ended', function (e) {
636
- try{
637
- t.media.setCurrentTime(0);
638
- } catch (exp) {
639
-
640
- }
641
- t.media.pause();
642
-
643
- if (t.setProgressRail)
644
- t.setProgressRail();
645
- if (t.setCurrentRail)
646
- t.setCurrentRail();
647
-
648
- if (t.options.loop) {
649
- t.media.play();
650
- } else if (!t.options.alwaysShowControls && t.controlsEnabled) {
651
- t.showControls();
652
- }
653
- }, false);
654
-
655
- // resize on the first play
656
- t.media.addEventListener('loadedmetadata', function(e) {
657
- if (t.updateDuration) {
658
- t.updateDuration();
659
- }
660
- if (t.updateCurrent) {
661
- t.updateCurrent();
662
- }
663
-
664
- if (!t.isFullScreen) {
665
- t.setPlayerSize(t.width, t.height);
666
- t.setControlsSize();
667
- }
668
- }, false);
669
-
670
-
671
- // webkit has trouble doing this without a delay
672
- setTimeout(function () {
673
- t.setPlayerSize(t.width, t.height);
674
- t.setControlsSize();
675
- }, 50);
676
-
677
- // adjust controls whenever window sizes (used to be in fullscreen only)
678
- $(window).resize(function() {
679
-
680
- // don't resize for fullscreen mode
681
- if ( !(t.isFullScreen || (mejs.MediaFeatures.hasTrueNativeFullScreen && document.webkitIsFullScreen)) ) {
682
- t.setPlayerSize(t.width, t.height);
683
- }
684
-
685
- // always adjust controls
686
- t.setControlsSize();
687
- });
688
-
689
- // TEMP: needs to be moved somewhere else
690
- if (t.media.pluginType == 'youtube') {
691
- t.container.find('.mejs-overlay-play').hide();
692
- }
693
- }
694
-
695
- // force autoplay for HTML5
696
- if (autoplay && media.pluginType == 'native') {
697
- media.load();
698
- media.play();
699
- }
700
-
701
-
702
- if (t.options.success) {
703
-
704
- if (typeof t.options.success == 'string') {
705
- window[t.options.success](t.media, t.domNode, t);
706
- } else {
707
- t.options.success(t.media, t.domNode, t);
708
- }
709
- }
710
- },
711
-
712
- handleError: function(e) {
713
- var t = this;
714
-
715
- t.controls.hide();
716
-
717
- // Tell user that the file cannot be played
718
- if (t.options.error) {
719
- t.options.error(e);
720
- }
721
- },
722
-
723
- setPlayerSize: function(width,height) {
724
- var t = this;
725
-
726
- if (typeof width != 'undefined')
727
- t.width = width;
728
-
729
- if (typeof height != 'undefined')
730
- t.height = height;
731
-
732
- // detect 100% mode
733
- if (t.height.toString().indexOf('%') > 0) {
734
-
735
- // do we have the native dimensions yet?
736
- var
737
- nativeWidth = (t.media.videoWidth && t.media.videoWidth > 0) ? t.media.videoWidth : t.options.defaultVideoWidth,
738
- nativeHeight = (t.media.videoHeight && t.media.videoHeight > 0) ? t.media.videoHeight : t.options.defaultVideoHeight,
739
- parentWidth = t.container.parent().width(),
740
- newHeight = parseInt(parentWidth * nativeHeight/nativeWidth, 10);
741
-
742
- if (t.container.parent()[0].tagName.toLowerCase() === 'body') { // && t.container.siblings().count == 0) {
743
- parentWidth = $(window).width();
744
- newHeight = $(window).height();
745
- }
746
-
747
- if ( newHeight != 0 ) {
748
- // set outer container size
749
- t.container
750
- .width(parentWidth)
751
- .height(newHeight);
752
-
753
- // set native <video>
754
- t.$media
755
- .width('100%')
756
- .height('100%');
757
-
758
- // set shims
759
- t.container.find('object, embed, iframe')
760
- .width('100%')
761
- .height('100%');
762
-
763
- // if shim is ready, send the size to the embeded plugin
764
- if (t.isVideo) {
765
- if (t.media.setVideoSize) {
766
- t.media.setVideoSize(parentWidth, newHeight);
767
- }
768
- }
769
-
770
- // set the layers
771
- t.layers.children('.mejs-layer')
772
- .width('100%')
773
- .height('100%');
774
- }
775
-
776
-
777
- } else {
778
-
779
- t.container
780
- .width(t.width)
781
- .height(t.height);
782
-
783
- t.layers.children('.mejs-layer')
784
- .width(t.width)
785
- .height(t.height);
786
-
787
- }
788
- },
789
-
790
- setControlsSize: function() {
791
- var t = this,
792
- usedWidth = 0,
793
- railWidth = 0,
794
- rail = t.controls.find('.mejs-time-rail'),
795
- total = t.controls.find('.mejs-time-total'),
796
- current = t.controls.find('.mejs-time-current'),
797
- loaded = t.controls.find('.mejs-time-loaded'),
798
- others = rail.siblings();
799
-
800
-
801
- // allow the size to come from custom CSS
802
- if (t.options && !t.options.autosizeProgress) {
803
- // Also, frontends devs can be more flexible
804
- // due the opportunity of absolute positioning.
805
- railWidth = parseInt(rail.css('width'));
806
- }
807
-
808
- // attempt to autosize
809
- if (railWidth === 0 || !railWidth) {
810
-
811
- // find the size of all the other controls besides the rail
812
- others.each(function() {
813
- if ($(this).css('position') != 'absolute') {
814
- usedWidth += $(this).outerWidth(true);
815
- }
816
- });
817
-
818
- // fit the rail into the remaining space
819
- railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.width());
820
- }
821
-
822
- // outer area
823
- rail.width(railWidth);
824
- // dark space
825
- total.width(railWidth - (total.outerWidth(true) - total.width()));
826
-
827
- if (t.setProgressRail)
828
- t.setProgressRail();
829
- if (t.setCurrentRail)
830
- t.setCurrentRail();
831
- },
832
-
833
-
834
- buildposter: function(player, controls, layers, media) {
835
- var t = this,
836
- poster =
837
- $('<div class="mejs-poster mejs-layer">' +
838
- '</div>')
839
- .appendTo(layers),
840
- posterUrl = player.$media.attr('poster');
841
-
842
- // prioriy goes to option (this is useful if you need to support iOS 3.x (iOS completely fails with poster)
843
- if (player.options.poster !== '') {
844
- posterUrl = player.options.poster;
845
- }
846
-
847
- // second, try the real poster
848
- if (posterUrl !== '' && posterUrl != null) {
849
- t.setPoster(posterUrl);
850
- } else {
851
- poster.hide();
852
- }
853
-
854
- media.addEventListener('play',function() {
855
- poster.hide();
856
- }, false);
857
- },
858
-
859
- setPoster: function(url) {
860
- var t = this,
861
- posterDiv = t.container.find('.mejs-poster'),
862
- posterImg = posterDiv.find('img');
863
-
864
- if (posterImg.length == 0) {
865
- posterImg = $('<img width="100%" height="100%" />').appendTo(posterDiv);
866
- }
867
-
868
- posterImg.attr('src', url);
869
- },
870
-
871
- buildoverlays: function(player, controls, layers, media) {
872
- if (!player.isVideo)
873
- return;
874
-
875
- var
876
- loading =
877
- $('<div class="mejs-overlay mejs-layer">'+
878
- '<div class="mejs-overlay-loading"><span></span></div>'+
879
- '</div>')
880
- .hide() // start out hidden
881
- .appendTo(layers),
882
- error =
883
- $('<div class="mejs-overlay mejs-layer">'+
884
- '<div class="mejs-overlay-error"></div>'+
885
- '</div>')
886
- .hide() // start out hidden
887
- .appendTo(layers),
888
- // this needs to come last so it's on top
889
- bigPlay =
890
- $('<div class="mejs-overlay mejs-layer mejs-overlay-play">'+
891
- '<div class="mejs-overlay-button"></div>'+
892
- '</div>')
893
- .appendTo(layers)
894
- .click(function() {
895
- if (media.paused) {
896
- media.play();
897
- } else {
898
- media.pause();
899
- }
900
- });
901
-
902
- /*
903
- if (mejs.MediaFeatures.isiOS || mejs.MediaFeatures.isAndroid) {
904
- bigPlay.remove();
905
- loading.remove();
906
- }
907
- */
908
-
909
-
910
- // show/hide big play button
911
- media.addEventListener('play',function() {
912
- bigPlay.hide();
913
- loading.hide();
914
- controls.find('.mejs-time-buffering').hide();
915
- error.hide();
916
- }, false);
917
-
918
- media.addEventListener('playing', function() {
919
- bigPlay.hide();
920
- loading.hide();
921
- controls.find('.mejs-time-buffering').hide();
922
- error.hide();
923
- }, false);
924
-
925
- media.addEventListener('seeking', function() {
926
- loading.show();
927
- controls.find('.mejs-time-buffering').show();
928
- }, false);
929
-
930
- media.addEventListener('seeked', function() {
931
- loading.hide();
932
- controls.find('.mejs-time-buffering').hide();
933
- }, false);
934
-
935
- media.addEventListener('pause',function() {
936
- if (!mejs.MediaFeatures.isiPhone) {
937
- bigPlay.show();
938
- }
939
- }, false);
940
-
941
- media.addEventListener('waiting', function() {
942
- loading.show();
943
- controls.find('.mejs-time-buffering').show();
944
- }, false);
945
-
946
-
947
- // show/hide loading
948
- media.addEventListener('loadeddata',function() {
949
- // for some reason Chrome is firing this event
950
- //if (mejs.MediaFeatures.isChrome && media.getAttribute && media.getAttribute('preload') === 'none')
951
- // return;
952
-
953
- loading.show();
954
- controls.find('.mejs-time-buffering').show();
955
- }, false);
956
- media.addEventListener('canplay',function() {
957
- loading.hide();
958
- controls.find('.mejs-time-buffering').hide();
959
- }, false);
960
-
961
- // error handling
962
- media.addEventListener('error',function() {
963
- loading.hide();
964
- controls.find('.mejs-time-buffering').hide();
965
- error.show();
966
- error.find('mejs-overlay-error').html("Error loading this resource");
967
- }, false);
968
- },
969
-
970
- buildkeyboard: function(player, controls, layers, media) {
971
-
972
- var t = this;
973
-
974
- // listen for key presses
975
- $(document).keydown(function(e) {
976
-
977
- if (player.hasFocus && player.options.enableKeyboard) {
978
-
979
- // find a matching key
980
- for (var i=0, il=player.options.keyActions.length; i<il; i++) {
981
- var keyAction = player.options.keyActions[i];
982
-
983
- for (var j=0, jl=keyAction.keys.length; j<jl; j++) {
984
- if (e.keyCode == keyAction.keys[j]) {
985
- e.preventDefault();
986
- keyAction.action(player, media, e.keyCode);
987
- return false;
988
- }
989
- }
990
- }
991
- }
992
-
993
- return true;
994
- });
995
-
996
- // check if someone clicked outside a player region, then kill its focus
997
- $(document).click(function(event) {
998
- if ($(event.target).closest('.mejs-container').length == 0) {
999
- player.hasFocus = false;
1000
- }
1001
- });
1002
-
1003
- },
1004
-
1005
- findTracks: function() {
1006
- var t = this,
1007
- tracktags = t.$media.find('track');
1008
-
1009
- // store for use by plugins
1010
- t.tracks = [];
1011
- tracktags.each(function(index, track) {
1012
-
1013
- track = $(track);
1014
-
1015
- t.tracks.push({
1016
- srclang: track.attr('srclang').toLowerCase(),
1017
- src: track.attr('src'),
1018
- kind: track.attr('kind'),
1019
- label: track.attr('label') || '',
1020
- entries: [],
1021
- isLoaded: false
1022
- });
1023
- });
1024
- },
1025
- changeSkin: function(className) {
1026
- this.container[0].className = 'mejs-container ' + className;
1027
- this.setPlayerSize(this.width, this.height);
1028
- this.setControlsSize();
1029
- },
1030
- play: function() {
1031
- this.media.play();
1032
- },
1033
- pause: function() {
1034
- this.media.pause();
1035
- },
1036
- load: function() {
1037
- this.media.load();
1038
- },
1039
- setMuted: function(muted) {
1040
- this.media.setMuted(muted);
1041
- },
1042
- setCurrentTime: function(time) {
1043
- this.media.setCurrentTime(time);
1044
- },
1045
- getCurrentTime: function() {
1046
- return this.media.currentTime;
1047
- },
1048
- setVolume: function(volume) {
1049
- this.media.setVolume(volume);
1050
- },
1051
- getVolume: function() {
1052
- return this.media.volume;
1053
- },
1054
- setSrc: function(src) {
1055
- this.media.setSrc(src);
1056
- },
1057
- remove: function() {
1058
- var t = this;
1059
-
1060
- if (t.media.pluginType === 'flash') {
1061
- t.media.remove();
1062
- } else if (t.media.pluginType === 'native') {
1063
- t.$media.prop('controls', true);
1064
- }
1065
-
1066
- // grab video and put it back in place
1067
- if (!t.isDynamic) {
1068
- t.$node.insertBefore(t.container)
1069
- }
1070
-
1071
- t.container.remove();
1072
- }
1073
- };
1074
-
1075
- // turn into jQuery plugin
1076
- if (typeof jQuery != 'undefined') {
1077
- jQuery.fn.mediaelementplayer = function (options) {
1078
- return this.each(function () {
1079
- new mejs.MediaElementPlayer(this, options);
1080
- });
1081
- };
1082
- }
1083
-
1084
- $(document).ready(function() {
1085
- // auto enable using JSON attribute
1086
- $('.mejs-player').mediaelementplayer();
1087
- });
1088
-
1089
- // push out to window
1090
- window.MediaElementPlayer = mejs.MediaElementPlayer;
1091
-
1092
- })(mejs.$);
17
+ (function ($) {
18
+
19
+ // default player values
20
+ mejs.MepDefaults = {
21
+ // url to poster (to fix iOS 3.x)
22
+ poster: '',
23
+ // default if the <video width> is not specified
24
+ defaultVideoWidth: 480,
25
+ // default if the <video height> is not specified
26
+ defaultVideoHeight: 270,
27
+ // if set, overrides <video width>
28
+ videoWidth: -1,
29
+ // if set, overrides <video height>
30
+ videoHeight: -1,
31
+ // default if the user doesn't specify
32
+ defaultAudioWidth: 400,
33
+ // default if the user doesn't specify
34
+ defaultAudioHeight: 30,
35
+
36
+ // default amount to move back when back key is pressed
37
+ defaultSeekBackwardInterval: function(media) {
38
+ return (media.duration * 0.05);
39
+ },
40
+ // default amount to move forward when forward key is pressed
41
+ defaultSeekForwardInterval: function(media) {
42
+ return (media.duration * 0.05);
43
+ },
44
+
45
+ // width of audio player
46
+ audioWidth: -1,
47
+ // height of audio player
48
+ audioHeight: -1,
49
+ // initial volume when the player starts (overrided by user cookie)
50
+ startVolume: 0.8,
51
+ // useful for <audio> player loops
52
+ loop: false,
53
+ // rewind to beginning when media ends
54
+ autoRewind: true,
55
+ // resize to media dimensions
56
+ enableAutosize: true,
57
+ // forces the hour marker (##:00:00)
58
+ alwaysShowHours: false,
59
+
60
+ // show framecount in timecode (##:00:00:00)
61
+ showTimecodeFrameCount: false,
62
+ // used when showTimecodeFrameCount is set to true
63
+ framesPerSecond: 25,
64
+
65
+ // automatically calculate the width of the progress bar based on the sizes of other elements
66
+ autosizeProgress : true,
67
+ // Hide controls when playing and mouse is not over the video
68
+ alwaysShowControls: false,
69
+ // Enable click video element to toggle play/pause
70
+ clickToPlayPause: true,
71
+ // force iPad's native controls
72
+ iPadUseNativeControls: false,
73
+ // force iPhone's native controls
74
+ iPhoneUseNativeControls: false,
75
+ // force Android's native controls
76
+ AndroidUseNativeControls: false,
77
+ // features to show
78
+ features: ['playpause','current','progress','duration','tracks','volume','fullscreen'],
79
+ // only for dynamic
80
+ isVideo: true,
81
+
82
+ // turns keyboard support on and off for this instance
83
+ enableKeyboard: true,
84
+
85
+ // whenthis player starts, it will pause other players
86
+ pauseOtherPlayers: true,
87
+
88
+ // array of keyboard actions such as play pause
89
+ keyActions: [
90
+ {
91
+ keys: [
92
+ 32, // SPACE
93
+ 179 // GOOGLE play/pause button
94
+ ],
95
+ action: function(player, media) {
96
+ if (media.paused || media.ended) {
97
+ media.play();
98
+ } else {
99
+ media.pause();
100
+ }
101
+ }
102
+ },
103
+ {
104
+ keys: [38], // UP
105
+ action: function(player, media) {
106
+ var newVolume = Math.min(media.volume + 0.1, 1);
107
+ media.setVolume(newVolume);
108
+ }
109
+ },
110
+ {
111
+ keys: [40], // DOWN
112
+ action: function(player, media) {
113
+ var newVolume = Math.max(media.volume - 0.1, 0);
114
+ media.setVolume(newVolume);
115
+ }
116
+ },
117
+ {
118
+ keys: [
119
+ 37, // LEFT
120
+ 227 // Google TV rewind
121
+ ],
122
+ action: function(player, media) {
123
+ if (!isNaN(media.duration) && media.duration > 0) {
124
+ if (player.isVideo) {
125
+ player.showControls();
126
+ player.startControlsTimer();
127
+ }
128
+
129
+ // 5%
130
+ var newTime = Math.max(media.currentTime - player.options.defaultSeekBackwardInterval(media), 0);
131
+ media.setCurrentTime(newTime);
132
+ }
133
+ }
134
+ },
135
+ {
136
+ keys: [
137
+ 39, // RIGHT
138
+ 228 // Google TV forward
139
+ ],
140
+ action: function(player, media) {
141
+ if (!isNaN(media.duration) && media.duration > 0) {
142
+ if (player.isVideo) {
143
+ player.showControls();
144
+ player.startControlsTimer();
145
+ }
146
+
147
+ // 5%
148
+ var newTime = Math.min(media.currentTime + player.options.defaultSeekForwardInterval(media), media.duration);
149
+ media.setCurrentTime(newTime);
150
+ }
151
+ }
152
+ },
153
+ {
154
+ keys: [70], // f
155
+ action: function(player, media) {
156
+ if (typeof player.enterFullScreen != 'undefined') {
157
+ if (player.isFullScreen) {
158
+ player.exitFullScreen();
159
+ } else {
160
+ player.enterFullScreen();
161
+ }
162
+ }
163
+ }
164
+ }
165
+ ]
166
+ };
167
+
168
+ mejs.mepIndex = 0;
169
+
170
+ mejs.players = [];
171
+
172
+ // wraps a MediaElement object in player controls
173
+ mejs.MediaElementPlayer = function(node, o) {
174
+ // enforce object, even without "new" (via John Resig)
175
+ if ( !(this instanceof mejs.MediaElementPlayer) ) {
176
+ return new mejs.MediaElementPlayer(node, o);
177
+ }
178
+
179
+ var t = this;
180
+
181
+ // these will be reset after the MediaElement.success fires
182
+ t.$media = t.$node = $(node);
183
+ t.node = t.media = t.$media[0];
184
+
185
+ // check for existing player
186
+ if (typeof t.node.player != 'undefined') {
187
+ return t.node.player;
188
+ } else {
189
+ // attach player to DOM node for reference
190
+ t.node.player = t;
191
+ }
192
+
193
+
194
+ // try to get options from data-mejsoptions
195
+ if (typeof o == 'undefined') {
196
+ o = t.$node.data('mejsoptions');
197
+ }
198
+
199
+ // extend default options
200
+ t.options = $.extend({},mejs.MepDefaults,o);
201
+
202
+ // add to player array (for focus events)
203
+ mejs.players.push(t);
204
+
205
+ // start up
206
+ t.init();
207
+
208
+ return t;
209
+ };
210
+
211
+ // actual player
212
+ mejs.MediaElementPlayer.prototype = {
213
+
214
+ hasFocus: false,
215
+
216
+ controlsAreVisible: true,
217
+
218
+ init: function() {
219
+
220
+ var
221
+ t = this,
222
+ mf = mejs.MediaFeatures,
223
+ // options for MediaElement (shim)
224
+ meOptions = $.extend(true, {}, t.options, {
225
+ success: function(media, domNode) { t.meReady(media, domNode); },
226
+ error: function(e) { t.handleError(e);}
227
+ }),
228
+ tagName = t.media.tagName.toLowerCase();
229
+
230
+ t.isDynamic = (tagName !== 'audio' && tagName !== 'video');
231
+
232
+ if (t.isDynamic) {
233
+ // get video from src or href?
234
+ t.isVideo = t.options.isVideo;
235
+ } else {
236
+ t.isVideo = (tagName !== 'audio' && t.options.isVideo);
237
+ }
238
+
239
+ // use native controls in iPad, iPhone, and Android
240
+ if ((mf.isiPad && t.options.iPadUseNativeControls) || (mf.isiPhone && t.options.iPhoneUseNativeControls)) {
241
+
242
+ // add controls and stop
243
+ t.$media.attr('controls', 'controls');
244
+
245
+ // attempt to fix iOS 3 bug
246
+ //t.$media.removeAttr('poster');
247
+ // no Issue found on iOS3 -ttroxell
248
+
249
+ // override Apple's autoplay override for iPads
250
+ if (mf.isiPad && t.media.getAttribute('autoplay') !== null) {
251
+ t.media.load();
252
+ t.media.play();
253
+ }
254
+
255
+ } else if (mf.isAndroid && t.AndroidUseNativeControls) {
256
+
257
+ // leave default player
258
+
259
+ } else {
260
+
261
+ // DESKTOP: use MediaElementPlayer controls
262
+
263
+ // remove native controls
264
+ t.$media.removeAttr('controls');
265
+
266
+ // unique ID
267
+ t.id = 'mep_' + mejs.mepIndex++;
268
+
269
+ // build container
270
+ t.container =
271
+ $('<div id="' + t.id + '" class="mejs-container ' + (mejs.MediaFeatures.svg ? 'svg' : 'no-svg') + '">'+
272
+ '<div class="mejs-inner">'+
273
+ '<div class="mejs-mediaelement"></div>'+
274
+ '<div class="mejs-layers"></div>'+
275
+ '<div class="mejs-controls"></div>'+
276
+ '<div class="mejs-clear"></div>'+
277
+ '</div>' +
278
+ '</div>')
279
+ .addClass(t.$media[0].className)
280
+ .insertBefore(t.$media);
281
+
282
+ // add classes for user and content
283
+ t.container.addClass(
284
+ (mf.isAndroid ? 'mejs-android ' : '') +
285
+ (mf.isiOS ? 'mejs-ios ' : '') +
286
+ (mf.isiPad ? 'mejs-ipad ' : '') +
287
+ (mf.isiPhone ? 'mejs-iphone ' : '') +
288
+ (t.isVideo ? 'mejs-video ' : 'mejs-audio ')
289
+ );
290
+
291
+
292
+ // move the <video/video> tag into the right spot
293
+ if (mf.isiOS) {
294
+
295
+ // sadly, you can't move nodes in iOS, so we have to destroy and recreate it!
296
+ var $newMedia = t.$media.clone();
297
+
298
+ t.container.find('.mejs-mediaelement').append($newMedia);
299
+
300
+ t.$media.remove();
301
+ t.$node = t.$media = $newMedia;
302
+ t.node = t.media = $newMedia[0]
303
+
304
+ } else {
305
+
306
+ // normal way of moving it into place (doesn't work on iOS)
307
+ t.container.find('.mejs-mediaelement').append(t.$media);
308
+ }
309
+
310
+ // find parts
311
+ t.controls = t.container.find('.mejs-controls');
312
+ t.layers = t.container.find('.mejs-layers');
313
+
314
+ // determine the size
315
+
316
+ /* size priority:
317
+ (1) videoWidth (forced),
318
+ (2) style="width;height;"
319
+ (3) width attribute,
320
+ (4) defaultVideoWidth (for unspecified cases)
321
+ */
322
+
323
+ var tagType = (t.isVideo ? 'video' : 'audio'),
324
+ capsTagName = tagType.substring(0,1).toUpperCase() + tagType.substring(1);
325
+
326
+
327
+ if (t.options[tagType + 'Width'] > 0 || t.options[tagType + 'Width'].toString().indexOf('%') > -1) {
328
+ t.width = t.options[tagType + 'Width'];
329
+ } else if (t.media.style.width !== '' && t.media.style.width !== null) {
330
+ t.width = t.media.style.width;
331
+ } else if (t.media.getAttribute('width') !== null) {
332
+ t.width = t.$media.attr('width');
333
+ } else {
334
+ t.width = t.options['default' + capsTagName + 'Width'];
335
+ }
336
+
337
+ if (t.options[tagType + 'Height'] > 0 || t.options[tagType + 'Height'].toString().indexOf('%') > -1) {
338
+ t.height = t.options[tagType + 'Height'];
339
+ } else if (t.media.style.height !== '' && t.media.style.height !== null) {
340
+ t.height = t.media.style.height;
341
+ } else if (t.$media[0].getAttribute('height') !== null) {
342
+ t.height = t.$media.attr('height');
343
+ } else {
344
+ t.height = t.options['default' + capsTagName + 'Height'];
345
+ }
346
+
347
+ // set the size, while we wait for the plugins to load below
348
+ t.setPlayerSize(t.width, t.height);
349
+
350
+ // create MediaElementShim
351
+ meOptions.pluginWidth = t.height;
352
+ meOptions.pluginHeight = t.width;
353
+ }
354
+
355
+
356
+
357
+ // create MediaElement shim
358
+ mejs.MediaElement(t.$media[0], meOptions);
359
+
360
+ // controls are shown when loaded
361
+ t.container.trigger('controlsshown');
362
+ },
363
+
364
+ showControls: function(doAnimation) {
365
+ var t = this;
366
+
367
+ doAnimation = typeof doAnimation == 'undefined' || doAnimation;
368
+
369
+ if (t.controlsAreVisible)
370
+ return;
371
+
372
+ if (doAnimation) {
373
+ t.controls
374
+ .css('visibility','visible')
375
+ .stop(true, true).fadeIn(200, function() {
376
+ t.controlsAreVisible = true;
377
+ t.container.trigger('controlsshown');
378
+ });
379
+
380
+ // any additional controls people might add and want to hide
381
+ t.container.find('.mejs-control')
382
+ .css('visibility','visible')
383
+ .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
384
+
385
+ } else {
386
+ t.controls
387
+ .css('visibility','visible')
388
+ .css('display','block');
389
+
390
+ // any additional controls people might add and want to hide
391
+ t.container.find('.mejs-control')
392
+ .css('visibility','visible')
393
+ .css('display','block');
394
+
395
+ t.controlsAreVisible = true;
396
+ t.container.trigger('controlsshown');
397
+ }
398
+
399
+ t.setControlsSize();
400
+
401
+ },
402
+
403
+ hideControls: function(doAnimation) {
404
+ var t = this;
405
+
406
+ doAnimation = typeof doAnimation == 'undefined' || doAnimation;
407
+
408
+ if (!t.controlsAreVisible)
409
+ return;
410
+
411
+ if (doAnimation) {
412
+ // fade out main controls
413
+ t.controls.stop(true, true).fadeOut(200, function() {
414
+ $(this)
415
+ .css('visibility','hidden')
416
+ .css('display','block');
417
+
418
+ t.controlsAreVisible = false;
419
+ t.container.trigger('controlshidden');
420
+ });
421
+
422
+ // any additional controls people might add and want to hide
423
+ t.container.find('.mejs-control').stop(true, true).fadeOut(200, function() {
424
+ $(this)
425
+ .css('visibility','hidden')
426
+ .css('display','block');
427
+ });
428
+ } else {
429
+
430
+ // hide main controls
431
+ t.controls
432
+ .css('visibility','hidden')
433
+ .css('display','block');
434
+
435
+ // hide others
436
+ t.container.find('.mejs-control')
437
+ .css('visibility','hidden')
438
+ .css('display','block');
439
+
440
+ t.controlsAreVisible = false;
441
+ t.container.trigger('controlshidden');
442
+ }
443
+ },
444
+
445
+ controlsTimer: null,
446
+
447
+ startControlsTimer: function(timeout) {
448
+
449
+ var t = this;
450
+
451
+ timeout = typeof timeout != 'undefined' ? timeout : 1500;
452
+
453
+ t.killControlsTimer('start');
454
+
455
+ t.controlsTimer = setTimeout(function() {
456
+ //console.log('timer fired');
457
+ t.hideControls();
458
+ t.killControlsTimer('hide');
459
+ }, timeout);
460
+ },
461
+
462
+ killControlsTimer: function(src) {
463
+
464
+ var t = this;
465
+
466
+ if (t.controlsTimer !== null) {
467
+ clearTimeout(t.controlsTimer);
468
+ delete t.controlsTimer;
469
+ t.controlsTimer = null;
470
+ }
471
+ },
472
+
473
+ controlsEnabled: true,
474
+
475
+ disableControls: function() {
476
+ var t= this;
477
+
478
+ t.killControlsTimer();
479
+ t.hideControls(false);
480
+ this.controlsEnabled = false;
481
+ },
482
+
483
+ enableControls: function() {
484
+ var t= this;
485
+
486
+ t.showControls(false);
487
+
488
+ t.controlsEnabled = true;
489
+ },
490
+
491
+
492
+ // Sets up all controls and events
493
+ meReady: function(media, domNode) {
494
+
495
+
496
+ var t = this,
497
+ mf = mejs.MediaFeatures,
498
+ autoplayAttr = domNode.getAttribute('autoplay'),
499
+ autoplay = !(typeof autoplayAttr == 'undefined' || autoplayAttr === null || autoplayAttr === 'false'),
500
+ featureIndex,
501
+ feature;
502
+
503
+ // make sure it can't create itself again if a plugin reloads
504
+ if (t.created)
505
+ return;
506
+ else
507
+ t.created = true;
508
+
509
+ t.media = media;
510
+ t.domNode = domNode;
511
+
512
+ if (!(mf.isAndroid && t.options.AndroidUseNativeControls) && !(mf.isiPad && t.options.iPadUseNativeControls) && !(mf.isiPhone && t.options.iPhoneUseNativeControls)) {
513
+
514
+ // two built in features
515
+ t.buildposter(t, t.controls, t.layers, t.media);
516
+ t.buildkeyboard(t, t.controls, t.layers, t.media);
517
+ t.buildoverlays(t, t.controls, t.layers, t.media);
518
+
519
+ // grab for use by features
520
+ t.findTracks();
521
+
522
+ // add user-defined features/controls
523
+ for (featureIndex in t.options.features) {
524
+ feature = t.options.features[featureIndex];
525
+ if (t['build' + feature]) {
526
+ try {
527
+ t['build' + feature](t, t.controls, t.layers, t.media);
528
+ } catch (e) {
529
+ // TODO: report control error
530
+ //throw e;
531
+ //console.log('error building ' + feature);
532
+ //console.log(e);
533
+ }
534
+ }
535
+ }
536
+
537
+ t.container.trigger('controlsready');
538
+
539
+ // reset all layers and controls
540
+ t.setPlayerSize(t.width, t.height);
541
+ t.setControlsSize();
542
+
543
+
544
+ // controls fade
545
+ if (t.isVideo) {
546
+
547
+ if (mejs.MediaFeatures.hasTouch) {
548
+
549
+ // for touch devices (iOS, Android)
550
+ // show/hide without animation on touch
551
+
552
+ t.$media.bind('touchstart', function() {
553
+
554
+
555
+ // toggle controls
556
+ if (t.controlsAreVisible) {
557
+ t.hideControls(false);
558
+ } else {
559
+ if (t.controlsEnabled) {
560
+ t.showControls(false);
561
+ }
562
+ }
563
+ });
564
+
565
+ } else {
566
+ // click to play/pause
567
+ t.media.addEventListener('click', function() {
568
+ if (t.options.clickToPlayPause) {
569
+ if (t.media.paused) {
570
+ t.media.play();
571
+ } else {
572
+ t.media.pause();
573
+ }
574
+ }
575
+ });
576
+
577
+ // show/hide controls
578
+ t.container
579
+ .bind('mouseenter mouseover', function () {
580
+ if (t.controlsEnabled) {
581
+ if (!t.options.alwaysShowControls) {
582
+ t.killControlsTimer('enter');
583
+ t.showControls();
584
+ t.startControlsTimer(2500);
585
+ }
586
+ }
587
+ })
588
+ .bind('mousemove', function() {
589
+ if (t.controlsEnabled) {
590
+ if (!t.controlsAreVisible) {
591
+ t.showControls();
592
+ }
593
+ //t.killControlsTimer('move');
594
+ if (!t.options.alwaysShowControls) {
595
+ t.startControlsTimer(2500);
596
+ }
597
+ }
598
+ })
599
+ .bind('mouseleave', function () {
600
+ if (t.controlsEnabled) {
601
+ if (!t.media.paused && !t.options.alwaysShowControls) {
602
+ t.startControlsTimer(1000);
603
+ }
604
+ }
605
+ });
606
+ }
607
+
608
+ // check for autoplay
609
+ if (autoplay && !t.options.alwaysShowControls) {
610
+ t.hideControls();
611
+ }
612
+
613
+ // resizer
614
+ if (t.options.enableAutosize) {
615
+ t.media.addEventListener('loadedmetadata', function(e) {
616
+ // if the <video height> was not set and the options.videoHeight was not set
617
+ // then resize to the real dimensions
618
+ if (t.options.videoHeight <= 0 && t.domNode.getAttribute('height') === null && !isNaN(e.target.videoHeight)) {
619
+ t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);
620
+ t.setControlsSize();
621
+ t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);
622
+ }
623
+ }, false);
624
+ }
625
+ }
626
+
627
+ // EVENTS
628
+
629
+ // FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)
630
+ media.addEventListener('play', function() {
631
+
632
+ // go through all other players
633
+ for (var i=0, il=mejs.players.length; i<il; i++) {
634
+ var p = mejs.players[i];
635
+ if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
636
+ p.pause();
637
+ }
638
+ p.hasFocus = false;
639
+ }
640
+
641
+ t.hasFocus = true;
642
+ },false);
643
+
644
+
645
+ // ended for all
646
+ t.media.addEventListener('ended', function (e) {
647
+ if(t.options.autoRewind) {
648
+ try{
649
+ t.media.setCurrentTime(0);
650
+ } catch (exp) {
651
+
652
+ }
653
+ }
654
+ t.media.pause();
655
+
656
+ if (t.setProgressRail)
657
+ t.setProgressRail();
658
+ if (t.setCurrentRail)
659
+ t.setCurrentRail();
660
+
661
+ if (t.options.loop) {
662
+ t.media.play();
663
+ } else if (!t.options.alwaysShowControls && t.controlsEnabled) {
664
+ t.showControls();
665
+ }
666
+ }, false);
667
+
668
+ // resize on the first play
669
+ t.media.addEventListener('loadedmetadata', function(e) {
670
+ if (t.updateDuration) {
671
+ t.updateDuration();
672
+ }
673
+ if (t.updateCurrent) {
674
+ t.updateCurrent();
675
+ }
676
+
677
+ if (!t.isFullScreen) {
678
+ t.setPlayerSize(t.width, t.height);
679
+ t.setControlsSize();
680
+ }
681
+ }, false);
682
+
683
+
684
+ // webkit has trouble doing this without a delay
685
+ setTimeout(function () {
686
+ t.setPlayerSize(t.width, t.height);
687
+ t.setControlsSize();
688
+ }, 50);
689
+
690
+ // adjust controls whenever window sizes (used to be in fullscreen only)
691
+ $(window).resize(function() {
692
+
693
+ // don't resize for fullscreen mode
694
+ if ( !(t.isFullScreen || (mejs.MediaFeatures.hasTrueNativeFullScreen && document.webkitIsFullScreen)) ) {
695
+ t.setPlayerSize(t.width, t.height);
696
+ }
697
+
698
+ // always adjust controls
699
+ t.setControlsSize();
700
+ });
701
+
702
+ // TEMP: needs to be moved somewhere else
703
+ if (t.media.pluginType == 'youtube') {
704
+ t.container.find('.mejs-overlay-play').hide();
705
+ }
706
+ }
707
+
708
+ // force autoplay for HTML5
709
+ if (autoplay && media.pluginType == 'native') {
710
+ media.load();
711
+ media.play();
712
+ }
713
+
714
+
715
+ if (t.options.success) {
716
+
717
+ if (typeof t.options.success == 'string') {
718
+ window[t.options.success](t.media, t.domNode, t);
719
+ } else {
720
+ t.options.success(t.media, t.domNode, t);
721
+ }
722
+ }
723
+ },
724
+
725
+ handleError: function(e) {
726
+ var t = this;
727
+
728
+ t.controls.hide();
729
+
730
+ // Tell user that the file cannot be played
731
+ if (t.options.error) {
732
+ t.options.error(e);
733
+ }
734
+ },
735
+
736
+ setPlayerSize: function(width,height) {
737
+ var t = this;
738
+
739
+ if (typeof width != 'undefined')
740
+ t.width = width;
741
+
742
+ if (typeof height != 'undefined')
743
+ t.height = height;
744
+
745
+ // detect 100% mode - use currentStyle for IE since css() doesn't return percentages
746
+ if (t.height.toString().indexOf('%') > 0 || t.$node.css('max-width') === '100%' || (t.$node[0].currentStyle && t.$node[0].currentStyle.maxWidth === '100%')) {
747
+
748
+ // do we have the native dimensions yet?
749
+ var
750
+ nativeWidth = t.isVideo ? ((t.media.videoWidth && t.media.videoWidth > 0) ? t.media.videoWidth : t.options.defaultVideoWidth) : t.options.defaultAudioWidth,
751
+ nativeHeight = t.isVideo ? ((t.media.videoHeight && t.media.videoHeight > 0) ? t.media.videoHeight : t.options.defaultVideoHeight) : t.options.defaultAudioHeight,
752
+ parentWidth = t.container.parent().closest(':visible').width(),
753
+ newHeight = t.isVideo || !t.options.autosizeProgress ? parseInt(parentWidth * nativeHeight/nativeWidth, 10) : nativeHeight;
754
+
755
+ if (t.container.parent()[0].tagName.toLowerCase() === 'body') { // && t.container.siblings().count == 0) {
756
+ parentWidth = $(window).width();
757
+ newHeight = $(window).height();
758
+ }
759
+
760
+ if ( newHeight != 0 && parentWidth != 0 ) {
761
+ // set outer container size
762
+ t.container
763
+ .width(parentWidth)
764
+ .height(newHeight);
765
+
766
+ // set native <video> or <audio>
767
+ t.$media
768
+ .width('100%')
769
+ .height('100%');
770
+
771
+ // set shims
772
+ t.container.find('object, embed, iframe')
773
+ .width('100%')
774
+ .height('100%');
775
+
776
+ // if shim is ready, send the size to the embeded plugin
777
+ if (t.isVideo) {
778
+ if (t.media.setVideoSize) {
779
+ t.media.setVideoSize(parentWidth, newHeight);
780
+ }
781
+ }
782
+
783
+ // set the layers
784
+ t.layers.children('.mejs-layer')
785
+ .width('100%')
786
+ .height('100%');
787
+ }
788
+
789
+
790
+ } else {
791
+
792
+ t.container
793
+ .width(t.width)
794
+ .height(t.height);
795
+
796
+ t.layers.children('.mejs-layer')
797
+ .width(t.width)
798
+ .height(t.height);
799
+
800
+ }
801
+ },
802
+
803
+ setControlsSize: function() {
804
+ var t = this,
805
+ usedWidth = 0,
806
+ railWidth = 0,
807
+ rail = t.controls.find('.mejs-time-rail'),
808
+ total = t.controls.find('.mejs-time-total'),
809
+ current = t.controls.find('.mejs-time-current'),
810
+ loaded = t.controls.find('.mejs-time-loaded'),
811
+ others = rail.siblings();
812
+
813
+
814
+ // allow the size to come from custom CSS
815
+ if (t.options && !t.options.autosizeProgress) {
816
+ // Also, frontends devs can be more flexible
817
+ // due the opportunity of absolute positioning.
818
+ railWidth = parseInt(rail.css('width'));
819
+ }
820
+
821
+ // attempt to autosize
822
+ if (railWidth === 0 || !railWidth) {
823
+
824
+ // find the size of all the other controls besides the rail
825
+ others.each(function() {
826
+ if ($(this).css('position') != 'absolute') {
827
+ usedWidth += $(this).outerWidth(true);
828
+ }
829
+ });
830
+
831
+ // fit the rail into the remaining space
832
+ railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.width());
833
+ }
834
+
835
+ // outer area
836
+ rail.width(railWidth);
837
+ // dark space
838
+ total.width(railWidth - (total.outerWidth(true) - total.width()));
839
+
840
+ if (t.setProgressRail)
841
+ t.setProgressRail();
842
+ if (t.setCurrentRail)
843
+ t.setCurrentRail();
844
+ },
845
+
846
+
847
+ buildposter: function(player, controls, layers, media) {
848
+ var t = this,
849
+ poster =
850
+ $('<div class="mejs-poster mejs-layer">' +
851
+ '</div>')
852
+ .appendTo(layers),
853
+ posterUrl = player.$media.attr('poster');
854
+
855
+ // prioriy goes to option (this is useful if you need to support iOS 3.x (iOS completely fails with poster)
856
+ if (player.options.poster !== '') {
857
+ posterUrl = player.options.poster;
858
+ }
859
+
860
+ // second, try the real poster
861
+ if (posterUrl !== '' && posterUrl != null) {
862
+ t.setPoster(posterUrl);
863
+ } else {
864
+ poster.hide();
865
+ }
866
+
867
+ media.addEventListener('play',function() {
868
+ poster.hide();
869
+ }, false);
870
+ },
871
+
872
+ setPoster: function(url) {
873
+ var t = this,
874
+ posterDiv = t.container.find('.mejs-poster'),
875
+ posterImg = posterDiv.find('img');
876
+
877
+ if (posterImg.length == 0) {
878
+ posterImg = $('<img width="100%" height="100%" />').appendTo(posterDiv);
879
+ }
880
+
881
+ posterImg.attr('src', url);
882
+ },
883
+
884
+ buildoverlays: function(player, controls, layers, media) {
885
+ var t = this;
886
+ if (!player.isVideo)
887
+ return;
888
+
889
+ var
890
+ loading =
891
+ $('<div class="mejs-overlay mejs-layer">'+
892
+ '<div class="mejs-overlay-loading"><span></span></div>'+
893
+ '</div>')
894
+ .hide() // start out hidden
895
+ .appendTo(layers),
896
+ error =
897
+ $('<div class="mejs-overlay mejs-layer">'+
898
+ '<div class="mejs-overlay-error"></div>'+
899
+ '</div>')
900
+ .hide() // start out hidden
901
+ .appendTo(layers),
902
+ // this needs to come last so it's on top
903
+ bigPlay =
904
+ $('<div class="mejs-overlay mejs-layer mejs-overlay-play">'+
905
+ '<div class="mejs-overlay-button"></div>'+
906
+ '</div>')
907
+ .appendTo(layers)
908
+ .click(function() {
909
+ if (t.options.clickToPlayPause) {
910
+ if (media.paused) {
911
+ media.play();
912
+ } else {
913
+ media.pause();
914
+ }
915
+ }
916
+ });
917
+
918
+ /*
919
+ if (mejs.MediaFeatures.isiOS || mejs.MediaFeatures.isAndroid) {
920
+ bigPlay.remove();
921
+ loading.remove();
922
+ }
923
+ */
924
+
925
+
926
+ // show/hide big play button
927
+ media.addEventListener('play',function() {
928
+ bigPlay.hide();
929
+ loading.hide();
930
+ controls.find('.mejs-time-buffering').hide();
931
+ error.hide();
932
+ }, false);
933
+
934
+ media.addEventListener('playing', function() {
935
+ bigPlay.hide();
936
+ loading.hide();
937
+ controls.find('.mejs-time-buffering').hide();
938
+ error.hide();
939
+ }, false);
940
+
941
+ media.addEventListener('seeking', function() {
942
+ loading.show();
943
+ controls.find('.mejs-time-buffering').show();
944
+ }, false);
945
+
946
+ media.addEventListener('seeked', function() {
947
+ loading.hide();
948
+ controls.find('.mejs-time-buffering').hide();
949
+ }, false);
950
+
951
+ media.addEventListener('pause',function() {
952
+ if (!mejs.MediaFeatures.isiPhone) {
953
+ bigPlay.show();
954
+ }
955
+ }, false);
956
+
957
+ media.addEventListener('waiting', function() {
958
+ loading.show();
959
+ controls.find('.mejs-time-buffering').show();
960
+ }, false);
961
+
962
+
963
+ // show/hide loading
964
+ media.addEventListener('loadeddata',function() {
965
+ // for some reason Chrome is firing this event
966
+ //if (mejs.MediaFeatures.isChrome && media.getAttribute && media.getAttribute('preload') === 'none')
967
+ // return;
968
+
969
+ loading.show();
970
+ controls.find('.mejs-time-buffering').show();
971
+ }, false);
972
+ media.addEventListener('canplay',function() {
973
+ loading.hide();
974
+ controls.find('.mejs-time-buffering').hide();
975
+ }, false);
976
+
977
+ // error handling
978
+ media.addEventListener('error',function() {
979
+ loading.hide();
980
+ controls.find('.mejs-time-buffering').hide();
981
+ error.show();
982
+ error.find('mejs-overlay-error').html("Error loading this resource");
983
+ }, false);
984
+ },
985
+
986
+ buildkeyboard: function(player, controls, layers, media) {
987
+
988
+ var t = this;
989
+
990
+ // listen for key presses
991
+ $(document).keydown(function(e) {
992
+
993
+ if (player.hasFocus && player.options.enableKeyboard) {
994
+
995
+ // find a matching key
996
+ for (var i=0, il=player.options.keyActions.length; i<il; i++) {
997
+ var keyAction = player.options.keyActions[i];
998
+
999
+ for (var j=0, jl=keyAction.keys.length; j<jl; j++) {
1000
+ if (e.keyCode == keyAction.keys[j]) {
1001
+ e.preventDefault();
1002
+ keyAction.action(player, media, e.keyCode);
1003
+ return false;
1004
+ }
1005
+ }
1006
+ }
1007
+ }
1008
+
1009
+ return true;
1010
+ });
1011
+
1012
+ // check if someone clicked outside a player region, then kill its focus
1013
+ $(document).click(function(event) {
1014
+ if ($(event.target).closest('.mejs-container').length == 0) {
1015
+ player.hasFocus = false;
1016
+ }
1017
+ });
1018
+
1019
+ },
1020
+
1021
+ findTracks: function() {
1022
+ var t = this,
1023
+ tracktags = t.$media.find('track');
1024
+
1025
+ // store for use by plugins
1026
+ t.tracks = [];
1027
+ tracktags.each(function(index, track) {
1028
+
1029
+ track = $(track);
1030
+
1031
+ t.tracks.push({
1032
+ srclang: track.attr('srclang').toLowerCase(),
1033
+ src: track.attr('src'),
1034
+ kind: track.attr('kind'),
1035
+ label: track.attr('label') || '',
1036
+ entries: [],
1037
+ isLoaded: false
1038
+ });
1039
+ });
1040
+ },
1041
+ changeSkin: function(className) {
1042
+ this.container[0].className = 'mejs-container ' + className;
1043
+ this.setPlayerSize(this.width, this.height);
1044
+ this.setControlsSize();
1045
+ },
1046
+ play: function() {
1047
+ this.media.play();
1048
+ },
1049
+ pause: function() {
1050
+ this.media.pause();
1051
+ },
1052
+ load: function() {
1053
+ this.media.load();
1054
+ },
1055
+ setMuted: function(muted) {
1056
+ this.media.setMuted(muted);
1057
+ },
1058
+ setCurrentTime: function(time) {
1059
+ this.media.setCurrentTime(time);
1060
+ },
1061
+ getCurrentTime: function() {
1062
+ return this.media.currentTime;
1063
+ },
1064
+ setVolume: function(volume) {
1065
+ this.media.setVolume(volume);
1066
+ },
1067
+ getVolume: function() {
1068
+ return this.media.volume;
1069
+ },
1070
+ setSrc: function(src) {
1071
+ this.media.setSrc(src);
1072
+ },
1073
+ remove: function() {
1074
+ var t = this;
1075
+
1076
+ if (t.media.pluginType === 'flash') {
1077
+ t.media.remove();
1078
+ } else if (t.media.pluginType === 'native') {
1079
+ t.$media.prop('controls', true);
1080
+ }
1081
+
1082
+ // grab video and put it back in place
1083
+ if (!t.isDynamic) {
1084
+ t.$node.insertBefore(t.container)
1085
+ }
1086
+
1087
+ t.container.remove();
1088
+ }
1089
+ };
1090
+
1091
+ // turn into jQuery plugin
1092
+ if (typeof jQuery != 'undefined') {
1093
+ jQuery.fn.mediaelementplayer = function (options) {
1094
+ return this.each(function () {
1095
+ new mejs.MediaElementPlayer(this, options);
1096
+ });
1097
+ };
1098
+ }
1099
+
1100
+ $(document).ready(function() {
1101
+ // auto enable using JSON attribute
1102
+ $('.mejs-player').mediaelementplayer();
1103
+ });
1104
+
1105
+ // push out to window
1106
+ window.MediaElementPlayer = mejs.MediaElementPlayer;
1107
+
1108
+ })(mejs.$);
1093
1109
 
1094
1110
  (function($) {
1095
1111
 
@@ -1157,7 +1173,8 @@ if (typeof jQuery != 'undefined') {
1157
1173
  media.pause();
1158
1174
  }
1159
1175
  if (media.currentTime > 0) {
1160
- media.setCurrentTime(0);
1176
+ media.setCurrentTime(0);
1177
+ media.pause();
1161
1178
  controls.find('.mejs-time-current').width('0px');
1162
1179
  controls.find('.mejs-time-handle').css('left', '0px');
1163
1180
  controls.find('.mejs-time-float-current').html( mejs.Utility.secondsToTimeCode(0) );
@@ -1201,18 +1218,25 @@ if (typeof jQuery != 'undefined') {
1201
1218
  // mouse position relative to the object
1202
1219
  var x = e.pageX,
1203
1220
  offset = total.offset(),
1204
- width = total.outerWidth(),
1221
+ width = total.outerWidth(true),
1205
1222
  percentage = 0,
1206
1223
  newTime = 0,
1207
- pos = x - offset.left;
1224
+ pos = 0;
1208
1225
 
1209
1226
 
1210
- if (x > offset.left && x <= width + offset.left && media.duration) {
1211
- percentage = ((x - offset.left) / width);
1227
+ if (media.duration) {
1228
+ if (x < offset.left) {
1229
+ x = offset.left;
1230
+ } else if (x > width + offset.left) {
1231
+ x = width + offset.left;
1232
+ }
1233
+
1234
+ pos = x - offset.left;
1235
+ percentage = (pos / width);
1212
1236
  newTime = (percentage <= 0.02) ? 0 : percentage * media.duration;
1213
1237
 
1214
1238
  // seek to where the mouse is
1215
- if (mouseIsDown) {
1239
+ if (mouseIsDown && newTime !== media.currentTime) {
1216
1240
  media.setCurrentTime(newTime);
1217
1241
  }
1218
1242
 
@@ -1336,86 +1360,90 @@ if (typeof jQuery != 'undefined') {
1336
1360
  }
1337
1361
  });
1338
1362
  })(mejs.$);
1339
- (function($) {
1340
-
1341
- // options
1342
- $.extend(mejs.MepDefaults, {
1343
- duration: -1,
1344
- timeAndDurationSeparator: ' <span> | </span> '
1345
- });
1346
-
1347
-
1348
- // current and duration 00:00 / 00:00
1349
- $.extend(MediaElementPlayer.prototype, {
1350
- buildcurrent: function(player, controls, layers, media) {
1351
- var t = this;
1352
-
1353
- $('<div class="mejs-time">'+
1354
- '<span class="mejs-currenttime">' + (player.options.alwaysShowHours ? '00:' : '')
1355
- + (player.options.showTimecodeFrameCount? '00:00:00':'00:00')+ '</span>'+
1356
- '</div>')
1357
- .appendTo(controls);
1358
-
1359
- t.currenttime = t.controls.find('.mejs-currenttime');
1360
-
1361
- media.addEventListener('timeupdate',function() {
1362
- player.updateCurrent();
1363
- }, false);
1364
- },
1365
-
1366
-
1367
- buildduration: function(player, controls, layers, media) {
1368
- var t = this;
1369
-
1370
- if (controls.children().last().find('.mejs-currenttime').length > 0) {
1371
- $(t.options.timeAndDurationSeparator +
1372
- '<span class="mejs-duration">' +
1373
- (t.options.duration > 0 ?
1374
- mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
1375
- ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
1376
- ) +
1377
- '</span>')
1378
- .appendTo(controls.find('.mejs-time'));
1379
- } else {
1380
-
1381
- // add class to current time
1382
- controls.find('.mejs-currenttime').parent().addClass('mejs-currenttime-container');
1383
-
1384
- $('<div class="mejs-time mejs-duration-container">'+
1385
- '<span class="mejs-duration">' +
1386
- (t.options.duration > 0 ?
1387
- mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
1388
- ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
1389
- ) +
1390
- '</span>' +
1391
- '</div>')
1392
- .appendTo(controls);
1393
- }
1394
-
1395
- t.durationD = t.controls.find('.mejs-duration');
1396
-
1397
- media.addEventListener('timeupdate',function() {
1398
- player.updateDuration();
1399
- }, false);
1400
- },
1401
-
1402
- updateCurrent: function() {
1403
- var t = this;
1404
-
1405
- if (t.currenttime) {
1406
- t.currenttime.html(mejs.Utility.secondsToTimeCode(t.media.currentTime, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
1407
- }
1408
- },
1409
-
1410
- updateDuration: function() {
1411
- var t = this;
1412
-
1413
- if (t.media.duration && t.durationD) {
1414
- t.durationD.html(mejs.Utility.secondsToTimeCode(t.media.duration, t.options.alwaysShowHours, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
1415
- }
1416
- }
1417
- });
1418
-
1363
+
1364
+ (function($) {
1365
+
1366
+ // options
1367
+ $.extend(mejs.MepDefaults, {
1368
+ duration: -1,
1369
+ timeAndDurationSeparator: ' <span> | </span> '
1370
+ });
1371
+
1372
+
1373
+ // current and duration 00:00 / 00:00
1374
+ $.extend(MediaElementPlayer.prototype, {
1375
+ buildcurrent: function(player, controls, layers, media) {
1376
+ var t = this;
1377
+
1378
+ $('<div class="mejs-time">'+
1379
+ '<span class="mejs-currenttime">' + (player.options.alwaysShowHours ? '00:' : '')
1380
+ + (player.options.showTimecodeFrameCount? '00:00:00':'00:00')+ '</span>'+
1381
+ '</div>')
1382
+ .appendTo(controls);
1383
+
1384
+ t.currenttime = t.controls.find('.mejs-currenttime');
1385
+
1386
+ media.addEventListener('timeupdate',function() {
1387
+ player.updateCurrent();
1388
+ }, false);
1389
+ },
1390
+
1391
+
1392
+ buildduration: function(player, controls, layers, media) {
1393
+ var t = this;
1394
+
1395
+ if (controls.children().last().find('.mejs-currenttime').length > 0) {
1396
+ $(t.options.timeAndDurationSeparator +
1397
+ '<span class="mejs-duration">' +
1398
+ (t.options.duration > 0 ?
1399
+ mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
1400
+ ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
1401
+ ) +
1402
+ '</span>')
1403
+ .appendTo(controls.find('.mejs-time'));
1404
+ } else {
1405
+
1406
+ // add class to current time
1407
+ controls.find('.mejs-currenttime').parent().addClass('mejs-currenttime-container');
1408
+
1409
+ $('<div class="mejs-time mejs-duration-container">'+
1410
+ '<span class="mejs-duration">' +
1411
+ (t.options.duration > 0 ?
1412
+ mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
1413
+ ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
1414
+ ) +
1415
+ '</span>' +
1416
+ '</div>')
1417
+ .appendTo(controls);
1418
+ }
1419
+
1420
+ t.durationD = t.controls.find('.mejs-duration');
1421
+
1422
+ media.addEventListener('timeupdate',function() {
1423
+ player.updateDuration();
1424
+ }, false);
1425
+ },
1426
+
1427
+ updateCurrent: function() {
1428
+ var t = this;
1429
+
1430
+ if (t.currenttime) {
1431
+ t.currenttime.html(mejs.Utility.secondsToTimeCode(t.media.currentTime, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
1432
+ }
1433
+ },
1434
+
1435
+ updateDuration: function() {
1436
+ var t = this;
1437
+
1438
+ //Toggle the long video class if the video is longer than an hour.
1439
+ t.container.toggleClass("mejs-long-video", t.media.duration > 3600);
1440
+
1441
+ if (t.media.duration && t.durationD) {
1442
+ t.durationD.html(mejs.Utility.secondsToTimeCode(t.media.duration, t.options.alwaysShowHours, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
1443
+ }
1444
+ }
1445
+ });
1446
+
1419
1447
  })(mejs.$);
1420
1448
  (function($) {
1421
1449
 
@@ -1467,7 +1495,7 @@ if (typeof jQuery != 'undefined') {
1467
1495
 
1468
1496
  positionVolumeHandle = function(volume, secondTry) {
1469
1497
 
1470
- if (!volumeSlider.is(':visible') && typeof secondTry != 'undefined') {
1498
+ if (!volumeSlider.is(':visible') && typeof secondTry == 'undefined') {
1471
1499
  volumeSlider.show();
1472
1500
  positionVolumeHandle(volume, true);
1473
1501
  volumeSlider.hide()
@@ -1500,7 +1528,7 @@ if (typeof jQuery != 'undefined') {
1500
1528
  newTop = totalHeight - (totalHeight * volume);
1501
1529
 
1502
1530
  // handle
1503
- volumeHandle.css('top', totalPosition.top + newTop - (volumeHandle.height() / 2));
1531
+ volumeHandle.css('top', Math.round(totalPosition.top + newTop - (volumeHandle.height() / 2)));
1504
1532
 
1505
1533
  // show the current visibility
1506
1534
  volumeCurrent.height(totalHeight - newTop );
@@ -1518,10 +1546,10 @@ if (typeof jQuery != 'undefined') {
1518
1546
  newLeft = totalWidth * volume;
1519
1547
 
1520
1548
  // handle
1521
- volumeHandle.css('left', totalPosition.left + newLeft - (volumeHandle.width() / 2));
1549
+ volumeHandle.css('left', Math.round(totalPosition.left + newLeft - (volumeHandle.width() / 2)));
1522
1550
 
1523
1551
  // rezize the current part of the volume bar
1524
- volumeCurrent.width( newLeft );
1552
+ volumeCurrent.width( Math.round(newLeft) );
1525
1553
  }
1526
1554
  },
1527
1555
  handleVolumeMove = function(e) {
@@ -1597,485 +1625,485 @@ if (typeof jQuery != 'undefined') {
1597
1625
  mouseIsDown = false;
1598
1626
  $(document).unbind('.vol');
1599
1627
 
1600
- if (!mouseIsOver && mode == 'vertical') {
1601
- volumeSlider.hide();
1628
+ if (!mouseIsOver && mode == 'vertical') {
1629
+ volumeSlider.hide();
1630
+ }
1631
+ });
1632
+ mouseIsDown = true;
1633
+
1634
+ return false;
1635
+ });
1636
+
1637
+
1638
+ // MUTE button
1639
+ mute.find('button').click(function() {
1640
+ media.setMuted( !media.muted );
1641
+ });
1642
+
1643
+ // listen for volume change events from other sources
1644
+ media.addEventListener('volumechange', function(e) {
1645
+ if (!mouseIsDown) {
1646
+ if (media.muted) {
1647
+ positionVolumeHandle(0);
1648
+ mute.removeClass('mejs-mute').addClass('mejs-unmute');
1649
+ } else {
1650
+ positionVolumeHandle(media.volume);
1651
+ mute.removeClass('mejs-unmute').addClass('mejs-mute');
1652
+ }
1653
+ }
1654
+ }, false);
1655
+
1656
+ if (t.container.is(':visible')) {
1657
+ // set initial volume
1658
+ positionVolumeHandle(player.options.startVolume);
1659
+
1660
+ // shim gets the startvolume as a parameter, but we have to set it on the native <video> and <audio> elements
1661
+ if (media.pluginType === 'native') {
1662
+ media.setVolume(player.options.startVolume);
1663
+ }
1664
+ }
1665
+ }
1666
+ });
1667
+
1668
+ })(mejs.$);
1669
+
1670
+ (function($) {
1671
+
1672
+ $.extend(mejs.MepDefaults, {
1673
+ usePluginFullScreen: true,
1674
+ newWindowCallback: function() { return '';},
1675
+ fullscreenText: mejs.i18n.t('Fullscreen')
1676
+ });
1677
+
1678
+ $.extend(MediaElementPlayer.prototype, {
1679
+
1680
+ isFullScreen: false,
1681
+
1682
+ isNativeFullScreen: false,
1683
+
1684
+ docStyleOverflow: null,
1685
+
1686
+ isInIframe: false,
1687
+
1688
+ buildfullscreen: function(player, controls, layers, media) {
1689
+
1690
+ if (!player.isVideo)
1691
+ return;
1692
+
1693
+ player.isInIframe = (window.location != window.parent.location);
1694
+
1695
+ // native events
1696
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
1697
+
1698
+ // chrome doesn't alays fire this in an iframe
1699
+ var target = null;
1700
+
1701
+ if (mejs.MediaFeatures.hasMozNativeFullScreen) {
1702
+ target = $(document);
1703
+ } else {
1704
+ target = player.container;
1705
+ }
1706
+
1707
+ target.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {
1708
+
1709
+ if (mejs.MediaFeatures.isFullScreen()) {
1710
+ player.isNativeFullScreen = true;
1711
+ // reset the controls once we are fully in full screen
1712
+ player.setControlsSize();
1713
+ } else {
1714
+ player.isNativeFullScreen = false;
1715
+ // when a user presses ESC
1716
+ // make sure to put the player back into place
1717
+ player.exitFullScreen();
1718
+ }
1719
+ });
1720
+ }
1721
+
1722
+ var t = this,
1723
+ normalHeight = 0,
1724
+ normalWidth = 0,
1725
+ container = player.container,
1726
+ fullscreenBtn =
1727
+ $('<div class="mejs-button mejs-fullscreen-button">' +
1728
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
1729
+ '</div>')
1730
+ .appendTo(controls);
1731
+
1732
+ if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {
1733
+
1734
+ fullscreenBtn.click(function() {
1735
+ var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;
1736
+
1737
+ if (isFullScreen) {
1738
+ player.exitFullScreen();
1739
+ } else {
1740
+ player.enterFullScreen();
1741
+ }
1742
+ });
1743
+
1744
+ } else {
1745
+
1746
+ var hideTimeout = null,
1747
+ supportsPointerEvents = (function() {
1748
+ // TAKEN FROM MODERNIZR
1749
+ var element = document.createElement('x'),
1750
+ documentElement = document.documentElement,
1751
+ getComputedStyle = window.getComputedStyle,
1752
+ supports;
1753
+ if(!('pointerEvents' in element.style)){
1754
+ return false;
1755
+ }
1756
+ element.style.pointerEvents = 'auto';
1757
+ element.style.pointerEvents = 'x';
1758
+ documentElement.appendChild(element);
1759
+ supports = getComputedStyle &&
1760
+ getComputedStyle(element, '').pointerEvents === 'auto';
1761
+ documentElement.removeChild(element);
1762
+ return !!supports;
1763
+ })();
1764
+
1765
+ //console.log('supportsPointerEvents', supportsPointerEvents);
1766
+
1767
+ if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(
1768
+
1769
+ // allows clicking through the fullscreen button and controls down directly to Flash
1770
+
1771
+ /*
1772
+ When a user puts his mouse over the fullscreen button, the controls are disabled
1773
+ So we put a div over the video and another one on iether side of the fullscreen button
1774
+ that caputre mouse movement
1775
+ and restore the controls once the mouse moves outside of the fullscreen button
1776
+ */
1777
+
1778
+ var fullscreenIsDisabled = false,
1779
+ restoreControls = function() {
1780
+ if (fullscreenIsDisabled) {
1781
+ // hide the hovers
1782
+ videoHoverDiv.hide();
1783
+ controlsLeftHoverDiv.hide();
1784
+ controlsRightHoverDiv.hide();
1785
+
1786
+ // restore the control bar
1787
+ fullscreenBtn.css('pointer-events', '');
1788
+ t.controls.css('pointer-events', '');
1789
+
1790
+ // store for later
1791
+ fullscreenIsDisabled = false;
1792
+ }
1793
+ },
1794
+ videoHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1795
+ controlsLeftHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1796
+ controlsRightHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1797
+ positionHoverDivs = function() {
1798
+ var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
1799
+ videoHoverDiv.css(style);
1800
+ controlsLeftHoverDiv.css(style);
1801
+ controlsRightHoverDiv.css(style);
1802
+
1803
+ // over video, but not controls
1804
+ videoHoverDiv
1805
+ .width( t.container.width() )
1806
+ .height( t.container.height() - t.controls.height() );
1807
+
1808
+ // over controls, but not the fullscreen button
1809
+ var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
1810
+ fullScreenBtnWidth = fullscreenBtn.outerWidth(true);
1811
+
1812
+ controlsLeftHoverDiv
1813
+ .width( fullScreenBtnOffset )
1814
+ .height( t.controls.height() )
1815
+ .css({top: t.container.height() - t.controls.height()});
1816
+
1817
+ // after the fullscreen button
1818
+ controlsRightHoverDiv
1819
+ .width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
1820
+ .height( t.controls.height() )
1821
+ .css({top: t.container.height() - t.controls.height(),
1822
+ left: fullScreenBtnOffset + fullScreenBtnWidth});
1823
+ };
1824
+
1825
+ $(document).resize(function() {
1826
+ positionHoverDivs();
1827
+ });
1828
+
1829
+ // on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
1830
+ fullscreenBtn
1831
+ .mouseover(function() {
1832
+
1833
+ if (!t.isFullScreen) {
1834
+
1835
+ var buttonPos = fullscreenBtn.offset(),
1836
+ containerPos = player.container.offset();
1837
+
1838
+ // move the button in Flash into place
1839
+ media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);
1840
+
1841
+ // allows click through
1842
+ fullscreenBtn.css('pointer-events', 'none');
1843
+ t.controls.css('pointer-events', 'none');
1844
+
1845
+ // show the divs that will restore things
1846
+ videoHoverDiv.show();
1847
+ controlsRightHoverDiv.show();
1848
+ controlsLeftHoverDiv.show();
1849
+ positionHoverDivs();
1850
+
1851
+ fullscreenIsDisabled = true;
1852
+ }
1853
+
1854
+ });
1855
+
1856
+ // restore controls anytime the user enters or leaves fullscreen
1857
+ media.addEventListener('fullscreenchange', function(e) {
1858
+ restoreControls();
1859
+ });
1860
+
1861
+
1862
+ // the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
1863
+ // so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
1864
+ /*
1865
+ $(document).mousemove(function(e) {
1866
+
1867
+ // if the mouse is anywhere but the fullsceen button, then restore it all
1868
+ if (fullscreenIsDisabled) {
1869
+
1870
+ var fullscreenBtnPos = fullscreenBtn.offset();
1871
+
1872
+
1873
+ if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
1874
+ e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
1875
+ ) {
1876
+
1877
+ fullscreenBtn.css('pointer-events', '');
1878
+ t.controls.css('pointer-events', '');
1879
+
1880
+ fullscreenIsDisabled = false;
1881
+ }
1602
1882
  }
1603
1883
  });
1604
- mouseIsDown = true;
1605
-
1606
- return false;
1607
- });
1884
+ */
1608
1885
 
1609
1886
 
1610
- // MUTE button
1611
- mute.find('button').click(function() {
1612
- media.setMuted( !media.muted );
1887
+ } else {
1888
+
1889
+ // the hover state will show the fullscreen button in Flash to hover up and click
1890
+
1891
+ fullscreenBtn
1892
+ .mouseover(function() {
1893
+
1894
+ if (hideTimeout !== null) {
1895
+ clearTimeout(hideTimeout);
1896
+ delete hideTimeout;
1897
+ }
1898
+
1899
+ var buttonPos = fullscreenBtn.offset(),
1900
+ containerPos = player.container.offset();
1901
+
1902
+ media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);
1903
+
1904
+ })
1905
+ .mouseout(function() {
1906
+
1907
+ if (hideTimeout !== null) {
1908
+ clearTimeout(hideTimeout);
1909
+ delete hideTimeout;
1910
+ }
1911
+
1912
+ hideTimeout = setTimeout(function() {
1913
+ media.hideFullscreenButton();
1914
+ }, 1500);
1915
+
1916
+
1917
+ });
1918
+ }
1919
+ }
1920
+
1921
+ player.fullscreenBtn = fullscreenBtn;
1922
+
1923
+ $(document).bind('keydown',function (e) {
1924
+ if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
1925
+ player.exitFullScreen();
1926
+ }
1613
1927
  });
1614
1928
 
1615
- // listen for volume change events from other sources
1616
- media.addEventListener('volumechange', function(e) {
1617
- if (!mouseIsDown) {
1618
- if (media.muted) {
1619
- positionVolumeHandle(0);
1620
- mute.removeClass('mejs-mute').addClass('mejs-unmute');
1621
- } else {
1622
- positionVolumeHandle(media.volume);
1623
- mute.removeClass('mejs-unmute').addClass('mejs-mute');
1929
+ },
1930
+ enterFullScreen: function() {
1931
+
1932
+ var t = this;
1933
+
1934
+ // firefox+flash can't adjust plugin sizes without resetting :(
1935
+ if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
1936
+ //t.media.setFullscreen(true);
1937
+ //player.isFullScreen = true;
1938
+ return;
1939
+ }
1940
+
1941
+ // store overflow
1942
+ docStyleOverflow = document.documentElement.style.overflow;
1943
+ // set it to not show scroll bars so 100% will work
1944
+ document.documentElement.style.overflow = 'hidden';
1945
+
1946
+ // store sizing
1947
+ normalHeight = t.container.height();
1948
+ normalWidth = t.container.width();
1949
+
1950
+ // attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
1951
+ if (t.media.pluginType === 'native') {
1952
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
1953
+
1954
+ mejs.MediaFeatures.requestFullScreen(t.container[0]);
1955
+ //return;
1956
+
1957
+ if (t.isInIframe) {
1958
+ // sometimes exiting from fullscreen doesn't work
1959
+ // notably in Chrome <iframe>. Fixed in version 17
1960
+ setTimeout(function checkFullscreen() {
1961
+
1962
+ if (t.isNativeFullScreen) {
1963
+
1964
+ // check if the video is suddenly not really fullscreen
1965
+ if ($(window).width() !== screen.width) {
1966
+ // manually exit
1967
+ t.exitFullScreen();
1968
+ } else {
1969
+ // test again
1970
+ setTimeout(checkFullscreen, 500);
1971
+ }
1972
+ }
1973
+
1974
+
1975
+ }, 500);
1624
1976
  }
1977
+
1978
+ } else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
1979
+ t.media.webkitEnterFullscreen();
1980
+ return;
1625
1981
  }
1626
- }, false);
1982
+ }
1627
1983
 
1628
- if (t.container.is(':visible')) {
1629
- // set initial volume
1630
- positionVolumeHandle(player.options.startVolume);
1631
-
1632
- // shim gets the startvolume as a parameter, but we have to set it on the native <video> and <audio> elements
1633
- if (media.pluginType === 'native') {
1634
- media.setVolume(player.options.startVolume);
1984
+ // check for iframe launch
1985
+ if (t.isInIframe) {
1986
+ var url = t.options.newWindowCallback(this);
1987
+
1988
+
1989
+ if (url !== '') {
1990
+
1991
+ // launch immediately
1992
+ if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
1993
+ t.pause();
1994
+ window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
1995
+ return;
1996
+ } else {
1997
+ setTimeout(function() {
1998
+ if (!t.isNativeFullScreen) {
1999
+ t.pause();
2000
+ window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
2001
+ }
2002
+ }, 250);
2003
+ }
1635
2004
  }
2005
+
2006
+ }
2007
+
2008
+ // full window code
2009
+
2010
+
2011
+
2012
+ // make full size
2013
+ t.container
2014
+ .addClass('mejs-container-fullscreen')
2015
+ .width('100%')
2016
+ .height('100%');
2017
+ //.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});
2018
+
2019
+ // Only needed for safari 5.1 native full screen, can cause display issues elsewhere
2020
+ // Actually, it seems to be needed for IE8, too
2021
+ //if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
2022
+ setTimeout(function() {
2023
+ t.container.css({width: '100%', height: '100%'});
2024
+ t.setControlsSize();
2025
+ }, 500);
2026
+ //}
2027
+
2028
+ if (t.pluginType === 'native') {
2029
+ t.$media
2030
+ .width('100%')
2031
+ .height('100%');
2032
+ } else {
2033
+ t.container.find('object, embed, iframe')
2034
+ .width('100%')
2035
+ .height('100%');
2036
+
2037
+ //if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
2038
+ t.media.setVideoSize($(window).width(),$(window).height());
2039
+ //}
2040
+ }
2041
+
2042
+ t.layers.children('div')
2043
+ .width('100%')
2044
+ .height('100%');
2045
+
2046
+ if (t.fullscreenBtn) {
2047
+ t.fullscreenBtn
2048
+ .removeClass('mejs-fullscreen')
2049
+ .addClass('mejs-unfullscreen');
2050
+ }
2051
+
2052
+ t.setControlsSize();
2053
+ t.isFullScreen = true;
2054
+ },
2055
+
2056
+ exitFullScreen: function() {
2057
+
2058
+ var t = this;
2059
+
2060
+ // firefox can't adjust plugins
2061
+ if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
2062
+ t.media.setFullscreen(false);
2063
+ //player.isFullScreen = false;
2064
+ return;
2065
+ }
2066
+
2067
+ // come outo of native fullscreen
2068
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
2069
+ mejs.MediaFeatures.cancelFullScreen();
2070
+ }
2071
+
2072
+ // restore scroll bars to document
2073
+ document.documentElement.style.overflow = docStyleOverflow;
2074
+
2075
+ t.container
2076
+ .removeClass('mejs-container-fullscreen')
2077
+ .width(normalWidth)
2078
+ .height(normalHeight);
2079
+ //.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});
2080
+
2081
+ if (t.pluginType === 'native') {
2082
+ t.$media
2083
+ .width(normalWidth)
2084
+ .height(normalHeight);
2085
+ } else {
2086
+ t.container.find('object embed')
2087
+ .width(normalWidth)
2088
+ .height(normalHeight);
2089
+
2090
+ t.media.setVideoSize(normalWidth, normalHeight);
1636
2091
  }
2092
+
2093
+ t.layers.children('div')
2094
+ .width(normalWidth)
2095
+ .height(normalHeight);
2096
+
2097
+ t.fullscreenBtn
2098
+ .removeClass('mejs-unfullscreen')
2099
+ .addClass('mejs-fullscreen');
2100
+
2101
+ t.setControlsSize();
2102
+ t.isFullScreen = false;
1637
2103
  }
1638
2104
  });
1639
-
1640
- })(mejs.$);
1641
2105
 
1642
- (function($) {
1643
-
1644
- $.extend(mejs.MepDefaults, {
1645
- usePluginFullScreen: true,
1646
- newWindowCallback: function() { return '';},
1647
- fullscreenText: 'Fullscreen'
1648
- });
1649
-
1650
- $.extend(MediaElementPlayer.prototype, {
1651
-
1652
- isFullScreen: false,
1653
-
1654
- isNativeFullScreen: false,
1655
-
1656
- docStyleOverflow: null,
1657
-
1658
- isInIframe: false,
1659
-
1660
- buildfullscreen: function(player, controls, layers, media) {
1661
-
1662
- if (!player.isVideo)
1663
- return;
1664
-
1665
- player.isInIframe = (window.location != window.parent.location);
1666
-
1667
- // native events
1668
- if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
1669
-
1670
- // chrome doesn't alays fire this in an iframe
1671
- var target = null;
1672
-
1673
- if (mejs.MediaFeatures.hasMozNativeFullScreen) {
1674
- target = $(document);
1675
- } else {
1676
- target = player.container;
1677
- }
1678
-
1679
- target.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {
1680
-
1681
- if (mejs.MediaFeatures.isFullScreen()) {
1682
- player.isNativeFullScreen = true;
1683
- // reset the controls once we are fully in full screen
1684
- player.setControlsSize();
1685
- } else {
1686
- player.isNativeFullScreen = false;
1687
- // when a user presses ESC
1688
- // make sure to put the player back into place
1689
- player.exitFullScreen();
1690
- }
1691
- });
1692
- }
1693
-
1694
- var t = this,
1695
- normalHeight = 0,
1696
- normalWidth = 0,
1697
- container = player.container,
1698
- fullscreenBtn =
1699
- $('<div class="mejs-button mejs-fullscreen-button">' +
1700
- '<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
1701
- '</div>')
1702
- .appendTo(controls);
1703
-
1704
- if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {
1705
-
1706
- fullscreenBtn.click(function() {
1707
- var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;
1708
-
1709
- if (isFullScreen) {
1710
- player.exitFullScreen();
1711
- } else {
1712
- player.enterFullScreen();
1713
- }
1714
- });
1715
-
1716
- } else {
1717
-
1718
- var hideTimeout = null,
1719
- supportsPointerEvents = (function() {
1720
- // TAKEN FROM MODERNIZR
1721
- var element = document.createElement('x'),
1722
- documentElement = document.documentElement,
1723
- getComputedStyle = window.getComputedStyle,
1724
- supports;
1725
- if(!('pointerEvents' in element.style)){
1726
- return false;
1727
- }
1728
- element.style.pointerEvents = 'auto';
1729
- element.style.pointerEvents = 'x';
1730
- documentElement.appendChild(element);
1731
- supports = getComputedStyle &&
1732
- getComputedStyle(element, '').pointerEvents === 'auto';
1733
- documentElement.removeChild(element);
1734
- return !!supports;
1735
- })();
1736
-
1737
- //console.log('supportsPointerEvents', supportsPointerEvents);
1738
-
1739
- if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(
1740
-
1741
- // allows clicking through the fullscreen button and controls down directly to Flash
1742
-
1743
- /*
1744
- When a user puts his mouse over the fullscreen button, the controls are disabled
1745
- So we put a div over the video and another one on iether side of the fullscreen button
1746
- that caputre mouse movement
1747
- and restore the controls once the mouse moves outside of the fullscreen button
1748
- */
1749
-
1750
- var fullscreenIsDisabled = false,
1751
- restoreControls = function() {
1752
- if (fullscreenIsDisabled) {
1753
- // hide the hovers
1754
- videoHoverDiv.hide();
1755
- controlsLeftHoverDiv.hide();
1756
- controlsRightHoverDiv.hide();
1757
-
1758
- // restore the control bar
1759
- fullscreenBtn.css('pointer-events', '');
1760
- t.controls.css('pointer-events', '');
1761
-
1762
- // store for later
1763
- fullscreenIsDisabled = false;
1764
- }
1765
- },
1766
- videoHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1767
- controlsLeftHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1768
- controlsRightHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1769
- positionHoverDivs = function() {
1770
- var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
1771
- videoHoverDiv.css(style);
1772
- controlsLeftHoverDiv.css(style);
1773
- controlsRightHoverDiv.css(style);
1774
-
1775
- // over video, but not controls
1776
- videoHoverDiv
1777
- .width( t.container.width() )
1778
- .height( t.container.height() - t.controls.height() );
1779
-
1780
- // over controls, but not the fullscreen button
1781
- var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
1782
- fullScreenBtnWidth = fullscreenBtn.outerWidth(true);
1783
-
1784
- controlsLeftHoverDiv
1785
- .width( fullScreenBtnOffset )
1786
- .height( t.controls.height() )
1787
- .css({top: t.container.height() - t.controls.height()});
1788
-
1789
- // after the fullscreen button
1790
- controlsRightHoverDiv
1791
- .width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
1792
- .height( t.controls.height() )
1793
- .css({top: t.container.height() - t.controls.height(),
1794
- left: fullScreenBtnOffset + fullScreenBtnWidth});
1795
- };
1796
-
1797
- $(document).resize(function() {
1798
- positionHoverDivs();
1799
- });
1800
-
1801
- // on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
1802
- fullscreenBtn
1803
- .mouseover(function() {
1804
-
1805
- if (!t.isFullScreen) {
1806
-
1807
- var buttonPos = fullscreenBtn.offset(),
1808
- containerPos = player.container.offset();
1809
-
1810
- // move the button in Flash into place
1811
- media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);
1812
-
1813
- // allows click through
1814
- fullscreenBtn.css('pointer-events', 'none');
1815
- t.controls.css('pointer-events', 'none');
1816
-
1817
- // show the divs that will restore things
1818
- videoHoverDiv.show();
1819
- controlsRightHoverDiv.show();
1820
- controlsLeftHoverDiv.show();
1821
- positionHoverDivs();
1822
-
1823
- fullscreenIsDisabled = true;
1824
- }
1825
-
1826
- });
1827
-
1828
- // restore controls anytime the user enters or leaves fullscreen
1829
- media.addEventListener('fullscreenchange', function(e) {
1830
- restoreControls();
1831
- });
1832
-
1833
-
1834
- // the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
1835
- // so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
1836
- /*
1837
- $(document).mousemove(function(e) {
1838
-
1839
- // if the mouse is anywhere but the fullsceen button, then restore it all
1840
- if (fullscreenIsDisabled) {
1841
-
1842
- var fullscreenBtnPos = fullscreenBtn.offset();
1843
-
1844
-
1845
- if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
1846
- e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
1847
- ) {
1848
-
1849
- fullscreenBtn.css('pointer-events', '');
1850
- t.controls.css('pointer-events', '');
1851
-
1852
- fullscreenIsDisabled = false;
1853
- }
1854
- }
1855
- });
1856
- */
1857
-
1858
-
1859
- } else {
1860
-
1861
- // the hover state will show the fullscreen button in Flash to hover up and click
1862
-
1863
- fullscreenBtn
1864
- .mouseover(function() {
1865
-
1866
- if (hideTimeout !== null) {
1867
- clearTimeout(hideTimeout);
1868
- delete hideTimeout;
1869
- }
1870
-
1871
- var buttonPos = fullscreenBtn.offset(),
1872
- containerPos = player.container.offset();
1873
-
1874
- media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);
1875
-
1876
- })
1877
- .mouseout(function() {
1878
-
1879
- if (hideTimeout !== null) {
1880
- clearTimeout(hideTimeout);
1881
- delete hideTimeout;
1882
- }
1883
-
1884
- hideTimeout = setTimeout(function() {
1885
- media.hideFullscreenButton();
1886
- }, 1500);
1887
-
1888
-
1889
- });
1890
- }
1891
- }
1892
-
1893
- player.fullscreenBtn = fullscreenBtn;
1894
-
1895
- $(document).bind('keydown',function (e) {
1896
- if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
1897
- player.exitFullScreen();
1898
- }
1899
- });
1900
-
1901
- },
1902
- enterFullScreen: function() {
1903
-
1904
- var t = this;
1905
-
1906
- // firefox+flash can't adjust plugin sizes without resetting :(
1907
- if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
1908
- //t.media.setFullscreen(true);
1909
- //player.isFullScreen = true;
1910
- return;
1911
- }
1912
-
1913
- // store overflow
1914
- docStyleOverflow = document.documentElement.style.overflow;
1915
- // set it to not show scroll bars so 100% will work
1916
- document.documentElement.style.overflow = 'hidden';
1917
-
1918
- // store sizing
1919
- normalHeight = t.container.height();
1920
- normalWidth = t.container.width();
1921
-
1922
- // attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
1923
- if (t.media.pluginType === 'native') {
1924
- if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
1925
-
1926
- mejs.MediaFeatures.requestFullScreen(t.container[0]);
1927
- //return;
1928
-
1929
- if (t.isInIframe) {
1930
- // sometimes exiting from fullscreen doesn't work
1931
- // notably in Chrome <iframe>. Fixed in version 17
1932
- setTimeout(function checkFullscreen() {
1933
-
1934
- if (t.isNativeFullScreen) {
1935
-
1936
- // check if the video is suddenly not really fullscreen
1937
- if ($(window).width() !== screen.width) {
1938
- // manually exit
1939
- t.exitFullScreen();
1940
- } else {
1941
- // test again
1942
- setTimeout(checkFullscreen, 500);
1943
- }
1944
- }
1945
-
1946
-
1947
- }, 500);
1948
- }
1949
-
1950
- } else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
1951
- t.media.webkitEnterFullscreen();
1952
- return;
1953
- }
1954
- }
1955
-
1956
- // check for iframe launch
1957
- if (t.isInIframe) {
1958
- var url = t.options.newWindowCallback(this);
1959
-
1960
-
1961
- if (url !== '') {
1962
-
1963
- // launch immediately
1964
- if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
1965
- t.pause();
1966
- window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
1967
- return;
1968
- } else {
1969
- setTimeout(function() {
1970
- if (!t.isNativeFullScreen) {
1971
- t.pause();
1972
- window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
1973
- }
1974
- }, 250);
1975
- }
1976
- }
1977
-
1978
- }
1979
-
1980
- // full window code
1981
-
1982
-
1983
-
1984
- // make full size
1985
- t.container
1986
- .addClass('mejs-container-fullscreen')
1987
- .width('100%')
1988
- .height('100%');
1989
- //.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});
1990
-
1991
- // Only needed for safari 5.1 native full screen, can cause display issues elsewhere
1992
- // Actually, it seems to be needed for IE8, too
1993
- //if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
1994
- setTimeout(function() {
1995
- t.container.css({width: '100%', height: '100%'});
1996
- t.setControlsSize();
1997
- }, 500);
1998
- //}
1999
-
2000
- if (t.pluginType === 'native') {
2001
- t.$media
2002
- .width('100%')
2003
- .height('100%');
2004
- } else {
2005
- t.container.find('object, embed, iframe')
2006
- .width('100%')
2007
- .height('100%');
2008
-
2009
- //if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
2010
- t.media.setVideoSize($(window).width(),$(window).height());
2011
- //}
2012
- }
2013
-
2014
- t.layers.children('div')
2015
- .width('100%')
2016
- .height('100%');
2017
-
2018
- if (t.fullscreenBtn) {
2019
- t.fullscreenBtn
2020
- .removeClass('mejs-fullscreen')
2021
- .addClass('mejs-unfullscreen');
2022
- }
2023
-
2024
- t.setControlsSize();
2025
- t.isFullScreen = true;
2026
- },
2027
-
2028
- exitFullScreen: function() {
2029
-
2030
- var t = this;
2031
-
2032
- // firefox can't adjust plugins
2033
- if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
2034
- t.media.setFullscreen(false);
2035
- //player.isFullScreen = false;
2036
- return;
2037
- }
2038
-
2039
- // come outo of native fullscreen
2040
- if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
2041
- mejs.MediaFeatures.cancelFullScreen();
2042
- }
2043
-
2044
- // restore scroll bars to document
2045
- document.documentElement.style.overflow = docStyleOverflow;
2046
-
2047
- t.container
2048
- .removeClass('mejs-container-fullscreen')
2049
- .width(normalWidth)
2050
- .height(normalHeight);
2051
- //.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});
2052
-
2053
- if (t.pluginType === 'native') {
2054
- t.$media
2055
- .width(normalWidth)
2056
- .height(normalHeight);
2057
- } else {
2058
- t.container.find('object embed')
2059
- .width(normalWidth)
2060
- .height(normalHeight);
2061
-
2062
- t.media.setVideoSize(normalWidth, normalHeight);
2063
- }
2064
-
2065
- t.layers.children('div')
2066
- .width(normalWidth)
2067
- .height(normalHeight);
2068
-
2069
- t.fullscreenBtn
2070
- .removeClass('mejs-unfullscreen')
2071
- .addClass('mejs-fullscreen');
2072
-
2073
- t.setControlsSize();
2074
- t.isFullScreen = false;
2075
- }
2076
- });
2077
-
2078
- })(mejs.$);
2106
+ })(mejs.$);
2079
2107
 
2080
2108
  (function($) {
2081
2109
 
@@ -2152,12 +2180,12 @@ if (typeof jQuery != 'undefined') {
2152
2180
  if (!player.options.alwaysShowControls) {
2153
2181
  // move with controls
2154
2182
  player.container
2155
- .bind('mouseenter', function () {
2183
+ .bind('controlsshown', function () {
2156
2184
  // push captions above controls
2157
2185
  player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
2158
2186
 
2159
2187
  })
2160
- .bind('mouseleave', function () {
2188
+ .bind('controlshidden', function () {
2161
2189
  if (!media.paused) {
2162
2190
  // move back to normal place
2163
2191
  player.container.find('.mejs-captions-position').removeClass('mejs-captions-position-hover');
@@ -2243,35 +2271,33 @@ if (typeof jQuery != 'undefined') {
2243
2271
 
2244
2272
  };
2245
2273
 
2246
- if (track.isTranslation) {
2247
-
2248
- // translate the first track
2249
- mejs.TrackFormatParser.translateTrackText(t.tracks[0].entries, t.tracks[0].srclang, track.srclang, t.options.googleApiKey, function(newOne) {
2250
2274
 
2251
- // store the new translation
2252
- track.entries = newOne;
2275
+ $.ajax({
2276
+ url: track.src,
2277
+ dataType: "text",
2278
+ success: function(d) {
2253
2279
 
2280
+ // parse the loaded file
2281
+ if (typeof d == "string" && (/<tt\s+xml/ig).exec(d)) {
2282
+ track.entries = mejs.TrackFormatParser.dfxp.parse(d);
2283
+ } else {
2284
+ track.entries = mejs.TrackFormatParser.webvvt.parse(d);
2285
+ }
2286
+
2254
2287
  after();
2255
- });
2256
-
2257
- } else {
2258
- $.ajax({
2259
- url: track.src,
2260
- success: function(d) {
2261
-
2262
- // parse the loaded file
2263
- track.entries = mejs.TrackFormatParser.parse(d);
2264
- after();
2265
2288
 
2266
- if (track.kind == 'chapters' && t.media.duration > 0) {
2267
- t.drawChapters(track);
2268
- }
2269
- },
2270
- error: function() {
2271
- t.loadNextTrack();
2289
+ if (track.kind == 'chapters') {
2290
+ t.media.addEventListener('play', function(e) {
2291
+ if (t.media.duration > 0) {
2292
+ t.displayChapters(track);
2293
+ }
2294
+ }, false);
2272
2295
  }
2273
- });
2274
- }
2296
+ },
2297
+ error: function() {
2298
+ t.loadNextTrack();
2299
+ }
2300
+ });
2275
2301
  },
2276
2302
 
2277
2303
  enableTrackButton: function(lang, label) {
@@ -2489,53 +2515,106 @@ if (typeof jQuery != 'undefined') {
2489
2515
  Adapted from: http://www.delphiki.com/html5/playr
2490
2516
  */
2491
2517
  mejs.TrackFormatParser = {
2492
- // match start "chapter-" (or anythingelse)
2493
- pattern_identifier: /^([a-zA-z]+-)?[0-9]+$/,
2494
- pattern_timecode: /^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,
2495
-
2496
- split2: function (text, regex) {
2497
- // normal version for compliant browsers
2498
- // see below for IE fix
2499
- return text.split(regex);
2500
- },
2501
- parse: function(trackText) {
2502
- var
2503
- i = 0,
2504
- lines = this.split2(trackText, /\r?\n/),
2505
- entries = {text:[], times:[]},
2506
- timecode,
2507
- text;
2508
-
2509
- for(; i<lines.length; i++) {
2510
- // check for the line number
2511
- if (this.pattern_identifier.exec(lines[i])){
2512
- // skip to the next line where the start --> end time code should be
2513
- i++;
2514
- timecode = this.pattern_timecode.exec(lines[i]);
2515
-
2516
- if (timecode && i<lines.length){
2518
+ webvvt: {
2519
+ // match start "chapter-" (or anythingelse)
2520
+ pattern_identifier: /^([a-zA-z]+-)?[0-9]+$/,
2521
+ pattern_timecode: /^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,
2522
+
2523
+ parse: function(trackText) {
2524
+ var
2525
+ i = 0,
2526
+ lines = mejs.TrackFormatParser.split2(trackText, /\r?\n/),
2527
+ entries = {text:[], times:[]},
2528
+ timecode,
2529
+ text;
2530
+ for(; i<lines.length; i++) {
2531
+ // check for the line number
2532
+ if (this.pattern_identifier.exec(lines[i])){
2533
+ // skip to the next line where the start --> end time code should be
2517
2534
  i++;
2518
- // grab all the (possibly multi-line) text that follows
2519
- text = lines[i];
2520
- i++;
2521
- while(lines[i] !== '' && i<lines.length){
2522
- text = text + '\n' + lines[i];
2535
+ timecode = this.pattern_timecode.exec(lines[i]);
2536
+
2537
+ if (timecode && i<lines.length){
2523
2538
  i++;
2539
+ // grab all the (possibly multi-line) text that follows
2540
+ text = lines[i];
2541
+ i++;
2542
+ while(lines[i] !== '' && i<lines.length){
2543
+ text = text + '\n' + lines[i];
2544
+ i++;
2545
+ }
2546
+ text = $.trim(text).replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, "<a href='$1' target='_blank'>$1</a>");
2547
+ // Text is in a different array so I can use .join
2548
+ entries.text.push(text);
2549
+ entries.times.push(
2550
+ {
2551
+ start: (mejs.Utility.convertSMPTEtoSeconds(timecode[1]) == 0) ? 0.200 : mejs.Utility.convertSMPTEtoSeconds(timecode[1]),
2552
+ stop: mejs.Utility.convertSMPTEtoSeconds(timecode[3]),
2553
+ settings: timecode[5]
2554
+ });
2524
2555
  }
2525
-
2526
- // Text is in a different array so I can use .join
2527
- entries.text.push(text);
2528
- entries.times.push(
2529
- {
2530
- start: mejs.Utility.timeCodeToSeconds(timecode[1]),
2531
- stop: mejs.Utility.timeCodeToSeconds(timecode[3]),
2532
- settings: timecode[5]
2533
- });
2534
2556
  }
2535
2557
  }
2558
+ return entries;
2536
2559
  }
2560
+ },
2561
+ // Thanks to Justin Capella: https://github.com/johndyer/mediaelement/pull/420
2562
+ dfxp: {
2563
+ parse: function(trackText) {
2564
+ trackText = $(trackText).filter("tt");
2565
+ var
2566
+ i = 0,
2567
+ container = trackText.children("div").eq(0),
2568
+ lines = container.find("p"),
2569
+ styleNode = trackText.find("#" + container.attr("style")),
2570
+ styles,
2571
+ begin,
2572
+ end,
2573
+ text,
2574
+ entries = {text:[], times:[]};
2575
+
2576
+
2577
+ if (styleNode.length) {
2578
+ var attributes = styleNode.removeAttr("id").get(0).attributes;
2579
+ if (attributes.length) {
2580
+ styles = {};
2581
+ for (i = 0; i < attributes.length; i++) {
2582
+ styles[attributes[i].name.split(":")[1]] = attributes[i].value;
2583
+ }
2584
+ }
2585
+ }
2537
2586
 
2538
- return entries;
2587
+ for(i = 0; i<lines.length; i++) {
2588
+ var style;
2589
+ var _temp_times = {
2590
+ start: null,
2591
+ stop: null,
2592
+ style: null
2593
+ };
2594
+ if (lines.eq(i).attr("begin")) _temp_times.start = mejs.Utility.convertSMPTEtoSeconds(lines.eq(i).attr("begin"));
2595
+ if (!_temp_times.start && lines.eq(i-1).attr("end")) _temp_times.start = mejs.Utility.convertSMPTEtoSeconds(lines.eq(i-1).attr("end"));
2596
+ if (lines.eq(i).attr("end")) _temp_times.stop = mejs.Utility.convertSMPTEtoSeconds(lines.eq(i).attr("end"));
2597
+ if (!_temp_times.stop && lines.eq(i+1).attr("begin")) _temp_times.stop = mejs.Utility.convertSMPTEtoSeconds(lines.eq(i+1).attr("begin"));
2598
+ if (styles) {
2599
+ style = "";
2600
+ for (var _style in styles) {
2601
+ style += _style + ":" + styles[_style] + ";";
2602
+ }
2603
+ }
2604
+ if (style) _temp_times.style = style;
2605
+ if (_temp_times.start == 0) _temp_times.start = 0.200;
2606
+ entries.times.push(_temp_times);
2607
+ text = $.trim(lines.eq(i).html()).replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, "<a href='$1' target='_blank'>$1</a>");
2608
+ entries.text.push(text);
2609
+ if (entries.times.start == 0) entries.times.start = 2;
2610
+ }
2611
+ return entries;
2612
+ }
2613
+ },
2614
+ split2: function (text, regex) {
2615
+ // normal version for compliant browsers
2616
+ // see below for IE fix
2617
+ return text.split(regex);
2539
2618
  }
2540
2619
  };
2541
2620
 
@@ -2562,196 +2641,231 @@ if (typeof jQuery != 'undefined') {
2562
2641
 
2563
2642
  })(mejs.$);
2564
2643
 
2565
- /*
2566
- * ContextMenu Plugin
2567
- *
2568
- *
2569
- */
2570
-
2571
- (function($) {
2572
-
2573
- $.extend(mejs.MepDefaults,
2574
- { 'contextMenuItems': [
2575
- // demo of a fullscreen option
2576
- {
2577
- render: function(player) {
2578
-
2579
- // check for fullscreen plugin
2580
- if (typeof player.enterFullScreen == 'undefined')
2581
- return null;
2582
-
2583
- if (player.isFullScreen) {
2584
- return "Turn off Fullscreen";
2585
- } else {
2586
- return "Go Fullscreen";
2587
- }
2588
- },
2589
- click: function(player) {
2590
- if (player.isFullScreen) {
2591
- player.exitFullScreen();
2592
- } else {
2593
- player.enterFullScreen();
2594
- }
2595
- }
2596
- }
2597
- ,
2598
- // demo of a mute/unmute button
2599
- {
2600
- render: function(player) {
2601
- if (player.media.muted) {
2602
- return "Unmute";
2603
- } else {
2604
- return "Mute";
2605
- }
2606
- },
2607
- click: function(player) {
2608
- if (player.media.muted) {
2609
- player.setMuted(false);
2610
- } else {
2611
- player.setMuted(true);
2612
- }
2613
- }
2614
- },
2615
- // separator
2616
- {
2617
- isSeparator: true
2618
- }
2619
- ,
2620
- // demo of simple download video
2621
- {
2622
- render: function(player) {
2623
- return "Download Video";
2624
- },
2625
- click: function(player) {
2626
- window.location.href = player.media.currentSrc;
2627
- }
2628
- }
2629
- ]}
2630
- );
2631
-
2632
-
2633
- $.extend(MediaElementPlayer.prototype, {
2634
- buildcontextmenu: function(player, controls, layers, media) {
2635
-
2636
- // create context menu
2637
- player.contextMenu = $('<div class="mejs-contextmenu"></div>')
2638
- .appendTo($('body'))
2639
- .hide();
2640
-
2641
- // create events for showing context menu
2642
- player.container.bind('contextmenu', function(e) {
2643
- if (player.isContextMenuEnabled) {
2644
- e.preventDefault();
2645
- player.renderContextMenu(e.clientX-1, e.clientY-1);
2646
- return false;
2647
- }
2648
- });
2649
- player.container.bind('click', function() {
2650
- player.contextMenu.hide();
2651
- });
2652
- player.contextMenu.bind('mouseleave', function() {
2653
-
2654
- //console.log('context hover out');
2655
- player.startContextMenuTimer();
2656
-
2657
- });
2658
- },
2659
-
2660
- isContextMenuEnabled: true,
2661
- enableContextMenu: function() {
2662
- this.isContextMenuEnabled = true;
2663
- },
2664
- disableContextMenu: function() {
2665
- this.isContextMenuEnabled = false;
2666
- },
2667
-
2668
- contextMenuTimeout: null,
2669
- startContextMenuTimer: function() {
2670
- //console.log('startContextMenuTimer');
2671
-
2672
- var t = this;
2673
-
2674
- t.killContextMenuTimer();
2675
-
2676
- t.contextMenuTimer = setTimeout(function() {
2677
- t.hideContextMenu();
2678
- t.killContextMenuTimer();
2679
- }, 750);
2680
- },
2681
- killContextMenuTimer: function() {
2682
- var timer = this.contextMenuTimer;
2683
-
2684
- //console.log('killContextMenuTimer', timer);
2685
-
2686
- if (timer != null) {
2687
- clearTimeout(timer);
2688
- delete timer;
2689
- timer = null;
2690
- }
2691
- },
2692
-
2693
- hideContextMenu: function() {
2694
- this.contextMenu.hide();
2695
- },
2696
-
2697
- renderContextMenu: function(x,y) {
2698
-
2699
- // alway re-render the items so that things like "turn fullscreen on" and "turn fullscreen off" are always written correctly
2700
- var t = this,
2701
- html = '',
2702
- items = t.options.contextMenuItems;
2703
-
2704
- for (var i=0, il=items.length; i<il; i++) {
2705
-
2706
- if (items[i].isSeparator) {
2707
- html += '<div class="mejs-contextmenu-separator"></div>';
2708
- } else {
2709
-
2710
- var rendered = items[i].render(t);
2711
-
2712
- // render can return null if the item doesn't need to be used at the moment
2713
- if (rendered != null) {
2714
- html += '<div class="mejs-contextmenu-item" data-itemindex="' + i + '" id="element-' + (Math.random()*1000000) + '">' + rendered + '</div>';
2715
- }
2716
- }
2717
- }
2718
-
2719
- // position and show the context menu
2720
- t.contextMenu
2721
- .empty()
2722
- .append($(html))
2723
- .css({top:y, left:x})
2724
- .show();
2725
-
2726
- // bind events
2727
- t.contextMenu.find('.mejs-contextmenu-item').each(function() {
2728
-
2729
- // which one is this?
2730
- var $dom = $(this),
2731
- itemIndex = parseInt( $dom.data('itemindex'), 10 ),
2732
- item = t.options.contextMenuItems[itemIndex];
2733
-
2734
- // bind extra functionality?
2735
- if (typeof item.show != 'undefined')
2736
- item.show( $dom , t);
2737
-
2738
- // bind click action
2739
- $dom.click(function() {
2740
- // perform click action
2741
- if (typeof item.click != 'undefined')
2742
- item.click(t);
2743
-
2744
- // close
2745
- t.contextMenu.hide();
2746
- });
2747
- });
2748
-
2749
- // stop the controls from hiding
2750
- setTimeout(function() {
2751
- t.killControlsTimer('rev3');
2752
- }, 100);
2753
-
2754
- }
2755
- });
2756
-
2644
+ /*
2645
+ * ContextMenu Plugin
2646
+ *
2647
+ *
2648
+ */
2649
+
2650
+ (function($) {
2651
+
2652
+ $.extend(mejs.MepDefaults,
2653
+ { 'contextMenuItems': [
2654
+ // demo of a fullscreen option
2655
+ {
2656
+ render: function(player) {
2657
+
2658
+ // check for fullscreen plugin
2659
+ if (typeof player.enterFullScreen == 'undefined')
2660
+ return null;
2661
+
2662
+ if (player.isFullScreen) {
2663
+ return "Turn off Fullscreen";
2664
+ } else {
2665
+ return "Go Fullscreen";
2666
+ }
2667
+ },
2668
+ click: function(player) {
2669
+ if (player.isFullScreen) {
2670
+ player.exitFullScreen();
2671
+ } else {
2672
+ player.enterFullScreen();
2673
+ }
2674
+ }
2675
+ }
2676
+ ,
2677
+ // demo of a mute/unmute button
2678
+ {
2679
+ render: function(player) {
2680
+ if (player.media.muted) {
2681
+ return "Unmute";
2682
+ } else {
2683
+ return "Mute";
2684
+ }
2685
+ },
2686
+ click: function(player) {
2687
+ if (player.media.muted) {
2688
+ player.setMuted(false);
2689
+ } else {
2690
+ player.setMuted(true);
2691
+ }
2692
+ }
2693
+ },
2694
+ // separator
2695
+ {
2696
+ isSeparator: true
2697
+ }
2698
+ ,
2699
+ // demo of simple download video
2700
+ {
2701
+ render: function(player) {
2702
+ return "Download Video";
2703
+ },
2704
+ click: function(player) {
2705
+ window.location.href = player.media.currentSrc;
2706
+ }
2707
+ }
2708
+ ]}
2709
+ );
2710
+
2711
+
2712
+ $.extend(MediaElementPlayer.prototype, {
2713
+ buildcontextmenu: function(player, controls, layers, media) {
2714
+
2715
+ // create context menu
2716
+ player.contextMenu = $('<div class="mejs-contextmenu"></div>')
2717
+ .appendTo($('body'))
2718
+ .hide();
2719
+
2720
+ // create events for showing context menu
2721
+ player.container.bind('contextmenu', function(e) {
2722
+ if (player.isContextMenuEnabled) {
2723
+ e.preventDefault();
2724
+ player.renderContextMenu(e.clientX-1, e.clientY-1);
2725
+ return false;
2726
+ }
2727
+ });
2728
+ player.container.bind('click', function() {
2729
+ player.contextMenu.hide();
2730
+ });
2731
+ player.contextMenu.bind('mouseleave', function() {
2732
+
2733
+ //console.log('context hover out');
2734
+ player.startContextMenuTimer();
2735
+
2736
+ });
2737
+ },
2738
+
2739
+ isContextMenuEnabled: true,
2740
+ enableContextMenu: function() {
2741
+ this.isContextMenuEnabled = true;
2742
+ },
2743
+ disableContextMenu: function() {
2744
+ this.isContextMenuEnabled = false;
2745
+ },
2746
+
2747
+ contextMenuTimeout: null,
2748
+ startContextMenuTimer: function() {
2749
+ //console.log('startContextMenuTimer');
2750
+
2751
+ var t = this;
2752
+
2753
+ t.killContextMenuTimer();
2754
+
2755
+ t.contextMenuTimer = setTimeout(function() {
2756
+ t.hideContextMenu();
2757
+ t.killContextMenuTimer();
2758
+ }, 750);
2759
+ },
2760
+ killContextMenuTimer: function() {
2761
+ var timer = this.contextMenuTimer;
2762
+
2763
+ //console.log('killContextMenuTimer', timer);
2764
+
2765
+ if (timer != null) {
2766
+ clearTimeout(timer);
2767
+ delete timer;
2768
+ timer = null;
2769
+ }
2770
+ },
2771
+
2772
+ hideContextMenu: function() {
2773
+ this.contextMenu.hide();
2774
+ },
2775
+
2776
+ renderContextMenu: function(x,y) {
2777
+
2778
+ // alway re-render the items so that things like "turn fullscreen on" and "turn fullscreen off" are always written correctly
2779
+ var t = this,
2780
+ html = '',
2781
+ items = t.options.contextMenuItems;
2782
+
2783
+ for (var i=0, il=items.length; i<il; i++) {
2784
+
2785
+ if (items[i].isSeparator) {
2786
+ html += '<div class="mejs-contextmenu-separator"></div>';
2787
+ } else {
2788
+
2789
+ var rendered = items[i].render(t);
2790
+
2791
+ // render can return null if the item doesn't need to be used at the moment
2792
+ if (rendered != null) {
2793
+ html += '<div class="mejs-contextmenu-item" data-itemindex="' + i + '" id="element-' + (Math.random()*1000000) + '">' + rendered + '</div>';
2794
+ }
2795
+ }
2796
+ }
2797
+
2798
+ // position and show the context menu
2799
+ t.contextMenu
2800
+ .empty()
2801
+ .append($(html))
2802
+ .css({top:y, left:x})
2803
+ .show();
2804
+
2805
+ // bind events
2806
+ t.contextMenu.find('.mejs-contextmenu-item').each(function() {
2807
+
2808
+ // which one is this?
2809
+ var $dom = $(this),
2810
+ itemIndex = parseInt( $dom.data('itemindex'), 10 ),
2811
+ item = t.options.contextMenuItems[itemIndex];
2812
+
2813
+ // bind extra functionality?
2814
+ if (typeof item.show != 'undefined')
2815
+ item.show( $dom , t);
2816
+
2817
+ // bind click action
2818
+ $dom.click(function() {
2819
+ // perform click action
2820
+ if (typeof item.click != 'undefined')
2821
+ item.click(t);
2822
+
2823
+ // close
2824
+ t.contextMenu.hide();
2825
+ });
2826
+ });
2827
+
2828
+ // stop the controls from hiding
2829
+ setTimeout(function() {
2830
+ t.killControlsTimer('rev3');
2831
+ }, 100);
2832
+
2833
+ }
2834
+ });
2835
+
2836
+ })(mejs.$);
2837
+ /**
2838
+ * Postroll plugin
2839
+ */
2840
+ (function($) {
2841
+
2842
+ $.extend(mejs.MepDefaults, {
2843
+ postrollCloseText: mejs.i18n.t('Close')
2844
+ });
2845
+
2846
+ // Postroll
2847
+ $.extend(MediaElementPlayer.prototype, {
2848
+ buildpostroll: function(player, controls, layers, media) {
2849
+ var
2850
+ t = this,
2851
+ postrollLink = t.container.find('link[rel="postroll"]').attr('href');
2852
+
2853
+ if (typeof postrollLink !== 'undefined') {
2854
+ player.postroll =
2855
+ $('<div class="mejs-postroll-layer mejs-layer"><a class="mejs-postroll-close" onclick="$(this).parent().hide();return false;">' + t.options.postrollCloseText + '</a><div class="mejs-postroll-layer-content"></div></div>').prependTo(layers).hide();
2856
+
2857
+ t.media.addEventListener('ended', function (e) {
2858
+ $.ajax({
2859
+ dataType: 'html',
2860
+ url: postrollLink,
2861
+ success: function (data, textStatus) {
2862
+ layers.find('.mejs-postroll-layer-content').html(data);
2863
+ }
2864
+ });
2865
+ player.postroll.show();
2866
+ }, false);
2867
+ }
2868
+ }
2869
+ });
2870
+
2757
2871
  })(mejs.$);