From 7b270067ea6774988957107a7e2a8d774c03c8d3 Mon Sep 17 00:00:00 2001 From: Nathaniel Bibler Date: Mon, 18 Jun 2012 09:58:46 -0400 Subject: [PATCH] Update to MediaElement.js version 2.9.1 --- .../images/mediaelement_rails/controls.png | Bin 689 -> 654 bytes .../mediaelement_rails/mediaelement.js | 49 ++- .../mediaelement_rails/mediaelementplayer.js | 346 +++++++++++------- .../mediaelement_rails/flashmediaelement.swf | Bin 22926 -> 27303 bytes .../silverlightmediaelement.xap | Bin 7715 -> 12461 bytes .../mediaelementplayer.css.erb | 172 ++++++++- 6 files changed, 422 insertions(+), 145 deletions(-) diff --git a/app/assets/images/mediaelement_rails/controls.png b/app/assets/images/mediaelement_rails/controls.png index a4f86631650e77f1fb920fd9bc60c78790eecb4e..7cce224e9980c529ce97199cd0a63b6b002bccaa 100755 GIT binary patch delta 631 zcmV--0*L*w1&#$giBL{Q4GJ0x0000DNk~Le0001x0000W1Oos701u+<{r~^~1ZP1_ zK>z@;j|==^1poj5Fi=cXMF0Q*kwGMX|Ns9pGc*7H|4kW=n*aa+4s=pZQvfp}-DX6H z?wPyHRd=fKvkce(00HkwL_t(Y$K{mGO2a@9$0ti$zYg0J)Pt9;_;FXngNGKO(u0B& z?}`Txy@?Od>I?V`dhno^Djo%W1fL`Xt4-@i#@TGPNt;+w5fPlwO?NZ-W#&JBvkUNh zR$fo$X9WLjIU;&Lj-Jud{p+^(m?1uC*X0nv2JYR*&h!dbAR0OP56LTC=!g+Qu^HET z6Y?X{Kz&KRfpmEwJn=!OKx*iM7Mp8;OBC;|Ydzlt5d|RBAg2gw-Bz#48C_`s6`GwM zPKfC?!2G6by_bTFd=S?P5D2Az2wjl&gNv*2YQu)w13;!ppbgh*l|)w|9TCN&LLv}; zh$tvkpDVMX?WJls1S-2$n?U^Hl$IYvSwvxyH>cfqYYUPHGA9^Sy(;VR}uG!7}+8W{;$o7WPTiV;SJlX8~0V$ zme1+aAzth#h%5ck? zrMq>1fPyk5t`Q}{`DrEPiAAXljw$&`sS0kHMXBZaMcKs)&cP;Zn=UV4U|_uB>EamT z(Rp{uS+Bzm0>{&Xy_Y6MXg~7ISp2|q1N-_QR$H&73qC$mesR)S|026UysMy1g^+C) z|GcGZeq4;2eOCF%%^b7Nve{uSEXzx7_P<$g{Qu{2hW+y2(thm}JU>Iil7F8XKht)z zd*aQ>hkh=u`eMd-V*bjRnv52+I3`r{81?eWy0gsu{3l)Ofs(_&rX3TXw<|VyH^?X* z@cGX6L-g79XFv6|3)wguqFHyQed>yMsP4S5XZ7RXg1auT&A9XF&-JJ|l}ra*Cki^u zJ$&?M#NI;-c5+X6t(0*4bF`_H<^+}x=C`;{SOuG{+_XUDuxrEHpSdg90w-XKM$;=^reShxDdwjeT+9 zirFsr&%QazXR7`M2R>)szGzYs*JP7P7Y~>{bXAx)za)vLV9_R(2dk$pe=qkfwQasj zSJMl#|B*fyz7$Vh%_gPuqFHj)%0&TO>a{LCj1{pa{q1o9iBk{R%bu5K5K#7BlPbZn zp{tp(ajNgfPag6|L`66ymMStHsFL3p;GFcAMS!=S?S~&{m0+TV;KF)oP03}w7w&sZ rQ{8JJz)+43r0)z4*}Q$iB}6C*Rv diff --git a/app/assets/javascripts/mediaelement_rails/mediaelement.js b/app/assets/javascripts/mediaelement_rails/mediaelement.js index 6bf13c0..ad21b23 100755 --- a/app/assets/javascripts/mediaelement_rails/mediaelement.js +++ b/app/assets/javascripts/mediaelement_rails/mediaelement.js @@ -7,7 +7,7 @@ * for browsers that don't understand HTML5 or can't play the provided codec * Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3 * -* Copyright 2010-2011, John Dyer (http://j.hn) +* Copyright 2010-2012, John Dyer (http://j.hn) * Dual licensed under the MIT or GPL Version 2 licenses. * */ @@ -15,7 +15,7 @@ var mejs = mejs || {}; // version number -mejs.version = '2.6.5'; +mejs.version = '2.9.1'; // player number (for missing, same id attr) mejs.meIndex = 0; @@ -26,11 +26,11 @@ mejs.plugins = { {version: [3,0], types: ['video/mp4','video/m4v','video/mov','video/wmv','audio/wma','audio/m4a','audio/mp3','audio/wav','audio/mpeg']} ], flash: [ - {version: [9,0,124], types: ['video/mp4','video/m4v','video/mov','video/flv','video/x-flv','audio/flv','audio/x-flv','audio/mp3','audio/m4a','audio/mpeg']} + {version: [9,0,124], types: ['video/mp4','video/m4v','video/mov','video/flv','video/x-flv','audio/flv','audio/x-flv','audio/mp3','audio/m4a','audio/mpeg', 'video/youtube', 'video/x-youtube']} //,{version: [12,0], types: ['video/webm']} // for future reference (hopefully!) ], youtube: [ - {version: null, types: ['video/youtube']} + {version: null, types: ['video/youtube', 'video/x-youtube']} ], vimeo: [ {version: null, types: ['video/vimeo']} @@ -59,11 +59,13 @@ mejs.Utility = { path = '', name = '', script, - scripts = document.getElementsByTagName('script'); + scripts = document.getElementsByTagName('script'), + il = scripts.length, + jl = scriptNames.length; - for (; i < scripts.length; i++) { + for (; i < il; i++) { script = scripts[i].src; - for (j = 0; j < scriptNames.length; j++) { + for (j = 0; j < jl; j++) { name = scriptNames[j]; if (script.indexOf(name) > -1) { path = script.substring(0, script.indexOf(name)); @@ -436,6 +438,7 @@ mejs.PluginMediaElement.prototype = { seeking: false, duration: 0, error: null, + tagName: '', // HTML5 get/set properties, but only set (updated by event handlers) muted: false, @@ -650,6 +653,24 @@ mejs.PluginMediaElement.prototype = { }, // end: fake events + // fake DOM attribute methods + attributes: {}, + hasAttribute: function(name){ + return (name in this.attributes); + }, + removeAttribute: function(name){ + delete this.attributes[name]; + }, + getAttribute: function(name){ + if (this.hasAttribute(name)) { + return this.attributes[name]; + } + return ''; + }, + setAttribute: function(name, value){ + this.attributes[name] = value; + }, + remove: function() { mejs.Utility.removeSwf(this.pluginElement.id); } @@ -1021,7 +1042,7 @@ mejs.HtmlMediaElementShim = { } catch (e) {} errorContainer.innerHTML = (poster !== '') ? - '' : + '' : 'Download File'; htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement); @@ -1042,6 +1063,17 @@ mejs.HtmlMediaElementShim = { node, initVars; + // copy tagName from html media element + pluginMediaElement.tagName = htmlMediaElement.tagName + + // copy attributes from html media element to plugin media element + for (var i = 0; i < htmlMediaElement.attributes.length; i++) { + var attribute = htmlMediaElement.attributes[i]; + if (attribute.specified == true) { + pluginMediaElement.setAttribute(attribute.name, attribute.value); + } + } + // check for placement inside a

tag (sometimes WYSIWYG editors do this) node = htmlMediaElement.parentNode; while (node !== null && node.tagName.toLowerCase() != 'body') { @@ -1361,6 +1393,7 @@ mejs.YouTubeApi = { iFrameReady: function() { + this.isLoaded = true; this.isIframeLoaded = true; while (this.iframeQueue.length > 0) { diff --git a/app/assets/javascripts/mediaelement_rails/mediaelementplayer.js b/app/assets/javascripts/mediaelement_rails/mediaelementplayer.js index d418db6..fc2b547 100755 --- a/app/assets/javascripts/mediaelement_rails/mediaelementplayer.js +++ b/app/assets/javascripts/mediaelement_rails/mediaelementplayer.js @@ -5,7 +5,7 @@ * Creates a controller bar for HTML5

'+ '') .hide() // start out hidden - .appendTo(layers), - + .appendTo(layers), // this needs to come last so it's on top bigPlay = $('
'+ @@ -889,14 +895,26 @@ if (typeof jQuery != 'undefined') { media.addEventListener('play',function() { bigPlay.hide(); loading.hide(); + controls.find('.mejs-time-buffering').hide(); error.hide(); }, false); media.addEventListener('playing', function() { bigPlay.hide(); loading.hide(); + controls.find('.mejs-time-buffering').hide(); error.hide(); }, false); + + media.addEventListener('seeking', function() { + loading.show(); + controls.find('.mejs-time-buffering').show(); + }, false); + + media.addEventListener('seeked', function() { + loading.hide(); + controls.find('.mejs-time-buffering').hide(); + }, false); media.addEventListener('pause',function() { if (!mejs.MediaFeatures.isiPhone) { @@ -906,6 +924,7 @@ if (typeof jQuery != 'undefined') { media.addEventListener('waiting', function() { loading.show(); + controls.find('.mejs-time-buffering').show(); }, false); @@ -916,14 +935,17 @@ if (typeof jQuery != 'undefined') { // return; loading.show(); + controls.find('.mejs-time-buffering').show(); }, false); media.addEventListener('canplay',function() { loading.hide(); + controls.find('.mejs-time-buffering').hide(); }, false); // error handling media.addEventListener('error',function() { loading.hide(); + controls.find('.mejs-time-buffering').hide(); error.show(); error.find('mejs-overlay-error').html("Error loading this resource"); }, false); @@ -986,7 +1008,7 @@ if (typeof jQuery != 'undefined') { }, changeSkin: function(className) { this.container[0].className = 'mejs-container ' + className; - this.setPlayerSize(); + this.setPlayerSize(this.width, this.height); this.setControlsSize(); }, play: function() { @@ -1021,7 +1043,7 @@ if (typeof jQuery != 'undefined') { if (t.media.pluginType == 'flash') { t.media.remove(); - } else if (t.media.pluginTyp == 'native') { + } else if (t.media.pluginType == 'native') { t.media.prop('controls', true); } @@ -1051,7 +1073,8 @@ if (typeof jQuery != 'undefined') { // push out to window window.MediaElementPlayer = mejs.MediaElementPlayer; -})(mejs.$); +})(mejs.$); + (function($) { $.extend(mejs.MepDefaults, { @@ -1110,7 +1133,7 @@ if (typeof jQuery != 'undefined') { var t = this, stop = $('
' + - '' + '
') .appendTo(controls) .click(function() { @@ -1137,6 +1160,7 @@ if (typeof jQuery != 'undefined') { $('
'+ ''+ + ''+ ''+ ''+ ''+ @@ -1147,6 +1171,7 @@ if (typeof jQuery != 'undefined') { ''+ '
') .appendTo(controls); + controls.find('.mejs-time-buffering').hide(); var t = this, @@ -1194,31 +1219,32 @@ if (typeof jQuery != 'undefined') { if (e.which === 1) { mouseIsDown = true; handleMouseMove(e); + $(document) + .bind('mousemove.dur', function(e) { + handleMouseMove(e); + }) + .bind('mouseup.dur', function (e) { + mouseIsDown = false; + timefloat.hide(); + $(document).unbind('.dur'); + }); return false; - } - }); - - controls.find('.mejs-time-total') + } + }) .bind('mouseenter', function(e) { mouseIsOver = true; + $(document).bind('mousemove.dur', function(e) { + handleMouseMove(e); + }); if (!mejs.MediaFeatures.hasTouch) { timefloat.show(); } }) .bind('mouseleave',function(e) { mouseIsOver = false; - timefloat.hide(); - }); - - $(document) - .bind('mouseup', function (e) { - mouseIsDown = false; - timefloat.hide(); - //handleMouseMove(e); - }) - .bind('mousemove', function (e) { - if (mouseIsDown || mouseIsOver) { - handleMouseMove(e); + if (!mouseIsDown) { + $(document).unbind('.dur'); + timefloat.hide(); } }); @@ -1379,18 +1405,36 @@ if (typeof jQuery != 'undefined') { $.extend(mejs.MepDefaults, { muteText: 'Mute Toggle', - hideVolumeOnTouchDevices: true + hideVolumeOnTouchDevices: true, + + audioVolume: 'horizontal', + videoVolume: 'vertical' }); $.extend(MediaElementPlayer.prototype, { buildvolume: function(player, controls, layers, media) { - + // Android and iOS don't support volume controls if (mejs.MediaFeatures.hasTouch && this.options.hideVolumeOnTouchDevices) return; var t = this, - mute = + mode = (t.isVideo) ? t.options.videoVolume : t.options.audioVolume, + mute = (mode == 'horizontal') ? + + // horizontal version + $('
'+ + ''+ + '
' + + '
'+ // outer background + '
'+ // line background + '
'+ // current volume + '
'+ // handle + '
' + ) + .appendTo(controls) : + + // vertical version $('
'+ ''+ '
'+ // outer background @@ -1399,89 +1443,118 @@ if (typeof jQuery != 'undefined') { '
'+ // handle '
'+ '
') - .appendTo(controls), - volumeSlider = mute.find('.mejs-volume-slider'), - volumeTotal = mute.find('.mejs-volume-total'), - volumeCurrent = mute.find('.mejs-volume-current'), - volumeHandle = mute.find('.mejs-volume-handle'), + .appendTo(controls), + volumeSlider = t.container.find('.mejs-volume-slider, .mejs-horizontal-volume-slider'), + volumeTotal = t.container.find('.mejs-volume-total, .mejs-horizontal-volume-total'), + volumeCurrent = t.container.find('.mejs-volume-current, .mejs-horizontal-volume-current'), + volumeHandle = t.container.find('.mejs-volume-handle, .mejs-horizontal-volume-handle'), - positionVolumeHandle = function(volume) { + positionVolumeHandle = function(volume, secondTry) { - if (!volumeSlider.is(':visible')) { + if (!volumeSlider.is(':visible') && typeof secondTry != 'undefined') { volumeSlider.show(); - positionVolumeHandle(volume); + positionVolumeHandle(volume, true); volumeSlider.hide() return; } - - var + + // correct to 0-1 + volume = Math.max(0,volume); + volume = Math.min(volume,1); - // height of the full size volume slider background - totalHeight = volumeTotal.height(), + // ajust mute button style + if (volume == 0) { + mute.removeClass('mejs-mute').addClass('mejs-unmute'); + } else { + mute.removeClass('mejs-unmute').addClass('mejs-mute'); + } + + // position slider + if (mode == 'vertical') { + var - // top/left of full size volume slider background - totalPosition = volumeTotal.position(), + // height of the full size volume slider background + totalHeight = volumeTotal.height(), + + // top/left of full size volume slider background + totalPosition = volumeTotal.position(), + + // the new top position based on the current volume + // 70% volume on 100px height == top:30px + newTop = totalHeight - (totalHeight * volume); + + // handle + volumeHandle.css('top', totalPosition.top + newTop - (volumeHandle.height() / 2)); + + // show the current visibility + volumeCurrent.height(totalHeight - newTop ); + volumeCurrent.css('top', totalPosition.top + newTop); + } else { + var - // the new top position based on the current volume - // 70% volume on 100px height == top:30px - newTop = totalHeight - (totalHeight * volume); - - // handle - volumeHandle.css('top', totalPosition.top + newTop - (volumeHandle.height() / 2)); - - // show the current visibility - volumeCurrent.height(totalHeight - newTop ); - volumeCurrent.css('top', totalPosition.top + newTop); + // height of the full size volume slider background + totalWidth = volumeTotal.width(), + + // top/left of full size volume slider background + totalPosition = volumeTotal.position(), + + // the new left position based on the current volume + newLeft = totalWidth * volume; + + // handle + volumeHandle.css('left', totalPosition.left + newLeft - (volumeHandle.width() / 2)); + + // rezize the current part of the volume bar + volumeCurrent.width( newLeft ); + } }, handleVolumeMove = function(e) { - var - railHeight = volumeTotal.height(), - totalOffset = volumeTotal.offset(), - totalTop = parseInt(volumeTotal.css('top').replace(/px/,''),10), - newY = e.pageY - totalOffset.top, - volume = (railHeight - newY) / railHeight - - // the controls just hide themselves (usually when mouse moves too far up) - if (totalOffset.top == 0 || totalOffset.left == 0) - return; + + var volume = null, + totalOffset = volumeTotal.offset(); + + // calculate the new volume based on the moust position + if (mode == 'vertical') { + + var + railHeight = volumeTotal.height(), + totalTop = parseInt(volumeTotal.css('top').replace(/px/,''),10), + newY = e.pageY - totalOffset.top; + + volume = (railHeight - newY) / railHeight; + + // the controls just hide themselves (usually when mouse moves too far up) + if (totalOffset.top == 0 || totalOffset.left == 0) + return; - // 0-1 + } else { + var + railWidth = volumeTotal.width(), + newX = e.pageX - totalOffset.left; + + volume = newX / railWidth; + } + + // ensure the volume isn't outside 0-1 volume = Math.max(0,volume); - volume = Math.min(volume,1); - - // TODO: handle vertical and horizontal CSS - // only allow it to move within the rail - if (newY < 0) - newY = 0; - else if (newY > railHeight) - newY = railHeight; - - // move the handle to match the mouse - volumeHandle.css('top', newY - (volumeHandle.height() / 2) + totalTop ); - - // show the current visibility - volumeCurrent.height(railHeight-newY); - volumeCurrent.css('top',newY+totalTop); - - // set mute status + volume = Math.min(volume,1); + + // position the slider and handle + positionVolumeHandle(volume); + + // set the media object (this will trigger the volumechanged event) if (volume == 0) { media.setMuted(true); - mute.removeClass('mejs-mute').addClass('mejs-unmute'); } else { media.setMuted(false); - mute.removeClass('mejs-unmute').addClass('mejs-mute'); } - - volume = Math.max(0,volume); - volume = Math.min(volume,1); - - // set the volume - media.setVolume(volume); + media.setVolume(volume); }, mouseIsDown = false, mouseIsOver = false; // SLIDER + mute .hover(function() { volumeSlider.show(); @@ -1489,7 +1562,7 @@ if (typeof jQuery != 'undefined') { }, function() { mouseIsOver = false; - if (!mouseIsDown) { + if (!mouseIsDown && mode == 'vertical') { volumeSlider.hide(); } }); @@ -1500,31 +1573,27 @@ if (typeof jQuery != 'undefined') { }) .bind('mousedown', function (e) { handleVolumeMove(e); + $(document) + .bind('mousemove.vol', function(e) { + handleVolumeMove(e); + }) + .bind('mouseup.vol', function () { + mouseIsDown = false; + $(document).unbind('.vol'); + + if (!mouseIsOver && mode == 'vertical') { + volumeSlider.hide(); + } + }); mouseIsDown = true; return false; }); - - $(document) - .bind('mouseup', function (e) { - mouseIsDown = false; - - if (!mouseIsOver) { - volumeSlider.hide(); - } - }) - .bind('mousemove', function (e) { - if (mouseIsDown) { - handleVolumeMove(e); - } - }); // MUTE button mute.find('button').click(function() { - media.setMuted( !media.muted ); - }); // listen for volume change events from other sources @@ -1540,13 +1609,14 @@ if (typeof jQuery != 'undefined') { } }, false); - // set initial volume - //console.log('init volume',player.options.startVolume); - positionVolumeHandle(player.options.startVolume); - - // shim gets the startvolume as a parameter, but we have to set it on the native