mediaelement_rails 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,7 +15,7 @@
15
15
  var mejs = mejs || {};
16
16
 
17
17
  // version number
18
- mejs.version = '2.10.3';
18
+ mejs.version = '2.11.0';
19
19
 
20
20
  // player number (for missing, same id attr)
21
21
  mejs.meIndex = 0;
@@ -30,13 +30,14 @@ mejs.plugins = {
30
30
  //,{version: [12,0], types: ['video/webm']} // for future reference (hopefully!)
31
31
  ],
32
32
  youtube: [
33
- {version: null, types: ['video/youtube', 'video/x-youtube']}
33
+ {version: null, types: ['video/youtube', 'video/x-youtube', 'audio/youtube', 'audio/x-youtube']}
34
34
  ],
35
35
  vimeo: [
36
36
  {version: null, types: ['video/vimeo', 'video/x-vimeo']}
37
37
  ]
38
38
  };
39
39
 
40
+
40
41
  /*
41
42
  Utility methods
42
43
  */
@@ -148,7 +149,7 @@ mejs.Utility = {
148
149
  /* borrowed from SWFObject: http://code.google.com/p/swfobject/source/browse/trunk/swfobject/src/swfobject.js#474 */
149
150
  removeSwf: function(id) {
150
151
  var obj = document.getElementById(id);
151
- if (obj && obj.nodeName == "OBJECT") {
152
+ if (obj && /object|embed/i.test(obj.nodeName)) {
152
153
  if (mejs.MediaFeatures.isIE) {
153
154
  obj.style.display = "none";
154
155
  (function(){
@@ -532,13 +533,13 @@ mejs.PluginMediaElement.prototype = {
532
533
  for (j=0; j<pluginInfo.types.length; j++) {
533
534
  // find plugin that can play the type
534
535
  if (type == pluginInfo.types[j]) {
535
- return true;
536
+ return 'probably';
536
537
  }
537
538
  }
538
539
  }
539
540
  }
540
541
 
541
- return false;
542
+ return '';
542
543
  },
543
544
 
544
545
  positionFullscreenButton: function(x,y,visibleAndAbove) {
@@ -701,6 +702,7 @@ mejs.PluginMediaElement.prototype = {
701
702
 
702
703
  remove: function() {
703
704
  mejs.Utility.removeSwf(this.pluginElement.id);
705
+ mejs.MediaPluginBridge.unregisterPluginElement(this.pluginElement.id);
704
706
  }
705
707
  };
706
708
 
@@ -715,6 +717,11 @@ mejs.MediaPluginBridge = {
715
717
  this.htmlMediaElements[id] = htmlMediaElement;
716
718
  },
717
719
 
720
+ unregisterPluginElement: function (id) {
721
+ delete this.pluginMediaElements[id];
722
+ delete this.htmlMediaElements[id];
723
+ },
724
+
718
725
  // when Flash/Silverlight is ready, it calls out to this method
719
726
  initPlugin: function (id) {
720
727
 
@@ -1210,7 +1217,7 @@ mejs.HtmlMediaElementShim = {
1210
1217
  switch (playback.method) {
1211
1218
  case 'silverlight':
1212
1219
  container.innerHTML =
1213
- '<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '">' +
1220
+ '<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '" class="mejs-shim">' +
1214
1221
  '<param name="initParams" value="' + initVars.join(',') + '" />' +
1215
1222
  '<param name="windowless" value="true" />' +
1216
1223
  '<param name="background" value="black" />' +
@@ -1227,7 +1234,7 @@ mejs.HtmlMediaElementShim = {
1227
1234
  container.appendChild(specialIEContainer);
1228
1235
  specialIEContainer.outerHTML =
1229
1236
  '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
1230
- 'id="' + pluginid + '" width="' + width + '" height="' + height + '">' +
1237
+ 'id="' + pluginid + '" width="' + width + '" height="' + height + '" class="mejs-shim">' +
1231
1238
  '<param name="movie" value="' + options.pluginPath + options.flashName + '?x=' + (new Date()) + '" />' +
1232
1239
  '<param name="flashvars" value="' + initVars.join('&amp;') + '" />' +
1233
1240
  '<param name="quality" value="high" />' +
@@ -1252,7 +1259,8 @@ mejs.HtmlMediaElementShim = {
1252
1259
  'src="' + options.pluginPath + options.flashName + '" ' +
1253
1260
  'flashvars="' + initVars.join('&') + '" ' +
1254
1261
  'width="' + width + '" ' +
1255
- 'height="' + height + '"></embed>';
1262
+ 'height="' + height + '" ' +
1263
+ 'class="mejs-shim"></embed>';
1256
1264
  }
1257
1265
  break;
1258
1266
 
@@ -1285,16 +1293,16 @@ mejs.HtmlMediaElementShim = {
1285
1293
 
1286
1294
  pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/')+1);
1287
1295
 
1288
- container.innerHTML ='<iframe src="http://player.vimeo.com/video/' + pluginMediaElement.vimeoid + '?portrait=0&byline=0&title=0" width="' + width +'" height="' + height +'" frameborder="0"></iframe>';
1296
+ container.innerHTML ='<iframe src="http://player.vimeo.com/video/' + pluginMediaElement.vimeoid + '?portrait=0&byline=0&title=0" width="' + width +'" height="' + height +'" frameborder="0" class="mejs-shim"></iframe>';
1289
1297
 
1290
1298
  /*
1291
1299
  container.innerHTML =
1292
- '<object width="' + width + '" height="' + height + '">' +
1300
+ '<object width="' + width + '" height="' + height + '" class="mejs-shim">' +
1293
1301
  '<param name="allowfullscreen" value="true" />' +
1294
1302
  '<param name="allowscriptaccess" value="always" />' +
1295
1303
  '<param name="flashvars" value="api=1" />' +
1296
1304
  '<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=' + pluginMediaElement.vimeoid + '&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" />' +
1297
- '<embed src="//vimeo.com/moogaloop.swf?api=1&amp;clip_id=' + pluginMediaElement.vimeoid + '&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="' + width + '" height="' + height + '"></embed>' +
1305
+ '<embed src="//vimeo.com/moogaloop.swf?api=1&amp;clip_id=' + pluginMediaElement.vimeoid + '&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="' + width + '" height="' + height + '" class="mejs-shim"></embed>' +
1298
1306
  '</object>';
1299
1307
  */
1300
1308
 
@@ -1478,7 +1486,7 @@ mejs.YouTubeApi = {
1478
1486
  /*
1479
1487
  settings.container.innerHTML =
1480
1488
  '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="//www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0" ' +
1481
- 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' +
1489
+ 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; " class="mejs-shim">' +
1482
1490
  '<param name="allowScriptAccess" value="always">' +
1483
1491
  '<param name="wmode" value="transparent">' +
1484
1492
  '</object>';
@@ -1492,7 +1500,7 @@ mejs.YouTubeApi = {
1492
1500
  specialIEContainer = document.createElement('div');
1493
1501
  settings.container.appendChild(specialIEContainer);
1494
1502
  specialIEContainer.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
1495
- 'id="' + settings.pluginId + '" width="' + settings.width + '" height="' + settings.height + '">' +
1503
+ 'id="' + settings.pluginId + '" width="' + settings.width + '" height="' + settings.height + '" class="mejs-shim">' +
1496
1504
  '<param name="movie" value="' + youtubeUrl + '" />' +
1497
1505
  '<param name="wmode" value="transparent" />' +
1498
1506
  '<param name="allowScriptAccess" value="always" />' +
@@ -1501,7 +1509,7 @@ mejs.YouTubeApi = {
1501
1509
  } else {
1502
1510
  settings.container.innerHTML =
1503
1511
  '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + youtubeUrl + '" ' +
1504
- 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' +
1512
+ 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; " class="mejs-shim">' +
1505
1513
  '<param name="allowScriptAccess" value="always">' +
1506
1514
  '<param name="wmode" value="transparent">' +
1507
1515
  '</object>';
@@ -66,6 +66,8 @@ if (typeof jQuery != 'undefined') {
66
66
  autosizeProgress : true,
67
67
  // Hide controls when playing and mouse is not over the video
68
68
  alwaysShowControls: false,
69
+ // Display the video control
70
+ hideVideoControlsOnLoad: false,
69
71
  // Enable click video element to toggle play/pause
70
72
  clickToPlayPause: true,
71
73
  // force iPad's native controls
@@ -167,7 +169,7 @@ if (typeof jQuery != 'undefined') {
167
169
 
168
170
  mejs.mepIndex = 0;
169
171
 
170
- mejs.players = [];
172
+ mejs.players = {};
171
173
 
172
174
  // wraps a MediaElement object in player controls
173
175
  mejs.MediaElementPlayer = function(node, o) {
@@ -199,8 +201,11 @@ if (typeof jQuery != 'undefined') {
199
201
  // extend default options
200
202
  t.options = $.extend({},mejs.MepDefaults,o);
201
203
 
204
+ // unique ID
205
+ t.id = 'mep_' + mejs.mepIndex++;
206
+
202
207
  // add to player array (for focus events)
203
- mejs.players.push(t);
208
+ mejs.players[t.id] = t;
204
209
 
205
210
  // start up
206
211
  t.init();
@@ -252,7 +257,7 @@ if (typeof jQuery != 'undefined') {
252
257
  t.media.play();
253
258
  }
254
259
 
255
- } else if (mf.isAndroid && t.AndroidUseNativeControls) {
260
+ } else if (mf.isAndroid && t.options.AndroidUseNativeControls) {
256
261
 
257
262
  // leave default player
258
263
 
@@ -263,9 +268,6 @@ if (typeof jQuery != 'undefined') {
263
268
  // remove native controls
264
269
  t.$media.removeAttr('controls');
265
270
 
266
- // unique ID
267
- t.id = 'mep_' + mejs.mepIndex++;
268
-
269
271
  // build container
270
272
  t.container =
271
273
  $('<div id="' + t.id + '" class="mejs-container ' + (mejs.MediaFeatures.svg ? 'svg' : 'no-svg') + '">'+
@@ -604,7 +606,11 @@ if (typeof jQuery != 'undefined') {
604
606
  }
605
607
  });
606
608
  }
607
-
609
+
610
+ if(t.options.hideVideoControlsOnLoad) {
611
+ t.hideControls(false);
612
+ }
613
+
608
614
  // check for autoplay
609
615
  if (autoplay && !t.options.alwaysShowControls) {
610
616
  t.hideControls();
@@ -628,10 +634,11 @@ if (typeof jQuery != 'undefined') {
628
634
 
629
635
  // FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)
630
636
  media.addEventListener('play', function() {
637
+ var playerIndex;
631
638
 
632
639
  // go through all other players
633
- for (var i=0, il=mejs.players.length; i<il; i++) {
634
- var p = mejs.players[i];
640
+ for (playerIndex in mejs.players) {
641
+ var p = mejs.players[playerIndex];
635
642
  if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
636
643
  p.pause();
637
644
  }
@@ -688,7 +695,7 @@ if (typeof jQuery != 'undefined') {
688
695
  }, 50);
689
696
 
690
697
  // adjust controls whenever window sizes (used to be in fullscreen only)
691
- $(window).resize(function() {
698
+ t.globalBind('resize', function() {
692
699
 
693
700
  // don't resize for fullscreen mode
694
701
  if ( !(t.isFullScreen || (mejs.MediaFeatures.hasTrueNativeFullScreen && document.webkitIsFullScreen)) ) {
@@ -762,17 +769,12 @@ if (typeof jQuery != 'undefined') {
762
769
  t.container
763
770
  .width(parentWidth)
764
771
  .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')
772
+
773
+ // set native <video> or <audio> and shims
774
+ t.$media.add(t.container.find('.mejs-shim'))
773
775
  .width('100%')
774
776
  .height('100%');
775
-
777
+
776
778
  // if shim is ready, send the size to the embeded plugin
777
779
  if (t.isVideo) {
778
780
  if (t.media.setVideoSize) {
@@ -823,7 +825,8 @@ if (typeof jQuery != 'undefined') {
823
825
 
824
826
  // find the size of all the other controls besides the rail
825
827
  others.each(function() {
826
- if ($(this).css('position') != 'absolute') {
828
+ var $this = $(this);
829
+ if ($this.css('position') != 'absolute' && $this.is(':visible')) {
827
830
  usedWidth += $(this).outerWidth(true);
828
831
  }
829
832
  });
@@ -988,7 +991,7 @@ if (typeof jQuery != 'undefined') {
988
991
  var t = this;
989
992
 
990
993
  // listen for key presses
991
- $(document).keydown(function(e) {
994
+ t.globalBind('keydown', function(e) {
992
995
 
993
996
  if (player.hasFocus && player.options.enableKeyboard) {
994
997
 
@@ -1010,7 +1013,7 @@ if (typeof jQuery != 'undefined') {
1010
1013
  });
1011
1014
 
1012
1015
  // check if someone clicked outside a player region, then kill its focus
1013
- $(document).click(function(event) {
1016
+ t.globalBind('click', function(event) {
1014
1017
  if ($(event.target).closest('.mejs-container').length == 0) {
1015
1018
  player.hasFocus = false;
1016
1019
  }
@@ -1029,7 +1032,7 @@ if (typeof jQuery != 'undefined') {
1029
1032
  track = $(track);
1030
1033
 
1031
1034
  t.tracks.push({
1032
- srclang: track.attr('srclang').toLowerCase(),
1035
+ srclang: (track.attr('srclang')) ? track.attr('srclang').toLowerCase() : '',
1033
1036
  src: track.attr('src'),
1034
1037
  kind: track.attr('kind'),
1035
1038
  label: track.attr('label') || '',
@@ -1071,29 +1074,98 @@ if (typeof jQuery != 'undefined') {
1071
1074
  this.media.setSrc(src);
1072
1075
  },
1073
1076
  remove: function() {
1074
- var t = this;
1077
+ var t = this, featureIndex, feature;
1075
1078
 
1076
- if (t.media.pluginType === 'flash') {
1077
- t.media.remove();
1078
- } else if (t.media.pluginType === 'native') {
1079
+ // invoke features cleanup
1080
+ for (featureIndex in t.options.features) {
1081
+ feature = t.options.features[featureIndex];
1082
+ if (t['clean' + feature]) {
1083
+ try {
1084
+ t['clean' + feature](t);
1085
+ } catch (e) {
1086
+ // TODO: report control error
1087
+ //throw e;
1088
+ //console.log('error building ' + feature);
1089
+ //console.log(e);
1090
+ }
1091
+ }
1092
+ }
1093
+
1094
+ if (t.media.pluginType === 'native') {
1079
1095
  t.$media.prop('controls', true);
1096
+ } else {
1097
+ t.media.remove();
1080
1098
  }
1081
1099
 
1082
1100
  // grab video and put it back in place
1083
1101
  if (!t.isDynamic) {
1084
- t.$node.insertBefore(t.container)
1102
+ if (t.media.pluginType === 'native') {
1103
+ // detach events from the video
1104
+ // TODO: detach event listeners better than this;
1105
+ // also detach ONLY the events attached by this plugin!
1106
+ //t.$node.clone().insertBefore(t.container);
1107
+ //t.$node.remove();
1108
+ }
1109
+ /*else*/ t.$node.insertBefore(t.container)
1085
1110
  }
1111
+
1112
+ // Remove the player from the mejs.players array so that pauseOtherPlayers doesn't blow up when trying to pause a non existance flash api.
1113
+ mejs.players.splice( $.inArray( t, mejs.players ), 1);
1086
1114
 
1087
1115
  t.container.remove();
1116
+ t.globalUnbind();
1117
+ delete t.node.player;
1118
+ delete mejs.players[t.id];
1088
1119
  }
1089
1120
  };
1090
1121
 
1122
+ (function(){
1123
+ var rwindow = /^((after|before)print|(before)?unload|hashchange|message|o(ff|n)line|page(hide|show)|popstate|resize|storage)\b/;
1124
+
1125
+ function splitEvents(events, id) {
1126
+ // add player ID as an event namespace so it's easier to unbind them all later
1127
+ var ret = {d: [], w: []};
1128
+ $.each((events || '').split(' '), function(k, v){
1129
+ ret[rwindow.test(v) ? 'w' : 'd'].push(v + '.' + id);
1130
+ });
1131
+ ret.d = ret.d.join(' ');
1132
+ ret.w = ret.w.join(' ');
1133
+ return ret;
1134
+ }
1135
+
1136
+ mejs.MediaElementPlayer.prototype.globalBind = function(events, data, callback) {
1137
+ var t = this;
1138
+ events = splitEvents(events, t.id);
1139
+ if (events.d) $(document).bind(events.d, data, callback);
1140
+ if (events.w) $(window).bind(events.w, data, callback);
1141
+ };
1142
+
1143
+ mejs.MediaElementPlayer.prototype.globalUnbind = function(events, callback) {
1144
+ var t = this;
1145
+ events = splitEvents(events, t.id);
1146
+ if (events.d) $(document).unbind(events.d, callback);
1147
+ if (events.w) $(window).unbind(events.w, callback);
1148
+ };
1149
+ })();
1150
+
1091
1151
  // turn into jQuery plugin
1092
1152
  if (typeof jQuery != 'undefined') {
1093
1153
  jQuery.fn.mediaelementplayer = function (options) {
1094
- return this.each(function () {
1095
- new mejs.MediaElementPlayer(this, options);
1096
- });
1154
+ if (options === false) {
1155
+ this.each(function () {
1156
+ var player = jQuery(this).data('mediaelementplayer');
1157
+ if (player) {
1158
+ player.remove();
1159
+ }
1160
+ jQuery(this).removeData('mediaelementplayer');
1161
+ });
1162
+ }
1163
+ else {
1164
+ this.each(function () {
1165
+ jQuery(this).data('mediaelementplayer', new mejs.MediaElementPlayer(this, options));
1166
+ });
1167
+ }
1168
+ return this;
1097
1169
  };
1098
1170
  }
1099
1171
 
@@ -1259,21 +1331,20 @@ if (typeof jQuery != 'undefined') {
1259
1331
  if (e.which === 1) {
1260
1332
  mouseIsDown = true;
1261
1333
  handleMouseMove(e);
1262
- $(document)
1263
- .bind('mousemove.dur', function(e) {
1264
- handleMouseMove(e);
1265
- })
1266
- .bind('mouseup.dur', function (e) {
1267
- mouseIsDown = false;
1268
- timefloat.hide();
1269
- $(document).unbind('.dur');
1270
- });
1334
+ t.globalBind('mousemove.dur', function(e) {
1335
+ handleMouseMove(e);
1336
+ });
1337
+ t.globalBind('mouseup.dur', function (e) {
1338
+ mouseIsDown = false;
1339
+ timefloat.hide();
1340
+ t.globalUnbind('.dur');
1341
+ });
1271
1342
  return false;
1272
1343
  }
1273
1344
  })
1274
1345
  .bind('mouseenter', function(e) {
1275
1346
  mouseIsOver = true;
1276
- $(document).bind('mousemove.dur', function(e) {
1347
+ t.globalBind('mousemove.dur', function(e) {
1277
1348
  handleMouseMove(e);
1278
1349
  });
1279
1350
  if (!mejs.MediaFeatures.hasTouch) {
@@ -1283,7 +1354,7 @@ if (typeof jQuery != 'undefined') {
1283
1354
  .bind('mouseleave',function(e) {
1284
1355
  mouseIsOver = false;
1285
1356
  if (!mouseIsDown) {
1286
- $(document).unbind('.dur');
1357
+ t.globalUnbind('.dur');
1287
1358
  timefloat.hide();
1288
1359
  }
1289
1360
  });
@@ -1349,8 +1420,8 @@ if (typeof jQuery != 'undefined') {
1349
1420
  // update bar and handle
1350
1421
  if (t.total && t.handle) {
1351
1422
  var
1352
- newWidth = t.total.width() * t.media.currentTime / t.media.duration,
1353
- handlePos = newWidth - (t.handle.outerWidth(true) / 2);
1423
+ newWidth = Math.round(t.total.width() * t.media.currentTime / t.media.duration),
1424
+ handlePos = newWidth - Math.round(t.handle.outerWidth(true) / 2);
1354
1425
 
1355
1426
  t.current.width(newWidth);
1356
1427
  t.handle.css('left', handlePos);
@@ -1432,14 +1503,14 @@ if (typeof jQuery != 'undefined') {
1432
1503
  }
1433
1504
  },
1434
1505
 
1435
- updateDuration: function() {
1506
+ updateDuration: function() {
1436
1507
  var t = this;
1437
1508
 
1438
1509
  //Toggle the long video class if the video is longer than an hour.
1439
1510
  t.container.toggleClass("mejs-long-video", t.media.duration > 3600);
1440
1511
 
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));
1512
+ if (t.durationD && (t.options.duration > 0 || t.media.duration)) {
1513
+ t.durationD.html(mejs.Utility.secondsToTimeCode(t.options.duration > 0 ? t.options.duration : t.media.duration, t.options.alwaysShowHours, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
1443
1514
  }
1444
1515
  }
1445
1516
  });
@@ -1617,18 +1688,17 @@ if (typeof jQuery != 'undefined') {
1617
1688
  })
1618
1689
  .bind('mousedown', function (e) {
1619
1690
  handleVolumeMove(e);
1620
- $(document)
1621
- .bind('mousemove.vol', function(e) {
1622
- handleVolumeMove(e);
1623
- })
1624
- .bind('mouseup.vol', function () {
1625
- mouseIsDown = false;
1626
- $(document).unbind('.vol');
1691
+ t.globalBind('mousemove.vol', function(e) {
1692
+ handleVolumeMove(e);
1693
+ });
1694
+ t.globalBind('mouseup.vol', function () {
1695
+ mouseIsDown = false;
1696
+ t.globalUnbind('.vol');
1627
1697
 
1628
- if (!mouseIsOver && mode == 'vertical') {
1629
- volumeSlider.hide();
1630
- }
1631
- });
1698
+ if (!mouseIsOver && mode == 'vertical') {
1699
+ volumeSlider.hide();
1700
+ }
1701
+ });
1632
1702
  mouseIsDown = true;
1633
1703
 
1634
1704
  return false;
@@ -1656,7 +1726,12 @@ if (typeof jQuery != 'undefined') {
1656
1726
  if (t.container.is(':visible')) {
1657
1727
  // set initial volume
1658
1728
  positionVolumeHandle(player.options.startVolume);
1659
-
1729
+
1730
+ // mutes the media and sets the volume icon muted if the initial volume is set to 0
1731
+ if (player.options.startVolume === 0) {
1732
+ media.setMuted(true);
1733
+ }
1734
+
1660
1735
  // shim gets the startvolume as a parameter, but we have to set it on the native <video> and <audio> elements
1661
1736
  if (media.pluginType === 'native') {
1662
1737
  media.setVolume(player.options.startVolume);
@@ -1696,15 +1771,7 @@ if (typeof jQuery != 'undefined') {
1696
1771
  if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
1697
1772
 
1698
1773
  // 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) {
1774
+ var func = function(e) {
1708
1775
 
1709
1776
  if (mejs.MediaFeatures.isFullScreen()) {
1710
1777
  player.isNativeFullScreen = true;
@@ -1716,7 +1783,13 @@ if (typeof jQuery != 'undefined') {
1716
1783
  // make sure to put the player back into place
1717
1784
  player.exitFullScreen();
1718
1785
  }
1719
- });
1786
+ };
1787
+
1788
+ if (mejs.MediaFeatures.hasMozNativeFullScreen) {
1789
+ player.globalBind(mejs.MediaFeatures.fullScreenEventName, func);
1790
+ } else {
1791
+ player.container.bind(mejs.MediaFeatures.fullScreenEventName, func);
1792
+ }
1720
1793
  }
1721
1794
 
1722
1795
  var t = this,
@@ -1822,7 +1895,7 @@ if (typeof jQuery != 'undefined') {
1822
1895
  left: fullScreenBtnOffset + fullScreenBtnWidth});
1823
1896
  };
1824
1897
 
1825
- $(document).resize(function() {
1898
+ t.globalBind('resize', function() {
1826
1899
  positionHoverDivs();
1827
1900
  });
1828
1901
 
@@ -1862,7 +1935,7 @@ if (typeof jQuery != 'undefined') {
1862
1935
  // the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
1863
1936
  // so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
1864
1937
  /*
1865
- $(document).mousemove(function(e) {
1938
+ t.globalBind('mousemove', function(e) {
1866
1939
 
1867
1940
  // if the mouse is anywhere but the fullsceen button, then restore it all
1868
1941
  if (fullscreenIsDisabled) {
@@ -1920,13 +1993,18 @@ if (typeof jQuery != 'undefined') {
1920
1993
 
1921
1994
  player.fullscreenBtn = fullscreenBtn;
1922
1995
 
1923
- $(document).bind('keydown',function (e) {
1996
+ t.globalBind('keydown',function (e) {
1924
1997
  if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
1925
1998
  player.exitFullScreen();
1926
1999
  }
1927
2000
  });
1928
2001
 
1929
2002
  },
2003
+
2004
+ cleanfullscreen: function(player) {
2005
+ player.exitFullScreen();
2006
+ },
2007
+
1930
2008
  enterFullScreen: function() {
1931
2009
 
1932
2010
  var t = this;
@@ -2030,7 +2108,7 @@ if (typeof jQuery != 'undefined') {
2030
2108
  .width('100%')
2031
2109
  .height('100%');
2032
2110
  } else {
2033
- t.container.find('object, embed, iframe')
2111
+ t.container.find('.mejs-shim')
2034
2112
  .width('100%')
2035
2113
  .height('100%');
2036
2114
 
@@ -2111,8 +2189,17 @@ if (typeof jQuery != 'undefined') {
2111
2189
  $.extend(mejs.MepDefaults, {
2112
2190
  // this will automatically turn on a <track>
2113
2191
  startLanguage: '',
2192
+
2193
+ tracksText: 'Captions/Subtitles',
2114
2194
 
2115
- tracksText: 'Captions/Subtitles'
2195
+ // option to remove the [cc] button when no <track kind="subtitles"> are present
2196
+ hideCaptionsButtonWhenEmpty: true,
2197
+
2198
+ // If true and we only have one track, change captions to popup
2199
+ toggleCaptionsButtonWhenOnlyOne: false,
2200
+
2201
+ // #id or .class
2202
+ slidesSelector: ''
2116
2203
  });
2117
2204
 
2118
2205
  $.extend(MediaElementPlayer.prototype, {
@@ -2126,13 +2213,15 @@ if (typeof jQuery != 'undefined') {
2126
2213
  if (player.tracks.length == 0)
2127
2214
  return;
2128
2215
 
2129
- var t= this, i, options = '';
2216
+ var t = this,
2217
+ i,
2218
+ options = '';
2130
2219
 
2131
2220
  player.chapters =
2132
2221
  $('<div class="mejs-chapters mejs-layer"></div>')
2133
2222
  .prependTo(layers).hide();
2134
2223
  player.captions =
2135
- $('<div class="mejs-captions-layer mejs-layer"><div class="mejs-captions-position"><span class="mejs-captions-text"></span></div></div>')
2224
+ $('<div class="mejs-captions-layer mejs-layer"><div class="mejs-captions-position mejs-captions-position-hover"><span class="mejs-captions-text"></span></div></div>')
2136
2225
  .prependTo(layers).hide();
2137
2226
  player.captionsText = player.captions.find('.mejs-captions-text');
2138
2227
  player.captionsButton =
@@ -2147,35 +2236,42 @@ if (typeof jQuery != 'undefined') {
2147
2236
  '</ul>'+
2148
2237
  '</div>'+
2149
2238
  '</div>')
2150
- .appendTo(controls)
2151
-
2152
- // hover
2153
- .hover(function() {
2154
- $(this).find('.mejs-captions-selector').css('visibility','visible');
2155
- }, function() {
2156
- $(this).find('.mejs-captions-selector').css('visibility','hidden');
2157
- })
2239
+ .appendTo(controls);
2240
+
2158
2241
 
2159
- // handle clicks to the language radio buttons
2160
- .delegate('input[type=radio]','click',function() {
2161
- lang = this.value;
2242
+ var subtitleCount = 0;
2243
+ for (i=0; i<player.tracks.length; i++) {
2244
+ if (player.tracks[i].kind == 'subtitles') {
2245
+ subtitleCount++;
2246
+ }
2247
+ }
2162
2248
 
2163
- if (lang == 'none') {
2164
- player.selectedTrack = null;
2165
- } else {
2166
- for (i=0; i<player.tracks.length; i++) {
2167
- if (player.tracks[i].srclang == lang) {
2168
- player.selectedTrack = player.tracks[i];
2169
- player.captions.attr('lang', player.selectedTrack.srclang);
2170
- player.displayCaptions();
2171
- break;
2172
- }
2173
- }
2174
- }
2175
- });
2176
- //.bind('mouseenter', function() {
2177
- // player.captionsButton.find('.mejs-captions-selector').css('visibility','visible')
2178
- //});
2249
+ // if only one language then just make the button a toggle
2250
+ if (t.options.toggleCaptionsButtonWhenOnlyOne && subtitleCount == 1){
2251
+ // click
2252
+ player.captionsButton.on('click',function() {
2253
+ if (player.selectedTrack == null) {
2254
+ var lang = player.tracks[0].srclang;
2255
+ } else {
2256
+ var lang = 'none';
2257
+ }
2258
+ player.setTrack(lang);
2259
+ });
2260
+ } else {
2261
+ // hover
2262
+ player.captionsButton.hover(function() {
2263
+ $(this).find('.mejs-captions-selector').css('visibility','visible');
2264
+ }, function() {
2265
+ $(this).find('.mejs-captions-selector').css('visibility','hidden');
2266
+ })
2267
+
2268
+ // handle clicks to the language radio buttons
2269
+ .on('click','input[type=radio]',function() {
2270
+ lang = this.value;
2271
+ player.setTrack(lang);
2272
+ });
2273
+
2274
+ }
2179
2275
 
2180
2276
  if (!player.options.alwaysShowControls) {
2181
2277
  // move with controls
@@ -2208,12 +2304,22 @@ if (typeof jQuery != 'undefined') {
2208
2304
  }
2209
2305
  }
2210
2306
 
2307
+ // start loading tracks
2211
2308
  player.loadNextTrack();
2212
2309
 
2213
2310
 
2214
2311
  media.addEventListener('timeupdate',function(e) {
2215
2312
  player.displayCaptions();
2216
2313
  }, false);
2314
+
2315
+ if (player.options.slidesSelector != '') {
2316
+ player.slidesContainer = $(player.options.slidesSelector);
2317
+
2318
+ media.addEventListener('timeupdate',function(e) {
2319
+ player.displaySlides();
2320
+ }, false);
2321
+
2322
+ }
2217
2323
 
2218
2324
  media.addEventListener('loadedmetadata', function(e) {
2219
2325
  player.displayChapters();
@@ -2241,6 +2347,28 @@ if (typeof jQuery != 'undefined') {
2241
2347
  player.chapters.css('visibility','hidden');
2242
2348
  }
2243
2349
  },
2350
+
2351
+ setTrack: function(lang){
2352
+
2353
+ var t = this,
2354
+ i;
2355
+
2356
+ if (lang == 'none') {
2357
+ t.selectedTrack = null;
2358
+ t.captionsButton.removeClass('mejs-captions-enabled');
2359
+ } else {
2360
+ for (i=0; i<t.tracks.length; i++) {
2361
+ if (t.tracks[i].srclang == lang) {
2362
+ if (t.selectedTrack == null)
2363
+ t.captionsButton.addClass('mejs-captions-enabled');
2364
+ t.selectedTrack = t.tracks[i];
2365
+ t.captions.attr('lang', t.selectedTrack.srclang);
2366
+ t.displayCaptions();
2367
+ break;
2368
+ }
2369
+ }
2370
+ }
2371
+ },
2244
2372
 
2245
2373
  loadNextTrack: function() {
2246
2374
  var t = this;
@@ -2252,6 +2380,8 @@ if (typeof jQuery != 'undefined') {
2252
2380
  } else {
2253
2381
  // add done?
2254
2382
  t.isLoadingTrack = false;
2383
+
2384
+ t.checkForTracks();
2255
2385
  }
2256
2386
  },
2257
2387
 
@@ -2293,6 +2423,10 @@ if (typeof jQuery != 'undefined') {
2293
2423
  }
2294
2424
  }, false);
2295
2425
  }
2426
+
2427
+ if (track.kind == 'slides') {
2428
+ t.setupSlides(track);
2429
+ }
2296
2430
  },
2297
2431
  error: function() {
2298
2432
  t.loadNextTrack();
@@ -2348,6 +2482,27 @@ if (typeof jQuery != 'undefined') {
2348
2482
  t.captionsButton.find('.mejs-captions-translations').outerHeight(true)
2349
2483
  );
2350
2484
  },
2485
+
2486
+ checkForTracks: function() {
2487
+ var
2488
+ t = this,
2489
+ hasSubtitles = false;
2490
+
2491
+ // check if any subtitles
2492
+ if (t.options.hideCaptionsButtonWhenEmpty) {
2493
+ for (i=0; i<t.tracks.length; i++) {
2494
+ if (t.tracks[i].kind == 'subtitles') {
2495
+ hasSubtitles = true;
2496
+ break;
2497
+ }
2498
+ }
2499
+
2500
+ if (!hasSubtitles) {
2501
+ t.captionsButton.hide();
2502
+ t.setControlsSize();
2503
+ }
2504
+ }
2505
+ },
2351
2506
 
2352
2507
  displayCaptions: function() {
2353
2508
 
@@ -2372,6 +2527,70 @@ if (typeof jQuery != 'undefined') {
2372
2527
  t.captions.hide();
2373
2528
  }
2374
2529
  },
2530
+
2531
+ setupSlides: function(track) {
2532
+ var t = this;
2533
+
2534
+ t.slides = track;
2535
+ t.slides.entries.imgs = [t.slides.entries.text.length];
2536
+ t.showSlide(0);
2537
+
2538
+ },
2539
+
2540
+ showSlide: function(index) {
2541
+ if (typeof this.tracks == 'undefined' || typeof this.slidesContainer == 'undefined') {
2542
+ return;
2543
+ }
2544
+
2545
+ var t = this,
2546
+ url = t.slides.entries.text[index],
2547
+ img = t.slides.entries.imgs[index];
2548
+
2549
+ if (typeof img == 'undefined' || typeof img.fadeIn == 'undefined') {
2550
+
2551
+ t.slides.entries.imgs[index] = img = $('<img src="' + url + '">')
2552
+ .on('load', function() {
2553
+ img.appendTo(t.slidesContainer)
2554
+ .hide()
2555
+ .fadeIn()
2556
+ .siblings(':visible')
2557
+ .fadeOut();
2558
+
2559
+ });
2560
+
2561
+ } else {
2562
+
2563
+ if (!img.is(':visible') && !img.is(':animated')) {
2564
+
2565
+ console.log('showing existing slide');
2566
+
2567
+ img.fadeIn()
2568
+ .siblings(':visible')
2569
+ .fadeOut();
2570
+ }
2571
+ }
2572
+
2573
+ },
2574
+
2575
+ displaySlides: function() {
2576
+
2577
+ if (typeof this.slides == 'undefined')
2578
+ return;
2579
+
2580
+ var
2581
+ t = this,
2582
+ slides = t.slides,
2583
+ i;
2584
+
2585
+ for (i=0; i<slides.entries.times.length; i++) {
2586
+ if (t.media.currentTime >= slides.entries.times[i].start && t.media.currentTime <= slides.entries.times[i].stop){
2587
+
2588
+ t.showSlide(i);
2589
+
2590
+ return; // exit out if one is visible;
2591
+ }
2592
+ }
2593
+ },
2375
2594
 
2376
2595
  displayChapters: function() {
2377
2596
  var
@@ -2735,6 +2954,10 @@ $.extend(mejs.MepDefaults,
2735
2954
 
2736
2955
  });
2737
2956
  },
2957
+
2958
+ cleancontextmenu: function(player) {
2959
+ player.contextMenu.remove();
2960
+ },
2738
2961
 
2739
2962
  isContextMenuEnabled: true,
2740
2963
  enableContextMenu: function() {
@@ -1,3 +1,3 @@
1
1
  module MediaelementRails
2
- VERSION = '0.5.0'
2
+ VERSION = '0.5.1'
3
3
  end
metadata CHANGED
@@ -1,105 +1,155 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mediaelement_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
5
- prerelease:
4
+ version: 0.5.1
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Tobias Schlottke
9
9
  - Pete Browne
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-02-10 00:00:00.000000000 Z
13
+ date: 2013-03-21 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: railties
17
- requirement: &70273556849820 !ruby/object:Gem::Requirement
17
+ version_requirements: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: '3.1'
18
22
  none: false
23
+ requirement: !ruby/object:Gem::Requirement
19
24
  requirements:
20
- - - ! '>='
25
+ - - ">="
21
26
  - !ruby/object:Gem::Version
22
27
  version: '3.1'
23
- type: :runtime
28
+ none: false
24
29
  prerelease: false
25
- version_requirements: *70273556849820
30
+ type: :runtime
26
31
  - !ruby/object:Gem::Dependency
27
32
  name: jquery-rails
28
- requirement: &70273556849320 !ruby/object:Gem::Requirement
33
+ version_requirements: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '1.0'
29
38
  none: false
39
+ requirement: !ruby/object:Gem::Requirement
30
40
  requirements:
31
- - - ! '>='
41
+ - - ">="
32
42
  - !ruby/object:Gem::Version
33
43
  version: '1.0'
34
- type: :runtime
44
+ none: false
35
45
  prerelease: false
36
- version_requirements: *70273556849320
46
+ type: :runtime
37
47
  - !ruby/object:Gem::Dependency
38
48
  name: rails
39
- requirement: &70273556848860 !ruby/object:Gem::Requirement
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '3.1'
40
54
  none: false
55
+ requirement: !ruby/object:Gem::Requirement
41
56
  requirements:
42
- - - ! '>='
57
+ - - ">="
43
58
  - !ruby/object:Gem::Version
44
59
  version: '3.1'
45
- type: :development
60
+ none: false
46
61
  prerelease: false
47
- version_requirements: *70273556848860
62
+ type: :development
48
63
  - !ruby/object:Gem::Dependency
49
64
  name: i18n
50
- requirement: &70273556848480 !ruby/object:Gem::Requirement
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: !binary |-
70
+ MA==
51
71
  none: false
72
+ requirement: !ruby/object:Gem::Requirement
52
73
  requirements:
53
- - - ! '>='
74
+ - - ">="
54
75
  - !ruby/object:Gem::Version
55
- version: '0'
56
- type: :development
76
+ version: !binary |-
77
+ MA==
78
+ none: false
57
79
  prerelease: false
58
- version_requirements: *70273556848480
80
+ type: :development
59
81
  - !ruby/object:Gem::Dependency
60
82
  name: turn
61
- requirement: &70273556848020 !ruby/object:Gem::Requirement
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: !binary |-
88
+ MA==
62
89
  none: false
90
+ requirement: !ruby/object:Gem::Requirement
63
91
  requirements:
64
- - - ! '>='
92
+ - - ">="
65
93
  - !ruby/object:Gem::Version
66
- version: '0'
67
- type: :development
94
+ version: !binary |-
95
+ MA==
96
+ none: false
68
97
  prerelease: false
69
- version_requirements: *70273556848020
98
+ type: :development
70
99
  - !ruby/object:Gem::Dependency
71
100
  name: sqlite3
72
- requirement: &70273556847600 !ruby/object:Gem::Requirement
101
+ version_requirements: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: !binary |-
106
+ MA==
73
107
  none: false
108
+ requirement: !ruby/object:Gem::Requirement
74
109
  requirements:
75
- - - ! '>='
110
+ - - ">="
76
111
  - !ruby/object:Gem::Version
77
- version: '0'
78
- type: :development
112
+ version: !binary |-
113
+ MA==
114
+ none: false
79
115
  prerelease: false
80
- version_requirements: *70273556847600
116
+ type: :development
81
117
  - !ruby/object:Gem::Dependency
82
118
  name: thor
83
- requirement: &70273556878140 !ruby/object:Gem::Requirement
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: !binary |-
124
+ MA==
84
125
  none: false
126
+ requirement: !ruby/object:Gem::Requirement
85
127
  requirements:
86
- - - ! '>='
128
+ - - ">="
87
129
  - !ruby/object:Gem::Version
88
- version: '0'
89
- type: :development
130
+ version: !binary |-
131
+ MA==
132
+ none: false
90
133
  prerelease: false
91
- version_requirements: *70273556878140
134
+ type: :development
92
135
  - !ruby/object:Gem::Dependency
93
136
  name: rake
94
- requirement: &70273556877720 !ruby/object:Gem::Requirement
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: !binary |-
142
+ MA==
95
143
  none: false
144
+ requirement: !ruby/object:Gem::Requirement
96
145
  requirements:
97
- - - ! '>='
146
+ - - ">="
98
147
  - !ruby/object:Gem::Version
99
- version: '0'
100
- type: :development
148
+ version: !binary |-
149
+ MA==
150
+ none: false
101
151
  prerelease: false
102
- version_requirements: *70273556877720
152
+ type: :development
103
153
  description: A MediaElement gem(engine) for Rails. Makes embedding HTML5 video easy.
104
154
  email:
105
155
  - tobias.schlottke@gmail.com
@@ -108,7 +158,7 @@ executables: []
108
158
  extensions: []
109
159
  extra_rdoc_files: []
110
160
  files:
111
- - .gitignore
161
+ - ".gitignore"
112
162
  - Gemfile
113
163
  - MIT-LICENSE
114
164
  - README.md
@@ -176,26 +226,28 @@ files:
176
226
  - vendor/.gitkeep
177
227
  homepage: https://github.com/tobsch/mediaelement_rails
178
228
  licenses: []
179
- post_install_message:
229
+ post_install_message:
180
230
  rdoc_options: []
181
231
  require_paths:
182
232
  - lib
183
233
  required_ruby_version: !ruby/object:Gem::Requirement
184
- none: false
185
234
  requirements:
186
- - - ! '>='
235
+ - - ">="
187
236
  - !ruby/object:Gem::Version
188
- version: '0'
189
- required_rubygems_version: !ruby/object:Gem::Requirement
237
+ version: !binary |-
238
+ MA==
190
239
  none: false
240
+ required_rubygems_version: !ruby/object:Gem::Requirement
191
241
  requirements:
192
- - - ! '>='
242
+ - - ">="
193
243
  - !ruby/object:Gem::Version
194
- version: '0'
244
+ version: !binary |-
245
+ MA==
246
+ none: false
195
247
  requirements: []
196
- rubyforge_project:
197
- rubygems_version: 1.8.17
198
- signing_key:
248
+ rubyforge_project:
249
+ rubygems_version: 1.8.24
250
+ signing_key:
199
251
  specification_version: 3
200
252
  summary: MediaElement.js for Rails
201
253
  test_files: