mediaelement_rails 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: