app/assets/javascripts/mediaelement_rails/mediaelementplayer.js in mediaelement_rails-0.4.0 vs app/assets/javascripts/mediaelement_rails/mediaelementplayer.js in mediaelement_rails-0.5.0
- old
+ new
@@ -4,1095 +4,1111 @@
*
* Creates a controller bar for HTML5 <video> add <audio> tags
* using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
*
* Copyright 2010-2012, John Dyer (http://j.hn/)
- * Dual licensed under the MIT or GPL Version 2 licenses.
+ * License: MIT
*
*/
if (typeof jQuery != 'undefined') {
mejs.$ = jQuery;
} else if (typeof ender != 'undefined') {
mejs.$ = ender;
}
-(function ($) {
-
- // default player values
- mejs.MepDefaults = {
- // url to poster (to fix iOS 3.x)
- poster: '',
- // default if the <video width> is not specified
- defaultVideoWidth: 480,
- // default if the <video height> is not specified
- defaultVideoHeight: 270,
- // if set, overrides <video width>
- videoWidth: -1,
- // if set, overrides <video height>
- videoHeight: -1,
- // default if the user doesn't specify
- defaultAudioWidth: 400,
- // default if the user doesn't specify
- defaultAudioHeight: 30,
-
- // default amount to move back when back key is pressed
- defaultSeekBackwardInterval: function(media) {
- return (media.duration * 0.05);
- },
- // default amount to move forward when forward key is pressed
- defaultSeekForwardInterval: function(media) {
- return (media.duration * 0.05);
- },
-
- // width of audio player
- audioWidth: -1,
- // height of audio player
- audioHeight: -1,
- // initial volume when the player starts (overrided by user cookie)
- startVolume: 0.8,
- // useful for <audio> player loops
- loop: false,
- // resize to media dimensions
- enableAutosize: true,
- // forces the hour marker (##:00:00)
- alwaysShowHours: false,
-
- // show framecount in timecode (##:00:00:00)
- showTimecodeFrameCount: false,
- // used when showTimecodeFrameCount is set to true
- framesPerSecond: 25,
-
- // automatically calculate the width of the progress bar based on the sizes of other elements
- autosizeProgress : true,
- // Hide controls when playing and mouse is not over the video
- alwaysShowControls: false,
- // force iPad's native controls
- iPadUseNativeControls: false,
- // force iPhone's native controls
- iPhoneUseNativeControls: false,
- // force Android's native controls
- AndroidUseNativeControls: false,
- // features to show
- features: ['playpause','current','progress','duration','tracks','volume','fullscreen'],
- // only for dynamic
- isVideo: true,
-
- // turns keyboard support on and off for this instance
- enableKeyboard: true,
-
- // whenthis player starts, it will pause other players
- pauseOtherPlayers: true,
-
- // array of keyboard actions such as play pause
- keyActions: [
- {
- keys: [
- 32, // SPACE
- 179 // GOOGLE play/pause button
- ],
- action: function(player, media) {
- if (media.paused || media.ended) {
- media.play();
- } else {
- media.pause();
- }
- }
- },
- {
- keys: [38], // UP
- action: function(player, media) {
- var newVolume = Math.min(media.volume + 0.1, 1);
- media.setVolume(newVolume);
- }
- },
- {
- keys: [40], // DOWN
- action: function(player, media) {
- var newVolume = Math.max(media.volume - 0.1, 0);
- media.setVolume(newVolume);
- }
- },
- {
- keys: [
- 37, // LEFT
- 227 // Google TV rewind
- ],
- action: function(player, media) {
- if (!isNaN(media.duration) && media.duration > 0) {
- if (player.isVideo) {
- player.showControls();
- player.startControlsTimer();
- }
-
- // 5%
- var newTime = Math.max(media.currentTime - player.options.defaultSeekBackwardInterval(media), 0);
- media.setCurrentTime(newTime);
- }
- }
- },
- {
- keys: [
- 39, // RIGHT
- 228 // Google TV forward
- ],
- action: function(player, media) {
- if (!isNaN(media.duration) && media.duration > 0) {
- if (player.isVideo) {
- player.showControls();
- player.startControlsTimer();
- }
-
- // 5%
- var newTime = Math.min(media.currentTime + player.options.defaultSeekForwardInterval(media), media.duration);
- media.setCurrentTime(newTime);
- }
- }
- },
- {
- keys: [70], // f
- action: function(player, media) {
- if (typeof player.enterFullScreen != 'undefined') {
- if (player.isFullScreen) {
- player.exitFullScreen();
- } else {
- player.enterFullScreen();
- }
- }
- }
- }
- ]
- };
-
- mejs.mepIndex = 0;
-
- mejs.players = [];
-
- // wraps a MediaElement object in player controls
- mejs.MediaElementPlayer = function(node, o) {
- // enforce object, even without "new" (via John Resig)
- if ( !(this instanceof mejs.MediaElementPlayer) ) {
- return new mejs.MediaElementPlayer(node, o);
- }
-
- var t = this;
-
- // these will be reset after the MediaElement.success fires
- t.$media = t.$node = $(node);
- t.node = t.media = t.$media[0];
-
- // check for existing player
- if (typeof t.node.player != 'undefined') {
- return t.node.player;
- } else {
- // attach player to DOM node for reference
- t.node.player = t;
- }
-
-
- // try to get options from data-mejsoptions
- if (typeof o == 'undefined') {
- o = t.$node.data('mejsoptions');
- }
-
- // extend default options
- t.options = $.extend({},mejs.MepDefaults,o);
-
- // add to player array (for focus events)
- mejs.players.push(t);
-
- // start up
- t.init();
-
- return t;
- };
-
- // actual player
- mejs.MediaElementPlayer.prototype = {
-
- hasFocus: false,
-
- controlsAreVisible: true,
-
- init: function() {
-
- var
- t = this,
- mf = mejs.MediaFeatures,
- // options for MediaElement (shim)
- meOptions = $.extend(true, {}, t.options, {
- success: function(media, domNode) { t.meReady(media, domNode); },
- error: function(e) { t.handleError(e);}
- }),
- tagName = t.media.tagName.toLowerCase();
-
- t.isDynamic = (tagName !== 'audio' && tagName !== 'video');
-
- if (t.isDynamic) {
- // get video from src or href?
- t.isVideo = t.options.isVideo;
- } else {
- t.isVideo = (tagName !== 'audio' && t.options.isVideo);
- }
-
- // use native controls in iPad, iPhone, and Android
- if ((mf.isiPad && t.options.iPadUseNativeControls) || (mf.isiPhone && t.options.iPhoneUseNativeControls)) {
-
- // add controls and stop
- t.$media.attr('controls', 'controls');
-
- // attempt to fix iOS 3 bug
- //t.$media.removeAttr('poster');
- // no Issue found on iOS3 -ttroxell
-
- // override Apple's autoplay override for iPads
- if (mf.isiPad && t.media.getAttribute('autoplay') !== null) {
- t.media.load();
- t.media.play();
- }
-
- } else if (mf.isAndroid && t.AndroidUseNativeControls) {
-
- // leave default player
-
- } else {
-
- // DESKTOP: use MediaElementPlayer controls
-
- // remove native controls
- t.$media.removeAttr('controls');
-
- // unique ID
- t.id = 'mep_' + mejs.mepIndex++;
-
- // build container
- t.container =
- $('<div id="' + t.id + '" class="mejs-container">'+
- '<div class="mejs-inner">'+
- '<div class="mejs-mediaelement"></div>'+
- '<div class="mejs-layers"></div>'+
- '<div class="mejs-controls"></div>'+
- '<div class="mejs-clear"></div>'+
- '</div>' +
- '</div>')
- .addClass(t.$media[0].className)
- .insertBefore(t.$media);
-
- // add classes for user and content
- t.container.addClass(
- (mf.isAndroid ? 'mejs-android ' : '') +
- (mf.isiOS ? 'mejs-ios ' : '') +
- (mf.isiPad ? 'mejs-ipad ' : '') +
- (mf.isiPhone ? 'mejs-iphone ' : '') +
- (t.isVideo ? 'mejs-video ' : 'mejs-audio ')
- );
-
-
- // move the <video/video> tag into the right spot
- if (mf.isiOS) {
-
- // sadly, you can't move nodes in iOS, so we have to destroy and recreate it!
- var $newMedia = t.$media.clone();
-
- t.container.find('.mejs-mediaelement').append($newMedia);
-
- t.$media.remove();
- t.$node = t.$media = $newMedia;
- t.node = t.media = $newMedia[0]
-
- } else {
-
- // normal way of moving it into place (doesn't work on iOS)
- t.container.find('.mejs-mediaelement').append(t.$media);
- }
-
- // find parts
- t.controls = t.container.find('.mejs-controls');
- t.layers = t.container.find('.mejs-layers');
-
- // determine the size
-
- /* size priority:
- (1) videoWidth (forced),
- (2) style="width;height;"
- (3) width attribute,
- (4) defaultVideoWidth (for unspecified cases)
- */
-
- var tagType = (t.isVideo ? 'video' : 'audio'),
- capsTagName = tagType.substring(0,1).toUpperCase() + tagType.substring(1);
-
-
- if (t.options[tagType + 'Width'] > 0 || t.options[tagType + 'Width'].toString().indexOf('%') > -1) {
- t.width = t.options[tagType + 'Width'];
- } else if (t.media.style.width !== '' && t.media.style.width !== null) {
- t.width = t.media.style.width;
- } else if (t.media.getAttribute('width') !== null) {
- t.width = t.$media.attr('width');
- } else {
- t.width = t.options['default' + capsTagName + 'Width'];
- }
-
- if (t.options[tagType + 'Height'] > 0 || t.options[tagType + 'Height'].toString().indexOf('%') > -1) {
- t.height = t.options[tagType + 'Height'];
- } else if (t.media.style.height !== '' && t.media.style.height !== null) {
- t.height = t.media.style.height;
- } else if (t.$media[0].getAttribute('height') !== null) {
- t.height = t.$media.attr('height');
- } else {
- t.height = t.options['default' + capsTagName + 'Height'];
- }
-
- // set the size, while we wait for the plugins to load below
- t.setPlayerSize(t.width, t.height);
-
- // create MediaElementShim
- meOptions.pluginWidth = t.height;
- meOptions.pluginHeight = t.width;
- }
-
-
-
- // create MediaElement shim
- mejs.MediaElement(t.$media[0], meOptions);
- },
-
- showControls: function(doAnimation) {
- var t = this;
-
- doAnimation = typeof doAnimation == 'undefined' || doAnimation;
-
- if (t.controlsAreVisible)
- return;
-
- if (doAnimation) {
- t.controls
- .css('visibility','visible')
- .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
-
- // any additional controls people might add and want to hide
- t.container.find('.mejs-control')
- .css('visibility','visible')
- .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
-
- } else {
- t.controls
- .css('visibility','visible')
- .css('display','block');
-
- // any additional controls people might add and want to hide
- t.container.find('.mejs-control')
- .css('visibility','visible')
- .css('display','block');
-
- t.controlsAreVisible = true;
- }
-
- t.setControlsSize();
-
- },
-
- hideControls: function(doAnimation) {
- var t = this;
-
- doAnimation = typeof doAnimation == 'undefined' || doAnimation;
-
- if (!t.controlsAreVisible)
- return;
-
- if (doAnimation) {
- // fade out main controls
- t.controls.stop(true, true).fadeOut(200, function() {
- $(this)
- .css('visibility','hidden')
- .css('display','block');
-
- t.controlsAreVisible = false;
- });
-
- // any additional controls people might add and want to hide
- t.container.find('.mejs-control').stop(true, true).fadeOut(200, function() {
- $(this)
- .css('visibility','hidden')
- .css('display','block');
- });
- } else {
-
- // hide main controls
- t.controls
- .css('visibility','hidden')
- .css('display','block');
-
- // hide others
- t.container.find('.mejs-control')
- .css('visibility','hidden')
- .css('display','block');
-
- t.controlsAreVisible = false;
- }
- },
-
- controlsTimer: null,
-
- startControlsTimer: function(timeout) {
-
- var t = this;
-
- timeout = typeof timeout != 'undefined' ? timeout : 1500;
-
- t.killControlsTimer('start');
-
- t.controlsTimer = setTimeout(function() {
- //console.log('timer fired');
- t.hideControls();
- t.killControlsTimer('hide');
- }, timeout);
- },
-
- killControlsTimer: function(src) {
-
- var t = this;
-
- if (t.controlsTimer !== null) {
- clearTimeout(t.controlsTimer);
- delete t.controlsTimer;
- t.controlsTimer = null;
- }
- },
-
- controlsEnabled: true,
-
- disableControls: function() {
- var t= this;
-
- t.killControlsTimer();
- t.hideControls(false);
- this.controlsEnabled = false;
- },
-
- enableControls: function() {
- var t= this;
-
- t.showControls(false);
-
- t.controlsEnabled = true;
- },
-
-
- // Sets up all controls and events
- meReady: function(media, domNode) {
-
-
- var t = this,
- mf = mejs.MediaFeatures,
- autoplayAttr = domNode.getAttribute('autoplay'),
- autoplay = !(typeof autoplayAttr == 'undefined' || autoplayAttr === null || autoplayAttr === 'false'),
- featureIndex,
- feature;
-
- // make sure it can't create itself again if a plugin reloads
- if (t.created)
- return;
- else
- t.created = true;
-
- t.media = media;
- t.domNode = domNode;
-
- if (!(mf.isAndroid && t.options.AndroidUseNativeControls) && !(mf.isiPad && t.options.iPadUseNativeControls) && !(mf.isiPhone && t.options.iPhoneUseNativeControls)) {
-
- // two built in features
- t.buildposter(t, t.controls, t.layers, t.media);
- t.buildkeyboard(t, t.controls, t.layers, t.media);
- t.buildoverlays(t, t.controls, t.layers, t.media);
-
- // grab for use by features
- t.findTracks();
-
- // add user-defined features/controls
- for (featureIndex in t.options.features) {
- feature = t.options.features[featureIndex];
- if (t['build' + feature]) {
- try {
- t['build' + feature](t, t.controls, t.layers, t.media);
- } catch (e) {
- // TODO: report control error
- //throw e;
- //console.log('error building ' + feature);
- //console.log(e);
- }
- }
- }
-
- t.container.trigger('controlsready');
-
- // reset all layers and controls
- t.setPlayerSize(t.width, t.height);
- t.setControlsSize();
-
-
- // controls fade
- if (t.isVideo) {
-
- if (mejs.MediaFeatures.hasTouch) {
-
- // for touch devices (iOS, Android)
- // show/hide without animation on touch
-
- t.$media.bind('touchstart', function() {
-
-
- // toggle controls
- if (t.controlsAreVisible) {
- t.hideControls(false);
- } else {
- if (t.controlsEnabled) {
- t.showControls(false);
- }
- }
- });
-
- } else {
- // click controls
- var clickElement = (t.media.pluginType == 'native') ? t.$media : $(t.media.pluginElement);
-
- // click to play/pause
- clickElement.click(function() {
- if (media.paused) {
- media.play();
- } else {
- media.pause();
- }
- });
-
-
- // show/hide controls
- t.container
- .bind('mouseenter mouseover', function () {
- if (t.controlsEnabled) {
- if (!t.options.alwaysShowControls) {
- t.killControlsTimer('enter');
- t.showControls();
- t.startControlsTimer(2500);
- }
- }
- })
- .bind('mousemove', function() {
- if (t.controlsEnabled) {
- if (!t.controlsAreVisible) {
- t.showControls();
- }
- //t.killControlsTimer('move');
- if (!t.options.alwaysShowControls) {
- t.startControlsTimer(2500);
- }
- }
- })
- .bind('mouseleave', function () {
- if (t.controlsEnabled) {
- if (!t.media.paused && !t.options.alwaysShowControls) {
- t.startControlsTimer(1000);
- }
- }
- });
- }
-
- // check for autoplay
- if (autoplay && !t.options.alwaysShowControls) {
- t.hideControls();
- }
-
- // resizer
- if (t.options.enableAutosize) {
- t.media.addEventListener('loadedmetadata', function(e) {
- // if the <video height> was not set and the options.videoHeight was not set
- // then resize to the real dimensions
- if (t.options.videoHeight <= 0 && t.domNode.getAttribute('height') === null && !isNaN(e.target.videoHeight)) {
- t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);
- t.setControlsSize();
- t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);
- }
- }, false);
- }
- }
-
- // EVENTS
-
- // FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)
- media.addEventListener('play', function() {
-
- // go through all other players
- for (var i=0, il=mejs.players.length; i<il; i++) {
- var p = mejs.players[i];
- if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
- p.pause();
- }
- p.hasFocus = false;
- }
-
- t.hasFocus = true;
- },false);
-
-
- // ended for all
- t.media.addEventListener('ended', function (e) {
- try{
- t.media.setCurrentTime(0);
- } catch (exp) {
-
- }
- t.media.pause();
-
- if (t.setProgressRail)
- t.setProgressRail();
- if (t.setCurrentRail)
- t.setCurrentRail();
-
- if (t.options.loop) {
- t.media.play();
- } else if (!t.options.alwaysShowControls && t.controlsEnabled) {
- t.showControls();
- }
- }, false);
-
- // resize on the first play
- t.media.addEventListener('loadedmetadata', function(e) {
- if (t.updateDuration) {
- t.updateDuration();
- }
- if (t.updateCurrent) {
- t.updateCurrent();
- }
-
- if (!t.isFullScreen) {
- t.setPlayerSize(t.width, t.height);
- t.setControlsSize();
- }
- }, false);
-
-
- // webkit has trouble doing this without a delay
- setTimeout(function () {
- t.setPlayerSize(t.width, t.height);
- t.setControlsSize();
- }, 50);
-
- // adjust controls whenever window sizes (used to be in fullscreen only)
- $(window).resize(function() {
-
- // don't resize for fullscreen mode
- if ( !(t.isFullScreen || (mejs.MediaFeatures.hasTrueNativeFullScreen && document.webkitIsFullScreen)) ) {
- t.setPlayerSize(t.width, t.height);
- }
-
- // always adjust controls
- t.setControlsSize();
- });
-
- // TEMP: needs to be moved somewhere else
- if (t.media.pluginType == 'youtube') {
- t.container.find('.mejs-overlay-play').hide();
- }
- }
-
- // force autoplay for HTML5
- if (autoplay && media.pluginType == 'native') {
- media.load();
- media.play();
- }
-
-
- if (t.options.success) {
-
- if (typeof t.options.success == 'string') {
- window[t.options.success](t.media, t.domNode, t);
- } else {
- t.options.success(t.media, t.domNode, t);
- }
- }
- },
-
- handleError: function(e) {
- var t = this;
-
- t.controls.hide();
-
- // Tell user that the file cannot be played
- if (t.options.error) {
- t.options.error(e);
- }
- },
-
- setPlayerSize: function(width,height) {
- var t = this;
-
- if (typeof width != 'undefined')
- t.width = width;
-
- if (typeof height != 'undefined')
- t.height = height;
-
- // detect 100% mode
- if (t.height.toString().indexOf('%') > 0) {
-
- // do we have the native dimensions yet?
- var
- nativeWidth = (t.media.videoWidth && t.media.videoWidth > 0) ? t.media.videoWidth : t.options.defaultVideoWidth,
- nativeHeight = (t.media.videoHeight && t.media.videoHeight > 0) ? t.media.videoHeight : t.options.defaultVideoHeight,
- parentWidth = t.container.parent().width(),
- newHeight = parseInt(parentWidth * nativeHeight/nativeWidth, 10);
-
- if (t.container.parent()[0].tagName.toLowerCase() === 'body') { // && t.container.siblings().count == 0) {
- parentWidth = $(window).width();
- newHeight = $(window).height();
- }
-
- if ( newHeight != 0 ) {
- // set outer container size
- t.container
- .width(parentWidth)
- .height(newHeight);
-
- // set native <video>
- t.$media
- .width('100%')
- .height('100%');
-
- // set shims
- t.container.find('object, embed, iframe')
- .width('100%')
- .height('100%');
-
- // if shim is ready, send the size to the embeded plugin
- if (t.isVideo) {
- if (t.media.setVideoSize) {
- t.media.setVideoSize(parentWidth, newHeight);
- }
- }
-
- // set the layers
- t.layers.children('.mejs-layer')
- .width('100%')
- .height('100%');
- }
-
-
- } else {
-
- t.container
- .width(t.width)
- .height(t.height);
-
- t.layers.children('.mejs-layer')
- .width(t.width)
- .height(t.height);
-
- }
- },
-
- setControlsSize: function() {
- var t = this,
- usedWidth = 0,
- railWidth = 0,
- rail = t.controls.find('.mejs-time-rail'),
- total = t.controls.find('.mejs-time-total'),
- current = t.controls.find('.mejs-time-current'),
- loaded = t.controls.find('.mejs-time-loaded'),
- others = rail.siblings();
-
-
- // allow the size to come from custom CSS
- if (t.options && !t.options.autosizeProgress) {
- // Also, frontends devs can be more flexible
- // due the opportunity of absolute positioning.
- railWidth = parseInt(rail.css('width'));
- }
-
- // attempt to autosize
- if (railWidth === 0 || !railWidth) {
-
- // find the size of all the other controls besides the rail
- others.each(function() {
- if ($(this).css('position') != 'absolute') {
- usedWidth += $(this).outerWidth(true);
- }
- });
-
- // fit the rail into the remaining space
- railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.width());
- }
-
- // outer area
- rail.width(railWidth);
- // dark space
- total.width(railWidth - (total.outerWidth(true) - total.width()));
-
- if (t.setProgressRail)
- t.setProgressRail();
- if (t.setCurrentRail)
- t.setCurrentRail();
- },
-
-
- buildposter: function(player, controls, layers, media) {
- var t = this,
- poster =
- $('<div class="mejs-poster mejs-layer">' +
- '</div>')
- .appendTo(layers),
- posterUrl = player.$media.attr('poster');
-
- // prioriy goes to option (this is useful if you need to support iOS 3.x (iOS completely fails with poster)
- if (player.options.poster !== '') {
- posterUrl = player.options.poster;
- }
-
- // second, try the real poster
- if (posterUrl !== '' && posterUrl != null) {
- t.setPoster(posterUrl);
- } else {
- poster.hide();
- }
-
- media.addEventListener('play',function() {
- poster.hide();
- }, false);
- },
-
- setPoster: function(url) {
- var t = this,
- posterDiv = t.container.find('.mejs-poster'),
- posterImg = posterDiv.find('img');
-
- if (posterImg.length == 0) {
- posterImg = $('<img width="100%" height="100%" />').appendTo(posterDiv);
- }
-
- posterImg.attr('src', url);
- },
-
- buildoverlays: function(player, controls, layers, media) {
- if (!player.isVideo)
- return;
-
- var
- loading =
- $('<div class="mejs-overlay mejs-layer">'+
- '<div class="mejs-overlay-loading"><span></span></div>'+
- '</div>')
- .hide() // start out hidden
- .appendTo(layers),
- error =
- $('<div class="mejs-overlay mejs-layer">'+
- '<div class="mejs-overlay-error"></div>'+
- '</div>')
- .hide() // start out hidden
- .appendTo(layers),
- // this needs to come last so it's on top
- bigPlay =
- $('<div class="mejs-overlay mejs-layer mejs-overlay-play">'+
- '<div class="mejs-overlay-button"></div>'+
- '</div>')
- .appendTo(layers)
- .click(function() {
- if (media.paused) {
- media.play();
- } else {
- media.pause();
- }
- });
-
- /*
- if (mejs.MediaFeatures.isiOS || mejs.MediaFeatures.isAndroid) {
- bigPlay.remove();
- loading.remove();
- }
- */
-
-
- // show/hide big play button
- 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) {
- bigPlay.show();
- }
- }, false);
-
- media.addEventListener('waiting', function() {
- loading.show();
- controls.find('.mejs-time-buffering').show();
- }, false);
-
-
- // show/hide loading
- media.addEventListener('loadeddata',function() {
- // for some reason Chrome is firing this event
- //if (mejs.MediaFeatures.isChrome && media.getAttribute && media.getAttribute('preload') === 'none')
- // 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);
- },
-
- buildkeyboard: function(player, controls, layers, media) {
-
- var t = this;
-
- // listen for key presses
- $(document).keydown(function(e) {
-
- if (player.hasFocus && player.options.enableKeyboard) {
-
- // find a matching key
- for (var i=0, il=player.options.keyActions.length; i<il; i++) {
- var keyAction = player.options.keyActions[i];
-
- for (var j=0, jl=keyAction.keys.length; j<jl; j++) {
- if (e.keyCode == keyAction.keys[j]) {
- e.preventDefault();
- keyAction.action(player, media, e.keyCode);
- return false;
- }
- }
- }
- }
-
- return true;
- });
-
- // check if someone clicked outside a player region, then kill its focus
- $(document).click(function(event) {
- if ($(event.target).closest('.mejs-container').length == 0) {
- player.hasFocus = false;
- }
- });
-
- },
-
- findTracks: function() {
- var t = this,
- tracktags = t.$media.find('track');
-
- // store for use by plugins
- t.tracks = [];
- tracktags.each(function(index, track) {
-
- track = $(track);
-
- t.tracks.push({
- srclang: track.attr('srclang').toLowerCase(),
- src: track.attr('src'),
- kind: track.attr('kind'),
- label: track.attr('label') || '',
- entries: [],
- isLoaded: false
- });
- });
- },
- changeSkin: function(className) {
- this.container[0].className = 'mejs-container ' + className;
- this.setPlayerSize(this.width, this.height);
- this.setControlsSize();
- },
- play: function() {
- this.media.play();
- },
- pause: function() {
- this.media.pause();
- },
- load: function() {
- this.media.load();
- },
- setMuted: function(muted) {
- this.media.setMuted(muted);
- },
- setCurrentTime: function(time) {
- this.media.setCurrentTime(time);
- },
- getCurrentTime: function() {
- return this.media.currentTime;
- },
- setVolume: function(volume) {
- this.media.setVolume(volume);
- },
- getVolume: function() {
- return this.media.volume;
- },
- setSrc: function(src) {
- this.media.setSrc(src);
- },
- remove: function() {
- var t = this;
-
- if (t.media.pluginType === 'flash') {
- t.media.remove();
- } else if (t.media.pluginType === 'native') {
- t.$media.prop('controls', true);
- }
-
- // grab video and put it back in place
- if (!t.isDynamic) {
- t.$node.insertBefore(t.container)
- }
-
- t.container.remove();
- }
- };
-
- // turn into jQuery plugin
- if (typeof jQuery != 'undefined') {
- jQuery.fn.mediaelementplayer = function (options) {
- return this.each(function () {
- new mejs.MediaElementPlayer(this, options);
- });
- };
- }
-
- $(document).ready(function() {
- // auto enable using JSON attribute
- $('.mejs-player').mediaelementplayer();
- });
-
- // push out to window
- window.MediaElementPlayer = mejs.MediaElementPlayer;
-
-})(mejs.$);
+(function ($) {
+ // default player values
+ mejs.MepDefaults = {
+ // url to poster (to fix iOS 3.x)
+ poster: '',
+ // default if the <video width> is not specified
+ defaultVideoWidth: 480,
+ // default if the <video height> is not specified
+ defaultVideoHeight: 270,
+ // if set, overrides <video width>
+ videoWidth: -1,
+ // if set, overrides <video height>
+ videoHeight: -1,
+ // default if the user doesn't specify
+ defaultAudioWidth: 400,
+ // default if the user doesn't specify
+ defaultAudioHeight: 30,
+
+ // default amount to move back when back key is pressed
+ defaultSeekBackwardInterval: function(media) {
+ return (media.duration * 0.05);
+ },
+ // default amount to move forward when forward key is pressed
+ defaultSeekForwardInterval: function(media) {
+ return (media.duration * 0.05);
+ },
+
+ // width of audio player
+ audioWidth: -1,
+ // height of audio player
+ audioHeight: -1,
+ // initial volume when the player starts (overrided by user cookie)
+ startVolume: 0.8,
+ // useful for <audio> player loops
+ loop: false,
+ // rewind to beginning when media ends
+ autoRewind: true,
+ // resize to media dimensions
+ enableAutosize: true,
+ // forces the hour marker (##:00:00)
+ alwaysShowHours: false,
+
+ // show framecount in timecode (##:00:00:00)
+ showTimecodeFrameCount: false,
+ // used when showTimecodeFrameCount is set to true
+ framesPerSecond: 25,
+
+ // automatically calculate the width of the progress bar based on the sizes of other elements
+ autosizeProgress : true,
+ // Hide controls when playing and mouse is not over the video
+ alwaysShowControls: false,
+ // Enable click video element to toggle play/pause
+ clickToPlayPause: true,
+ // force iPad's native controls
+ iPadUseNativeControls: false,
+ // force iPhone's native controls
+ iPhoneUseNativeControls: false,
+ // force Android's native controls
+ AndroidUseNativeControls: false,
+ // features to show
+ features: ['playpause','current','progress','duration','tracks','volume','fullscreen'],
+ // only for dynamic
+ isVideo: true,
+
+ // turns keyboard support on and off for this instance
+ enableKeyboard: true,
+
+ // whenthis player starts, it will pause other players
+ pauseOtherPlayers: true,
+
+ // array of keyboard actions such as play pause
+ keyActions: [
+ {
+ keys: [
+ 32, // SPACE
+ 179 // GOOGLE play/pause button
+ ],
+ action: function(player, media) {
+ if (media.paused || media.ended) {
+ media.play();
+ } else {
+ media.pause();
+ }
+ }
+ },
+ {
+ keys: [38], // UP
+ action: function(player, media) {
+ var newVolume = Math.min(media.volume + 0.1, 1);
+ media.setVolume(newVolume);
+ }
+ },
+ {
+ keys: [40], // DOWN
+ action: function(player, media) {
+ var newVolume = Math.max(media.volume - 0.1, 0);
+ media.setVolume(newVolume);
+ }
+ },
+ {
+ keys: [
+ 37, // LEFT
+ 227 // Google TV rewind
+ ],
+ action: function(player, media) {
+ if (!isNaN(media.duration) && media.duration > 0) {
+ if (player.isVideo) {
+ player.showControls();
+ player.startControlsTimer();
+ }
+
+ // 5%
+ var newTime = Math.max(media.currentTime - player.options.defaultSeekBackwardInterval(media), 0);
+ media.setCurrentTime(newTime);
+ }
+ }
+ },
+ {
+ keys: [
+ 39, // RIGHT
+ 228 // Google TV forward
+ ],
+ action: function(player, media) {
+ if (!isNaN(media.duration) && media.duration > 0) {
+ if (player.isVideo) {
+ player.showControls();
+ player.startControlsTimer();
+ }
+
+ // 5%
+ var newTime = Math.min(media.currentTime + player.options.defaultSeekForwardInterval(media), media.duration);
+ media.setCurrentTime(newTime);
+ }
+ }
+ },
+ {
+ keys: [70], // f
+ action: function(player, media) {
+ if (typeof player.enterFullScreen != 'undefined') {
+ if (player.isFullScreen) {
+ player.exitFullScreen();
+ } else {
+ player.enterFullScreen();
+ }
+ }
+ }
+ }
+ ]
+ };
+
+ mejs.mepIndex = 0;
+
+ mejs.players = [];
+
+ // wraps a MediaElement object in player controls
+ mejs.MediaElementPlayer = function(node, o) {
+ // enforce object, even without "new" (via John Resig)
+ if ( !(this instanceof mejs.MediaElementPlayer) ) {
+ return new mejs.MediaElementPlayer(node, o);
+ }
+
+ var t = this;
+
+ // these will be reset after the MediaElement.success fires
+ t.$media = t.$node = $(node);
+ t.node = t.media = t.$media[0];
+
+ // check for existing player
+ if (typeof t.node.player != 'undefined') {
+ return t.node.player;
+ } else {
+ // attach player to DOM node for reference
+ t.node.player = t;
+ }
+
+
+ // try to get options from data-mejsoptions
+ if (typeof o == 'undefined') {
+ o = t.$node.data('mejsoptions');
+ }
+
+ // extend default options
+ t.options = $.extend({},mejs.MepDefaults,o);
+
+ // add to player array (for focus events)
+ mejs.players.push(t);
+
+ // start up
+ t.init();
+
+ return t;
+ };
+
+ // actual player
+ mejs.MediaElementPlayer.prototype = {
+
+ hasFocus: false,
+
+ controlsAreVisible: true,
+
+ init: function() {
+
+ var
+ t = this,
+ mf = mejs.MediaFeatures,
+ // options for MediaElement (shim)
+ meOptions = $.extend(true, {}, t.options, {
+ success: function(media, domNode) { t.meReady(media, domNode); },
+ error: function(e) { t.handleError(e);}
+ }),
+ tagName = t.media.tagName.toLowerCase();
+
+ t.isDynamic = (tagName !== 'audio' && tagName !== 'video');
+
+ if (t.isDynamic) {
+ // get video from src or href?
+ t.isVideo = t.options.isVideo;
+ } else {
+ t.isVideo = (tagName !== 'audio' && t.options.isVideo);
+ }
+
+ // use native controls in iPad, iPhone, and Android
+ if ((mf.isiPad && t.options.iPadUseNativeControls) || (mf.isiPhone && t.options.iPhoneUseNativeControls)) {
+
+ // add controls and stop
+ t.$media.attr('controls', 'controls');
+
+ // attempt to fix iOS 3 bug
+ //t.$media.removeAttr('poster');
+ // no Issue found on iOS3 -ttroxell
+
+ // override Apple's autoplay override for iPads
+ if (mf.isiPad && t.media.getAttribute('autoplay') !== null) {
+ t.media.load();
+ t.media.play();
+ }
+
+ } else if (mf.isAndroid && t.AndroidUseNativeControls) {
+
+ // leave default player
+
+ } else {
+
+ // DESKTOP: use MediaElementPlayer controls
+
+ // remove native controls
+ t.$media.removeAttr('controls');
+
+ // unique ID
+ t.id = 'mep_' + mejs.mepIndex++;
+
+ // build container
+ t.container =
+ $('<div id="' + t.id + '" class="mejs-container ' + (mejs.MediaFeatures.svg ? 'svg' : 'no-svg') + '">'+
+ '<div class="mejs-inner">'+
+ '<div class="mejs-mediaelement"></div>'+
+ '<div class="mejs-layers"></div>'+
+ '<div class="mejs-controls"></div>'+
+ '<div class="mejs-clear"></div>'+
+ '</div>' +
+ '</div>')
+ .addClass(t.$media[0].className)
+ .insertBefore(t.$media);
+
+ // add classes for user and content
+ t.container.addClass(
+ (mf.isAndroid ? 'mejs-android ' : '') +
+ (mf.isiOS ? 'mejs-ios ' : '') +
+ (mf.isiPad ? 'mejs-ipad ' : '') +
+ (mf.isiPhone ? 'mejs-iphone ' : '') +
+ (t.isVideo ? 'mejs-video ' : 'mejs-audio ')
+ );
+
+
+ // move the <video/video> tag into the right spot
+ if (mf.isiOS) {
+
+ // sadly, you can't move nodes in iOS, so we have to destroy and recreate it!
+ var $newMedia = t.$media.clone();
+
+ t.container.find('.mejs-mediaelement').append($newMedia);
+
+ t.$media.remove();
+ t.$node = t.$media = $newMedia;
+ t.node = t.media = $newMedia[0]
+
+ } else {
+
+ // normal way of moving it into place (doesn't work on iOS)
+ t.container.find('.mejs-mediaelement').append(t.$media);
+ }
+
+ // find parts
+ t.controls = t.container.find('.mejs-controls');
+ t.layers = t.container.find('.mejs-layers');
+
+ // determine the size
+
+ /* size priority:
+ (1) videoWidth (forced),
+ (2) style="width;height;"
+ (3) width attribute,
+ (4) defaultVideoWidth (for unspecified cases)
+ */
+
+ var tagType = (t.isVideo ? 'video' : 'audio'),
+ capsTagName = tagType.substring(0,1).toUpperCase() + tagType.substring(1);
+
+
+ if (t.options[tagType + 'Width'] > 0 || t.options[tagType + 'Width'].toString().indexOf('%') > -1) {
+ t.width = t.options[tagType + 'Width'];
+ } else if (t.media.style.width !== '' && t.media.style.width !== null) {
+ t.width = t.media.style.width;
+ } else if (t.media.getAttribute('width') !== null) {
+ t.width = t.$media.attr('width');
+ } else {
+ t.width = t.options['default' + capsTagName + 'Width'];
+ }
+
+ if (t.options[tagType + 'Height'] > 0 || t.options[tagType + 'Height'].toString().indexOf('%') > -1) {
+ t.height = t.options[tagType + 'Height'];
+ } else if (t.media.style.height !== '' && t.media.style.height !== null) {
+ t.height = t.media.style.height;
+ } else if (t.$media[0].getAttribute('height') !== null) {
+ t.height = t.$media.attr('height');
+ } else {
+ t.height = t.options['default' + capsTagName + 'Height'];
+ }
+
+ // set the size, while we wait for the plugins to load below
+ t.setPlayerSize(t.width, t.height);
+
+ // create MediaElementShim
+ meOptions.pluginWidth = t.height;
+ meOptions.pluginHeight = t.width;
+ }
+
+
+
+ // create MediaElement shim
+ mejs.MediaElement(t.$media[0], meOptions);
+
+ // controls are shown when loaded
+ t.container.trigger('controlsshown');
+ },
+
+ showControls: function(doAnimation) {
+ var t = this;
+
+ doAnimation = typeof doAnimation == 'undefined' || doAnimation;
+
+ if (t.controlsAreVisible)
+ return;
+
+ if (doAnimation) {
+ t.controls
+ .css('visibility','visible')
+ .stop(true, true).fadeIn(200, function() {
+ t.controlsAreVisible = true;
+ t.container.trigger('controlsshown');
+ });
+
+ // any additional controls people might add and want to hide
+ t.container.find('.mejs-control')
+ .css('visibility','visible')
+ .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
+
+ } else {
+ t.controls
+ .css('visibility','visible')
+ .css('display','block');
+
+ // any additional controls people might add and want to hide
+ t.container.find('.mejs-control')
+ .css('visibility','visible')
+ .css('display','block');
+
+ t.controlsAreVisible = true;
+ t.container.trigger('controlsshown');
+ }
+
+ t.setControlsSize();
+
+ },
+
+ hideControls: function(doAnimation) {
+ var t = this;
+
+ doAnimation = typeof doAnimation == 'undefined' || doAnimation;
+
+ if (!t.controlsAreVisible)
+ return;
+
+ if (doAnimation) {
+ // fade out main controls
+ t.controls.stop(true, true).fadeOut(200, function() {
+ $(this)
+ .css('visibility','hidden')
+ .css('display','block');
+
+ t.controlsAreVisible = false;
+ t.container.trigger('controlshidden');
+ });
+
+ // any additional controls people might add and want to hide
+ t.container.find('.mejs-control').stop(true, true).fadeOut(200, function() {
+ $(this)
+ .css('visibility','hidden')
+ .css('display','block');
+ });
+ } else {
+
+ // hide main controls
+ t.controls
+ .css('visibility','hidden')
+ .css('display','block');
+
+ // hide others
+ t.container.find('.mejs-control')
+ .css('visibility','hidden')
+ .css('display','block');
+
+ t.controlsAreVisible = false;
+ t.container.trigger('controlshidden');
+ }
+ },
+
+ controlsTimer: null,
+
+ startControlsTimer: function(timeout) {
+
+ var t = this;
+
+ timeout = typeof timeout != 'undefined' ? timeout : 1500;
+
+ t.killControlsTimer('start');
+
+ t.controlsTimer = setTimeout(function() {
+ //console.log('timer fired');
+ t.hideControls();
+ t.killControlsTimer('hide');
+ }, timeout);
+ },
+
+ killControlsTimer: function(src) {
+
+ var t = this;
+
+ if (t.controlsTimer !== null) {
+ clearTimeout(t.controlsTimer);
+ delete t.controlsTimer;
+ t.controlsTimer = null;
+ }
+ },
+
+ controlsEnabled: true,
+
+ disableControls: function() {
+ var t= this;
+
+ t.killControlsTimer();
+ t.hideControls(false);
+ this.controlsEnabled = false;
+ },
+
+ enableControls: function() {
+ var t= this;
+
+ t.showControls(false);
+
+ t.controlsEnabled = true;
+ },
+
+
+ // Sets up all controls and events
+ meReady: function(media, domNode) {
+
+
+ var t = this,
+ mf = mejs.MediaFeatures,
+ autoplayAttr = domNode.getAttribute('autoplay'),
+ autoplay = !(typeof autoplayAttr == 'undefined' || autoplayAttr === null || autoplayAttr === 'false'),
+ featureIndex,
+ feature;
+
+ // make sure it can't create itself again if a plugin reloads
+ if (t.created)
+ return;
+ else
+ t.created = true;
+
+ t.media = media;
+ t.domNode = domNode;
+
+ if (!(mf.isAndroid && t.options.AndroidUseNativeControls) && !(mf.isiPad && t.options.iPadUseNativeControls) && !(mf.isiPhone && t.options.iPhoneUseNativeControls)) {
+
+ // two built in features
+ t.buildposter(t, t.controls, t.layers, t.media);
+ t.buildkeyboard(t, t.controls, t.layers, t.media);
+ t.buildoverlays(t, t.controls, t.layers, t.media);
+
+ // grab for use by features
+ t.findTracks();
+
+ // add user-defined features/controls
+ for (featureIndex in t.options.features) {
+ feature = t.options.features[featureIndex];
+ if (t['build' + feature]) {
+ try {
+ t['build' + feature](t, t.controls, t.layers, t.media);
+ } catch (e) {
+ // TODO: report control error
+ //throw e;
+ //console.log('error building ' + feature);
+ //console.log(e);
+ }
+ }
+ }
+
+ t.container.trigger('controlsready');
+
+ // reset all layers and controls
+ t.setPlayerSize(t.width, t.height);
+ t.setControlsSize();
+
+
+ // controls fade
+ if (t.isVideo) {
+
+ if (mejs.MediaFeatures.hasTouch) {
+
+ // for touch devices (iOS, Android)
+ // show/hide without animation on touch
+
+ t.$media.bind('touchstart', function() {
+
+
+ // toggle controls
+ if (t.controlsAreVisible) {
+ t.hideControls(false);
+ } else {
+ if (t.controlsEnabled) {
+ t.showControls(false);
+ }
+ }
+ });
+
+ } else {
+ // click to play/pause
+ t.media.addEventListener('click', function() {
+ if (t.options.clickToPlayPause) {
+ if (t.media.paused) {
+ t.media.play();
+ } else {
+ t.media.pause();
+ }
+ }
+ });
+
+ // show/hide controls
+ t.container
+ .bind('mouseenter mouseover', function () {
+ if (t.controlsEnabled) {
+ if (!t.options.alwaysShowControls) {
+ t.killControlsTimer('enter');
+ t.showControls();
+ t.startControlsTimer(2500);
+ }
+ }
+ })
+ .bind('mousemove', function() {
+ if (t.controlsEnabled) {
+ if (!t.controlsAreVisible) {
+ t.showControls();
+ }
+ //t.killControlsTimer('move');
+ if (!t.options.alwaysShowControls) {
+ t.startControlsTimer(2500);
+ }
+ }
+ })
+ .bind('mouseleave', function () {
+ if (t.controlsEnabled) {
+ if (!t.media.paused && !t.options.alwaysShowControls) {
+ t.startControlsTimer(1000);
+ }
+ }
+ });
+ }
+
+ // check for autoplay
+ if (autoplay && !t.options.alwaysShowControls) {
+ t.hideControls();
+ }
+
+ // resizer
+ if (t.options.enableAutosize) {
+ t.media.addEventListener('loadedmetadata', function(e) {
+ // if the <video height> was not set and the options.videoHeight was not set
+ // then resize to the real dimensions
+ if (t.options.videoHeight <= 0 && t.domNode.getAttribute('height') === null && !isNaN(e.target.videoHeight)) {
+ t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);
+ t.setControlsSize();
+ t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);
+ }
+ }, false);
+ }
+ }
+
+ // EVENTS
+
+ // FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)
+ media.addEventListener('play', function() {
+
+ // go through all other players
+ for (var i=0, il=mejs.players.length; i<il; i++) {
+ var p = mejs.players[i];
+ if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
+ p.pause();
+ }
+ p.hasFocus = false;
+ }
+
+ t.hasFocus = true;
+ },false);
+
+
+ // ended for all
+ t.media.addEventListener('ended', function (e) {
+ if(t.options.autoRewind) {
+ try{
+ t.media.setCurrentTime(0);
+ } catch (exp) {
+
+ }
+ }
+ t.media.pause();
+
+ if (t.setProgressRail)
+ t.setProgressRail();
+ if (t.setCurrentRail)
+ t.setCurrentRail();
+
+ if (t.options.loop) {
+ t.media.play();
+ } else if (!t.options.alwaysShowControls && t.controlsEnabled) {
+ t.showControls();
+ }
+ }, false);
+
+ // resize on the first play
+ t.media.addEventListener('loadedmetadata', function(e) {
+ if (t.updateDuration) {
+ t.updateDuration();
+ }
+ if (t.updateCurrent) {
+ t.updateCurrent();
+ }
+
+ if (!t.isFullScreen) {
+ t.setPlayerSize(t.width, t.height);
+ t.setControlsSize();
+ }
+ }, false);
+
+
+ // webkit has trouble doing this without a delay
+ setTimeout(function () {
+ t.setPlayerSize(t.width, t.height);
+ t.setControlsSize();
+ }, 50);
+
+ // adjust controls whenever window sizes (used to be in fullscreen only)
+ $(window).resize(function() {
+
+ // don't resize for fullscreen mode
+ if ( !(t.isFullScreen || (mejs.MediaFeatures.hasTrueNativeFullScreen && document.webkitIsFullScreen)) ) {
+ t.setPlayerSize(t.width, t.height);
+ }
+
+ // always adjust controls
+ t.setControlsSize();
+ });
+
+ // TEMP: needs to be moved somewhere else
+ if (t.media.pluginType == 'youtube') {
+ t.container.find('.mejs-overlay-play').hide();
+ }
+ }
+
+ // force autoplay for HTML5
+ if (autoplay && media.pluginType == 'native') {
+ media.load();
+ media.play();
+ }
+
+
+ if (t.options.success) {
+
+ if (typeof t.options.success == 'string') {
+ window[t.options.success](t.media, t.domNode, t);
+ } else {
+ t.options.success(t.media, t.domNode, t);
+ }
+ }
+ },
+
+ handleError: function(e) {
+ var t = this;
+
+ t.controls.hide();
+
+ // Tell user that the file cannot be played
+ if (t.options.error) {
+ t.options.error(e);
+ }
+ },
+
+ setPlayerSize: function(width,height) {
+ var t = this;
+
+ if (typeof width != 'undefined')
+ t.width = width;
+
+ if (typeof height != 'undefined')
+ t.height = height;
+
+ // detect 100% mode - use currentStyle for IE since css() doesn't return percentages
+ if (t.height.toString().indexOf('%') > 0 || t.$node.css('max-width') === '100%' || (t.$node[0].currentStyle && t.$node[0].currentStyle.maxWidth === '100%')) {
+
+ // do we have the native dimensions yet?
+ var
+ nativeWidth = t.isVideo ? ((t.media.videoWidth && t.media.videoWidth > 0) ? t.media.videoWidth : t.options.defaultVideoWidth) : t.options.defaultAudioWidth,
+ nativeHeight = t.isVideo ? ((t.media.videoHeight && t.media.videoHeight > 0) ? t.media.videoHeight : t.options.defaultVideoHeight) : t.options.defaultAudioHeight,
+ parentWidth = t.container.parent().closest(':visible').width(),
+ newHeight = t.isVideo || !t.options.autosizeProgress ? parseInt(parentWidth * nativeHeight/nativeWidth, 10) : nativeHeight;
+
+ if (t.container.parent()[0].tagName.toLowerCase() === 'body') { // && t.container.siblings().count == 0) {
+ parentWidth = $(window).width();
+ newHeight = $(window).height();
+ }
+
+ if ( newHeight != 0 && parentWidth != 0 ) {
+ // set outer container size
+ t.container
+ .width(parentWidth)
+ .height(newHeight);
+
+ // set native <video> or <audio>
+ t.$media
+ .width('100%')
+ .height('100%');
+
+ // set shims
+ t.container.find('object, embed, iframe')
+ .width('100%')
+ .height('100%');
+
+ // if shim is ready, send the size to the embeded plugin
+ if (t.isVideo) {
+ if (t.media.setVideoSize) {
+ t.media.setVideoSize(parentWidth, newHeight);
+ }
+ }
+
+ // set the layers
+ t.layers.children('.mejs-layer')
+ .width('100%')
+ .height('100%');
+ }
+
+
+ } else {
+
+ t.container
+ .width(t.width)
+ .height(t.height);
+
+ t.layers.children('.mejs-layer')
+ .width(t.width)
+ .height(t.height);
+
+ }
+ },
+
+ setControlsSize: function() {
+ var t = this,
+ usedWidth = 0,
+ railWidth = 0,
+ rail = t.controls.find('.mejs-time-rail'),
+ total = t.controls.find('.mejs-time-total'),
+ current = t.controls.find('.mejs-time-current'),
+ loaded = t.controls.find('.mejs-time-loaded'),
+ others = rail.siblings();
+
+
+ // allow the size to come from custom CSS
+ if (t.options && !t.options.autosizeProgress) {
+ // Also, frontends devs can be more flexible
+ // due the opportunity of absolute positioning.
+ railWidth = parseInt(rail.css('width'));
+ }
+
+ // attempt to autosize
+ if (railWidth === 0 || !railWidth) {
+
+ // find the size of all the other controls besides the rail
+ others.each(function() {
+ if ($(this).css('position') != 'absolute') {
+ usedWidth += $(this).outerWidth(true);
+ }
+ });
+
+ // fit the rail into the remaining space
+ railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.width());
+ }
+
+ // outer area
+ rail.width(railWidth);
+ // dark space
+ total.width(railWidth - (total.outerWidth(true) - total.width()));
+
+ if (t.setProgressRail)
+ t.setProgressRail();
+ if (t.setCurrentRail)
+ t.setCurrentRail();
+ },
+
+
+ buildposter: function(player, controls, layers, media) {
+ var t = this,
+ poster =
+ $('<div class="mejs-poster mejs-layer">' +
+ '</div>')
+ .appendTo(layers),
+ posterUrl = player.$media.attr('poster');
+
+ // prioriy goes to option (this is useful if you need to support iOS 3.x (iOS completely fails with poster)
+ if (player.options.poster !== '') {
+ posterUrl = player.options.poster;
+ }
+
+ // second, try the real poster
+ if (posterUrl !== '' && posterUrl != null) {
+ t.setPoster(posterUrl);
+ } else {
+ poster.hide();
+ }
+
+ media.addEventListener('play',function() {
+ poster.hide();
+ }, false);
+ },
+
+ setPoster: function(url) {
+ var t = this,
+ posterDiv = t.container.find('.mejs-poster'),
+ posterImg = posterDiv.find('img');
+
+ if (posterImg.length == 0) {
+ posterImg = $('<img width="100%" height="100%" />').appendTo(posterDiv);
+ }
+
+ posterImg.attr('src', url);
+ },
+
+ buildoverlays: function(player, controls, layers, media) {
+ var t = this;
+ if (!player.isVideo)
+ return;
+
+ var
+ loading =
+ $('<div class="mejs-overlay mejs-layer">'+
+ '<div class="mejs-overlay-loading"><span></span></div>'+
+ '</div>')
+ .hide() // start out hidden
+ .appendTo(layers),
+ error =
+ $('<div class="mejs-overlay mejs-layer">'+
+ '<div class="mejs-overlay-error"></div>'+
+ '</div>')
+ .hide() // start out hidden
+ .appendTo(layers),
+ // this needs to come last so it's on top
+ bigPlay =
+ $('<div class="mejs-overlay mejs-layer mejs-overlay-play">'+
+ '<div class="mejs-overlay-button"></div>'+
+ '</div>')
+ .appendTo(layers)
+ .click(function() {
+ if (t.options.clickToPlayPause) {
+ if (media.paused) {
+ media.play();
+ } else {
+ media.pause();
+ }
+ }
+ });
+
+ /*
+ if (mejs.MediaFeatures.isiOS || mejs.MediaFeatures.isAndroid) {
+ bigPlay.remove();
+ loading.remove();
+ }
+ */
+
+
+ // show/hide big play button
+ 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) {
+ bigPlay.show();
+ }
+ }, false);
+
+ media.addEventListener('waiting', function() {
+ loading.show();
+ controls.find('.mejs-time-buffering').show();
+ }, false);
+
+
+ // show/hide loading
+ media.addEventListener('loadeddata',function() {
+ // for some reason Chrome is firing this event
+ //if (mejs.MediaFeatures.isChrome && media.getAttribute && media.getAttribute('preload') === 'none')
+ // 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);
+ },
+
+ buildkeyboard: function(player, controls, layers, media) {
+
+ var t = this;
+
+ // listen for key presses
+ $(document).keydown(function(e) {
+
+ if (player.hasFocus && player.options.enableKeyboard) {
+
+ // find a matching key
+ for (var i=0, il=player.options.keyActions.length; i<il; i++) {
+ var keyAction = player.options.keyActions[i];
+
+ for (var j=0, jl=keyAction.keys.length; j<jl; j++) {
+ if (e.keyCode == keyAction.keys[j]) {
+ e.preventDefault();
+ keyAction.action(player, media, e.keyCode);
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ });
+
+ // check if someone clicked outside a player region, then kill its focus
+ $(document).click(function(event) {
+ if ($(event.target).closest('.mejs-container').length == 0) {
+ player.hasFocus = false;
+ }
+ });
+
+ },
+
+ findTracks: function() {
+ var t = this,
+ tracktags = t.$media.find('track');
+
+ // store for use by plugins
+ t.tracks = [];
+ tracktags.each(function(index, track) {
+
+ track = $(track);
+
+ t.tracks.push({
+ srclang: track.attr('srclang').toLowerCase(),
+ src: track.attr('src'),
+ kind: track.attr('kind'),
+ label: track.attr('label') || '',
+ entries: [],
+ isLoaded: false
+ });
+ });
+ },
+ changeSkin: function(className) {
+ this.container[0].className = 'mejs-container ' + className;
+ this.setPlayerSize(this.width, this.height);
+ this.setControlsSize();
+ },
+ play: function() {
+ this.media.play();
+ },
+ pause: function() {
+ this.media.pause();
+ },
+ load: function() {
+ this.media.load();
+ },
+ setMuted: function(muted) {
+ this.media.setMuted(muted);
+ },
+ setCurrentTime: function(time) {
+ this.media.setCurrentTime(time);
+ },
+ getCurrentTime: function() {
+ return this.media.currentTime;
+ },
+ setVolume: function(volume) {
+ this.media.setVolume(volume);
+ },
+ getVolume: function() {
+ return this.media.volume;
+ },
+ setSrc: function(src) {
+ this.media.setSrc(src);
+ },
+ remove: function() {
+ var t = this;
+
+ if (t.media.pluginType === 'flash') {
+ t.media.remove();
+ } else if (t.media.pluginType === 'native') {
+ t.$media.prop('controls', true);
+ }
+
+ // grab video and put it back in place
+ if (!t.isDynamic) {
+ t.$node.insertBefore(t.container)
+ }
+
+ t.container.remove();
+ }
+ };
+
+ // turn into jQuery plugin
+ if (typeof jQuery != 'undefined') {
+ jQuery.fn.mediaelementplayer = function (options) {
+ return this.each(function () {
+ new mejs.MediaElementPlayer(this, options);
+ });
+ };
+ }
+
+ $(document).ready(function() {
+ // auto enable using JSON attribute
+ $('.mejs-player').mediaelementplayer();
+ });
+
+ // push out to window
+ window.MediaElementPlayer = mejs.MediaElementPlayer;
+
+})(mejs.$);
+
(function($) {
$.extend(mejs.MepDefaults, {
playpauseText: 'Play/Pause'
});
@@ -1155,11 +1171,12 @@
.click(function() {
if (!media.paused) {
media.pause();
}
if (media.currentTime > 0) {
- media.setCurrentTime(0);
+ media.setCurrentTime(0);
+ media.pause();
controls.find('.mejs-time-current').width('0px');
controls.find('.mejs-time-handle').css('left', '0px');
controls.find('.mejs-time-float-current').html( mejs.Utility.secondsToTimeCode(0) );
controls.find('.mejs-currenttime').html( mejs.Utility.secondsToTimeCode(0) );
layers.find('.mejs-poster').show();
@@ -1199,22 +1216,29 @@
timefloatcurrent = controls.find('.mejs-time-float-current'),
handleMouseMove = function (e) {
// mouse position relative to the object
var x = e.pageX,
offset = total.offset(),
- width = total.outerWidth(),
+ width = total.outerWidth(true),
percentage = 0,
newTime = 0,
- pos = x - offset.left;
+ pos = 0;
- if (x > offset.left && x <= width + offset.left && media.duration) {
- percentage = ((x - offset.left) / width);
+ if (media.duration) {
+ if (x < offset.left) {
+ x = offset.left;
+ } else if (x > width + offset.left) {
+ x = width + offset.left;
+ }
+
+ pos = x - offset.left;
+ percentage = (pos / width);
newTime = (percentage <= 0.02) ? 0 : percentage * media.duration;
// seek to where the mouse is
- if (mouseIsDown) {
+ if (mouseIsDown && newTime !== media.currentTime) {
media.setCurrentTime(newTime);
}
// position floating time box
if (!mejs.MediaFeatures.hasTouch) {
@@ -1334,90 +1358,94 @@
}
}
});
})(mejs.$);
-(function($) {
-
- // options
- $.extend(mejs.MepDefaults, {
- duration: -1,
- timeAndDurationSeparator: ' <span> | </span> '
- });
-
-
- // current and duration 00:00 / 00:00
- $.extend(MediaElementPlayer.prototype, {
- buildcurrent: function(player, controls, layers, media) {
- var t = this;
-
- $('<div class="mejs-time">'+
- '<span class="mejs-currenttime">' + (player.options.alwaysShowHours ? '00:' : '')
- + (player.options.showTimecodeFrameCount? '00:00:00':'00:00')+ '</span>'+
- '</div>')
- .appendTo(controls);
-
- t.currenttime = t.controls.find('.mejs-currenttime');
-
- media.addEventListener('timeupdate',function() {
- player.updateCurrent();
- }, false);
- },
-
-
- buildduration: function(player, controls, layers, media) {
- var t = this;
-
- if (controls.children().last().find('.mejs-currenttime').length > 0) {
- $(t.options.timeAndDurationSeparator +
- '<span class="mejs-duration">' +
- (t.options.duration > 0 ?
- mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
- ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
- ) +
- '</span>')
- .appendTo(controls.find('.mejs-time'));
- } else {
-
- // add class to current time
- controls.find('.mejs-currenttime').parent().addClass('mejs-currenttime-container');
-
- $('<div class="mejs-time mejs-duration-container">'+
- '<span class="mejs-duration">' +
- (t.options.duration > 0 ?
- mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
- ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
- ) +
- '</span>' +
- '</div>')
- .appendTo(controls);
- }
-
- t.durationD = t.controls.find('.mejs-duration');
-
- media.addEventListener('timeupdate',function() {
- player.updateDuration();
- }, false);
- },
-
- updateCurrent: function() {
- var t = this;
-
- if (t.currenttime) {
- t.currenttime.html(mejs.Utility.secondsToTimeCode(t.media.currentTime, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
- }
- },
-
- updateDuration: function() {
- var t = this;
-
- if (t.media.duration && t.durationD) {
- t.durationD.html(mejs.Utility.secondsToTimeCode(t.media.duration, t.options.alwaysShowHours, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
- }
- }
- });
-
+
+(function($) {
+
+ // options
+ $.extend(mejs.MepDefaults, {
+ duration: -1,
+ timeAndDurationSeparator: ' <span> | </span> '
+ });
+
+
+ // current and duration 00:00 / 00:00
+ $.extend(MediaElementPlayer.prototype, {
+ buildcurrent: function(player, controls, layers, media) {
+ var t = this;
+
+ $('<div class="mejs-time">'+
+ '<span class="mejs-currenttime">' + (player.options.alwaysShowHours ? '00:' : '')
+ + (player.options.showTimecodeFrameCount? '00:00:00':'00:00')+ '</span>'+
+ '</div>')
+ .appendTo(controls);
+
+ t.currenttime = t.controls.find('.mejs-currenttime');
+
+ media.addEventListener('timeupdate',function() {
+ player.updateCurrent();
+ }, false);
+ },
+
+
+ buildduration: function(player, controls, layers, media) {
+ var t = this;
+
+ if (controls.children().last().find('.mejs-currenttime').length > 0) {
+ $(t.options.timeAndDurationSeparator +
+ '<span class="mejs-duration">' +
+ (t.options.duration > 0 ?
+ mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
+ ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
+ ) +
+ '</span>')
+ .appendTo(controls.find('.mejs-time'));
+ } else {
+
+ // add class to current time
+ controls.find('.mejs-currenttime').parent().addClass('mejs-currenttime-container');
+
+ $('<div class="mejs-time mejs-duration-container">'+
+ '<span class="mejs-duration">' +
+ (t.options.duration > 0 ?
+ mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
+ ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
+ ) +
+ '</span>' +
+ '</div>')
+ .appendTo(controls);
+ }
+
+ t.durationD = t.controls.find('.mejs-duration');
+
+ media.addEventListener('timeupdate',function() {
+ player.updateDuration();
+ }, false);
+ },
+
+ updateCurrent: function() {
+ var t = this;
+
+ if (t.currenttime) {
+ t.currenttime.html(mejs.Utility.secondsToTimeCode(t.media.currentTime, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
+ }
+ },
+
+ updateDuration: function() {
+ var t = this;
+
+ //Toggle the long video class if the video is longer than an hour.
+ t.container.toggleClass("mejs-long-video", t.media.duration > 3600);
+
+ if (t.media.duration && t.durationD) {
+ t.durationD.html(mejs.Utility.secondsToTimeCode(t.media.duration, t.options.alwaysShowHours, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
+ }
+ }
+ });
+
})(mejs.$);
(function($) {
$.extend(mejs.MepDefaults, {
muteText: 'Mute Toggle',
@@ -1465,11 +1493,11 @@
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, secondTry) {
- if (!volumeSlider.is(':visible') && typeof secondTry != 'undefined') {
+ if (!volumeSlider.is(':visible') && typeof secondTry == 'undefined') {
volumeSlider.show();
positionVolumeHandle(volume, true);
volumeSlider.hide()
return;
}
@@ -1498,11 +1526,11 @@
// 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));
+ volumeHandle.css('top', Math.round(totalPosition.top + newTop - (volumeHandle.height() / 2)));
// show the current visibility
volumeCurrent.height(totalHeight - newTop );
volumeCurrent.css('top', totalPosition.top + newTop);
} else {
@@ -1516,14 +1544,14 @@
// the new left position based on the current volume
newLeft = totalWidth * volume;
// handle
- volumeHandle.css('left', totalPosition.left + newLeft - (volumeHandle.width() / 2));
+ volumeHandle.css('left', Math.round(totalPosition.left + newLeft - (volumeHandle.width() / 2)));
// rezize the current part of the volume bar
- volumeCurrent.width( newLeft );
+ volumeCurrent.width( Math.round(newLeft) );
}
},
handleVolumeMove = function(e) {
var volume = null,
@@ -1637,448 +1665,448 @@
}
});
})(mejs.$);
-(function($) {
-
- $.extend(mejs.MepDefaults, {
- usePluginFullScreen: true,
- newWindowCallback: function() { return '';},
- fullscreenText: 'Fullscreen'
- });
-
- $.extend(MediaElementPlayer.prototype, {
-
- isFullScreen: false,
-
- isNativeFullScreen: false,
-
- docStyleOverflow: null,
-
- isInIframe: false,
-
- buildfullscreen: function(player, controls, layers, media) {
-
- if (!player.isVideo)
- return;
-
- player.isInIframe = (window.location != window.parent.location);
-
- // native events
- if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
-
- // chrome doesn't alays fire this in an iframe
- var target = null;
-
- if (mejs.MediaFeatures.hasMozNativeFullScreen) {
- target = $(document);
- } else {
- target = player.container;
- }
-
- target.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {
-
- if (mejs.MediaFeatures.isFullScreen()) {
- player.isNativeFullScreen = true;
- // reset the controls once we are fully in full screen
- player.setControlsSize();
- } else {
- player.isNativeFullScreen = false;
- // when a user presses ESC
- // make sure to put the player back into place
- player.exitFullScreen();
- }
- });
- }
-
- var t = this,
- normalHeight = 0,
- normalWidth = 0,
- container = player.container,
- fullscreenBtn =
- $('<div class="mejs-button mejs-fullscreen-button">' +
- '<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
- '</div>')
- .appendTo(controls);
-
- if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {
-
- fullscreenBtn.click(function() {
- var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;
-
- if (isFullScreen) {
- player.exitFullScreen();
- } else {
- player.enterFullScreen();
- }
- });
-
- } else {
-
- var hideTimeout = null,
- supportsPointerEvents = (function() {
- // TAKEN FROM MODERNIZR
- var element = document.createElement('x'),
- documentElement = document.documentElement,
- getComputedStyle = window.getComputedStyle,
- supports;
- if(!('pointerEvents' in element.style)){
- return false;
- }
- element.style.pointerEvents = 'auto';
- element.style.pointerEvents = 'x';
- documentElement.appendChild(element);
- supports = getComputedStyle &&
- getComputedStyle(element, '').pointerEvents === 'auto';
- documentElement.removeChild(element);
- return !!supports;
- })();
-
- //console.log('supportsPointerEvents', supportsPointerEvents);
-
- if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(
-
- // allows clicking through the fullscreen button and controls down directly to Flash
-
- /*
- When a user puts his mouse over the fullscreen button, the controls are disabled
- So we put a div over the video and another one on iether side of the fullscreen button
- that caputre mouse movement
- and restore the controls once the mouse moves outside of the fullscreen button
- */
-
- var fullscreenIsDisabled = false,
- restoreControls = function() {
- if (fullscreenIsDisabled) {
- // hide the hovers
- videoHoverDiv.hide();
- controlsLeftHoverDiv.hide();
- controlsRightHoverDiv.hide();
-
- // restore the control bar
- fullscreenBtn.css('pointer-events', '');
- t.controls.css('pointer-events', '');
-
- // store for later
- fullscreenIsDisabled = false;
- }
- },
- videoHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
- controlsLeftHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
- controlsRightHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
- positionHoverDivs = function() {
- var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
- videoHoverDiv.css(style);
- controlsLeftHoverDiv.css(style);
- controlsRightHoverDiv.css(style);
-
- // over video, but not controls
- videoHoverDiv
- .width( t.container.width() )
- .height( t.container.height() - t.controls.height() );
-
- // over controls, but not the fullscreen button
- var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
- fullScreenBtnWidth = fullscreenBtn.outerWidth(true);
-
- controlsLeftHoverDiv
- .width( fullScreenBtnOffset )
- .height( t.controls.height() )
- .css({top: t.container.height() - t.controls.height()});
-
- // after the fullscreen button
- controlsRightHoverDiv
- .width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
- .height( t.controls.height() )
- .css({top: t.container.height() - t.controls.height(),
- left: fullScreenBtnOffset + fullScreenBtnWidth});
- };
-
- $(document).resize(function() {
- positionHoverDivs();
- });
-
- // on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
- fullscreenBtn
- .mouseover(function() {
-
- if (!t.isFullScreen) {
-
- var buttonPos = fullscreenBtn.offset(),
- containerPos = player.container.offset();
-
- // move the button in Flash into place
- media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);
-
- // allows click through
- fullscreenBtn.css('pointer-events', 'none');
- t.controls.css('pointer-events', 'none');
-
- // show the divs that will restore things
- videoHoverDiv.show();
- controlsRightHoverDiv.show();
- controlsLeftHoverDiv.show();
- positionHoverDivs();
-
- fullscreenIsDisabled = true;
- }
-
- });
-
- // restore controls anytime the user enters or leaves fullscreen
- media.addEventListener('fullscreenchange', function(e) {
- restoreControls();
- });
-
-
- // the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
- // so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
- /*
- $(document).mousemove(function(e) {
-
- // if the mouse is anywhere but the fullsceen button, then restore it all
- if (fullscreenIsDisabled) {
-
- var fullscreenBtnPos = fullscreenBtn.offset();
-
-
- if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
- e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
- ) {
-
- fullscreenBtn.css('pointer-events', '');
- t.controls.css('pointer-events', '');
-
- fullscreenIsDisabled = false;
- }
- }
- });
- */
-
-
- } else {
-
- // the hover state will show the fullscreen button in Flash to hover up and click
-
- fullscreenBtn
- .mouseover(function() {
-
- if (hideTimeout !== null) {
- clearTimeout(hideTimeout);
- delete hideTimeout;
- }
-
- var buttonPos = fullscreenBtn.offset(),
- containerPos = player.container.offset();
-
- media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);
-
- })
- .mouseout(function() {
-
- if (hideTimeout !== null) {
- clearTimeout(hideTimeout);
- delete hideTimeout;
- }
-
- hideTimeout = setTimeout(function() {
- media.hideFullscreenButton();
- }, 1500);
-
-
- });
- }
- }
-
- player.fullscreenBtn = fullscreenBtn;
-
- $(document).bind('keydown',function (e) {
- if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
- player.exitFullScreen();
- }
- });
-
- },
- enterFullScreen: function() {
-
- var t = this;
-
- // firefox+flash can't adjust plugin sizes without resetting :(
- if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
- //t.media.setFullscreen(true);
- //player.isFullScreen = true;
- return;
- }
-
- // store overflow
- docStyleOverflow = document.documentElement.style.overflow;
- // set it to not show scroll bars so 100% will work
- document.documentElement.style.overflow = 'hidden';
-
- // store sizing
- normalHeight = t.container.height();
- normalWidth = t.container.width();
-
- // attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
- if (t.media.pluginType === 'native') {
- if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
-
- mejs.MediaFeatures.requestFullScreen(t.container[0]);
- //return;
-
- if (t.isInIframe) {
- // sometimes exiting from fullscreen doesn't work
- // notably in Chrome <iframe>. Fixed in version 17
- setTimeout(function checkFullscreen() {
-
- if (t.isNativeFullScreen) {
-
- // check if the video is suddenly not really fullscreen
- if ($(window).width() !== screen.width) {
- // manually exit
- t.exitFullScreen();
- } else {
- // test again
- setTimeout(checkFullscreen, 500);
- }
- }
-
-
- }, 500);
- }
-
- } else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
- t.media.webkitEnterFullscreen();
- return;
- }
- }
-
- // check for iframe launch
- if (t.isInIframe) {
- var url = t.options.newWindowCallback(this);
-
-
- if (url !== '') {
-
- // launch immediately
- if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
- t.pause();
- window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
- return;
- } else {
- setTimeout(function() {
- if (!t.isNativeFullScreen) {
- t.pause();
- window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
- }
- }, 250);
- }
- }
-
- }
-
- // full window code
-
-
-
- // make full size
- t.container
- .addClass('mejs-container-fullscreen')
- .width('100%')
- .height('100%');
- //.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});
-
- // Only needed for safari 5.1 native full screen, can cause display issues elsewhere
- // Actually, it seems to be needed for IE8, too
- //if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
- setTimeout(function() {
- t.container.css({width: '100%', height: '100%'});
- t.setControlsSize();
- }, 500);
- //}
-
- if (t.pluginType === 'native') {
- t.$media
- .width('100%')
- .height('100%');
- } else {
- t.container.find('object, embed, iframe')
- .width('100%')
- .height('100%');
-
- //if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
- t.media.setVideoSize($(window).width(),$(window).height());
- //}
- }
-
- t.layers.children('div')
- .width('100%')
- .height('100%');
-
- if (t.fullscreenBtn) {
- t.fullscreenBtn
- .removeClass('mejs-fullscreen')
- .addClass('mejs-unfullscreen');
- }
-
- t.setControlsSize();
- t.isFullScreen = true;
- },
-
- exitFullScreen: function() {
-
- var t = this;
-
- // firefox can't adjust plugins
- if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
- t.media.setFullscreen(false);
- //player.isFullScreen = false;
- return;
- }
-
- // come outo of native fullscreen
- if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
- mejs.MediaFeatures.cancelFullScreen();
- }
-
- // restore scroll bars to document
- document.documentElement.style.overflow = docStyleOverflow;
-
- t.container
- .removeClass('mejs-container-fullscreen')
- .width(normalWidth)
- .height(normalHeight);
- //.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});
-
- if (t.pluginType === 'native') {
- t.$media
- .width(normalWidth)
- .height(normalHeight);
- } else {
- t.container.find('object embed')
- .width(normalWidth)
- .height(normalHeight);
-
- t.media.setVideoSize(normalWidth, normalHeight);
- }
-
- t.layers.children('div')
- .width(normalWidth)
- .height(normalHeight);
-
- t.fullscreenBtn
- .removeClass('mejs-unfullscreen')
- .addClass('mejs-fullscreen');
-
- t.setControlsSize();
- t.isFullScreen = false;
- }
- });
-
-})(mejs.$);
+(function($) {
+ $.extend(mejs.MepDefaults, {
+ usePluginFullScreen: true,
+ newWindowCallback: function() { return '';},
+ fullscreenText: mejs.i18n.t('Fullscreen')
+ });
+
+ $.extend(MediaElementPlayer.prototype, {
+
+ isFullScreen: false,
+
+ isNativeFullScreen: false,
+
+ docStyleOverflow: null,
+
+ isInIframe: false,
+
+ buildfullscreen: function(player, controls, layers, media) {
+
+ if (!player.isVideo)
+ return;
+
+ player.isInIframe = (window.location != window.parent.location);
+
+ // native events
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
+
+ // chrome doesn't alays fire this in an iframe
+ var target = null;
+
+ if (mejs.MediaFeatures.hasMozNativeFullScreen) {
+ target = $(document);
+ } else {
+ target = player.container;
+ }
+
+ target.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {
+
+ if (mejs.MediaFeatures.isFullScreen()) {
+ player.isNativeFullScreen = true;
+ // reset the controls once we are fully in full screen
+ player.setControlsSize();
+ } else {
+ player.isNativeFullScreen = false;
+ // when a user presses ESC
+ // make sure to put the player back into place
+ player.exitFullScreen();
+ }
+ });
+ }
+
+ var t = this,
+ normalHeight = 0,
+ normalWidth = 0,
+ container = player.container,
+ fullscreenBtn =
+ $('<div class="mejs-button mejs-fullscreen-button">' +
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
+ '</div>')
+ .appendTo(controls);
+
+ if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {
+
+ fullscreenBtn.click(function() {
+ var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;
+
+ if (isFullScreen) {
+ player.exitFullScreen();
+ } else {
+ player.enterFullScreen();
+ }
+ });
+
+ } else {
+
+ var hideTimeout = null,
+ supportsPointerEvents = (function() {
+ // TAKEN FROM MODERNIZR
+ var element = document.createElement('x'),
+ documentElement = document.documentElement,
+ getComputedStyle = window.getComputedStyle,
+ supports;
+ if(!('pointerEvents' in element.style)){
+ return false;
+ }
+ element.style.pointerEvents = 'auto';
+ element.style.pointerEvents = 'x';
+ documentElement.appendChild(element);
+ supports = getComputedStyle &&
+ getComputedStyle(element, '').pointerEvents === 'auto';
+ documentElement.removeChild(element);
+ return !!supports;
+ })();
+
+ //console.log('supportsPointerEvents', supportsPointerEvents);
+
+ if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(
+
+ // allows clicking through the fullscreen button and controls down directly to Flash
+
+ /*
+ When a user puts his mouse over the fullscreen button, the controls are disabled
+ So we put a div over the video and another one on iether side of the fullscreen button
+ that caputre mouse movement
+ and restore the controls once the mouse moves outside of the fullscreen button
+ */
+
+ var fullscreenIsDisabled = false,
+ restoreControls = function() {
+ if (fullscreenIsDisabled) {
+ // hide the hovers
+ videoHoverDiv.hide();
+ controlsLeftHoverDiv.hide();
+ controlsRightHoverDiv.hide();
+
+ // restore the control bar
+ fullscreenBtn.css('pointer-events', '');
+ t.controls.css('pointer-events', '');
+
+ // store for later
+ fullscreenIsDisabled = false;
+ }
+ },
+ videoHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
+ controlsLeftHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
+ controlsRightHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
+ positionHoverDivs = function() {
+ var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
+ videoHoverDiv.css(style);
+ controlsLeftHoverDiv.css(style);
+ controlsRightHoverDiv.css(style);
+
+ // over video, but not controls
+ videoHoverDiv
+ .width( t.container.width() )
+ .height( t.container.height() - t.controls.height() );
+
+ // over controls, but not the fullscreen button
+ var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
+ fullScreenBtnWidth = fullscreenBtn.outerWidth(true);
+
+ controlsLeftHoverDiv
+ .width( fullScreenBtnOffset )
+ .height( t.controls.height() )
+ .css({top: t.container.height() - t.controls.height()});
+
+ // after the fullscreen button
+ controlsRightHoverDiv
+ .width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
+ .height( t.controls.height() )
+ .css({top: t.container.height() - t.controls.height(),
+ left: fullScreenBtnOffset + fullScreenBtnWidth});
+ };
+
+ $(document).resize(function() {
+ positionHoverDivs();
+ });
+
+ // on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
+ fullscreenBtn
+ .mouseover(function() {
+
+ if (!t.isFullScreen) {
+
+ var buttonPos = fullscreenBtn.offset(),
+ containerPos = player.container.offset();
+
+ // move the button in Flash into place
+ media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);
+
+ // allows click through
+ fullscreenBtn.css('pointer-events', 'none');
+ t.controls.css('pointer-events', 'none');
+
+ // show the divs that will restore things
+ videoHoverDiv.show();
+ controlsRightHoverDiv.show();
+ controlsLeftHoverDiv.show();
+ positionHoverDivs();
+
+ fullscreenIsDisabled = true;
+ }
+
+ });
+
+ // restore controls anytime the user enters or leaves fullscreen
+ media.addEventListener('fullscreenchange', function(e) {
+ restoreControls();
+ });
+
+
+ // the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
+ // so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
+ /*
+ $(document).mousemove(function(e) {
+
+ // if the mouse is anywhere but the fullsceen button, then restore it all
+ if (fullscreenIsDisabled) {
+
+ var fullscreenBtnPos = fullscreenBtn.offset();
+
+
+ if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
+ e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
+ ) {
+
+ fullscreenBtn.css('pointer-events', '');
+ t.controls.css('pointer-events', '');
+
+ fullscreenIsDisabled = false;
+ }
+ }
+ });
+ */
+
+
+ } else {
+
+ // the hover state will show the fullscreen button in Flash to hover up and click
+
+ fullscreenBtn
+ .mouseover(function() {
+
+ if (hideTimeout !== null) {
+ clearTimeout(hideTimeout);
+ delete hideTimeout;
+ }
+
+ var buttonPos = fullscreenBtn.offset(),
+ containerPos = player.container.offset();
+
+ media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);
+
+ })
+ .mouseout(function() {
+
+ if (hideTimeout !== null) {
+ clearTimeout(hideTimeout);
+ delete hideTimeout;
+ }
+
+ hideTimeout = setTimeout(function() {
+ media.hideFullscreenButton();
+ }, 1500);
+
+
+ });
+ }
+ }
+
+ player.fullscreenBtn = fullscreenBtn;
+
+ $(document).bind('keydown',function (e) {
+ if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
+ player.exitFullScreen();
+ }
+ });
+
+ },
+ enterFullScreen: function() {
+
+ var t = this;
+
+ // firefox+flash can't adjust plugin sizes without resetting :(
+ if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
+ //t.media.setFullscreen(true);
+ //player.isFullScreen = true;
+ return;
+ }
+
+ // store overflow
+ docStyleOverflow = document.documentElement.style.overflow;
+ // set it to not show scroll bars so 100% will work
+ document.documentElement.style.overflow = 'hidden';
+
+ // store sizing
+ normalHeight = t.container.height();
+ normalWidth = t.container.width();
+
+ // attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
+ if (t.media.pluginType === 'native') {
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
+
+ mejs.MediaFeatures.requestFullScreen(t.container[0]);
+ //return;
+
+ if (t.isInIframe) {
+ // sometimes exiting from fullscreen doesn't work
+ // notably in Chrome <iframe>. Fixed in version 17
+ setTimeout(function checkFullscreen() {
+
+ if (t.isNativeFullScreen) {
+
+ // check if the video is suddenly not really fullscreen
+ if ($(window).width() !== screen.width) {
+ // manually exit
+ t.exitFullScreen();
+ } else {
+ // test again
+ setTimeout(checkFullscreen, 500);
+ }
+ }
+
+
+ }, 500);
+ }
+
+ } else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
+ t.media.webkitEnterFullscreen();
+ return;
+ }
+ }
+
+ // check for iframe launch
+ if (t.isInIframe) {
+ var url = t.options.newWindowCallback(this);
+
+
+ if (url !== '') {
+
+ // launch immediately
+ if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
+ t.pause();
+ window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
+ return;
+ } else {
+ setTimeout(function() {
+ if (!t.isNativeFullScreen) {
+ t.pause();
+ window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
+ }
+ }, 250);
+ }
+ }
+
+ }
+
+ // full window code
+
+
+
+ // make full size
+ t.container
+ .addClass('mejs-container-fullscreen')
+ .width('100%')
+ .height('100%');
+ //.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});
+
+ // Only needed for safari 5.1 native full screen, can cause display issues elsewhere
+ // Actually, it seems to be needed for IE8, too
+ //if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
+ setTimeout(function() {
+ t.container.css({width: '100%', height: '100%'});
+ t.setControlsSize();
+ }, 500);
+ //}
+
+ if (t.pluginType === 'native') {
+ t.$media
+ .width('100%')
+ .height('100%');
+ } else {
+ t.container.find('object, embed, iframe')
+ .width('100%')
+ .height('100%');
+
+ //if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
+ t.media.setVideoSize($(window).width(),$(window).height());
+ //}
+ }
+
+ t.layers.children('div')
+ .width('100%')
+ .height('100%');
+
+ if (t.fullscreenBtn) {
+ t.fullscreenBtn
+ .removeClass('mejs-fullscreen')
+ .addClass('mejs-unfullscreen');
+ }
+
+ t.setControlsSize();
+ t.isFullScreen = true;
+ },
+
+ exitFullScreen: function() {
+
+ var t = this;
+
+ // firefox can't adjust plugins
+ if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
+ t.media.setFullscreen(false);
+ //player.isFullScreen = false;
+ return;
+ }
+
+ // come outo of native fullscreen
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
+ mejs.MediaFeatures.cancelFullScreen();
+ }
+
+ // restore scroll bars to document
+ document.documentElement.style.overflow = docStyleOverflow;
+
+ t.container
+ .removeClass('mejs-container-fullscreen')
+ .width(normalWidth)
+ .height(normalHeight);
+ //.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});
+
+ if (t.pluginType === 'native') {
+ t.$media
+ .width(normalWidth)
+ .height(normalHeight);
+ } else {
+ t.container.find('object embed')
+ .width(normalWidth)
+ .height(normalHeight);
+
+ t.media.setVideoSize(normalWidth, normalHeight);
+ }
+
+ t.layers.children('div')
+ .width(normalWidth)
+ .height(normalHeight);
+
+ t.fullscreenBtn
+ .removeClass('mejs-unfullscreen')
+ .addClass('mejs-fullscreen');
+
+ t.setControlsSize();
+ t.isFullScreen = false;
+ }
+ });
+
+})(mejs.$);
+
(function($) {
// add extra default options
$.extend(mejs.MepDefaults, {
// this will automatically turn on a <track>
@@ -2150,16 +2178,16 @@
//});
if (!player.options.alwaysShowControls) {
// move with controls
player.container
- .bind('mouseenter', function () {
+ .bind('controlsshown', function () {
// push captions above controls
player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
})
- .bind('mouseleave', function () {
+ .bind('controlshidden', function () {
if (!media.paused) {
// move back to normal place
player.container.find('.mejs-captions-position').removeClass('mejs-captions-position-hover');
}
});
@@ -2241,39 +2269,37 @@
t.loadNextTrack();
};
- if (track.isTranslation) {
- // translate the first track
- mejs.TrackFormatParser.translateTrackText(t.tracks[0].entries, t.tracks[0].srclang, track.srclang, t.options.googleApiKey, function(newOne) {
+ $.ajax({
+ url: track.src,
+ dataType: "text",
+ success: function(d) {
- // store the new translation
- track.entries = newOne;
-
+ // parse the loaded file
+ if (typeof d == "string" && (/<tt\s+xml/ig).exec(d)) {
+ track.entries = mejs.TrackFormatParser.dfxp.parse(d);
+ } else {
+ track.entries = mejs.TrackFormatParser.webvvt.parse(d);
+ }
+
after();
- });
- } else {
- $.ajax({
- url: track.src,
- success: function(d) {
-
- // parse the loaded file
- track.entries = mejs.TrackFormatParser.parse(d);
- after();
-
- if (track.kind == 'chapters' && t.media.duration > 0) {
- t.drawChapters(track);
- }
- },
- error: function() {
- t.loadNextTrack();
+ if (track.kind == 'chapters') {
+ t.media.addEventListener('play', function(e) {
+ if (t.media.duration > 0) {
+ t.displayChapters(track);
+ }
+ }, false);
}
- });
- }
+ },
+ error: function() {
+ t.loadNextTrack();
+ }
+ });
},
enableTrackButton: function(lang, label) {
var t = this;
@@ -2487,57 +2513,110 @@
===============================
Adapted from: http://www.delphiki.com/html5/playr
*/
mejs.TrackFormatParser = {
- // match start "chapter-" (or anythingelse)
- pattern_identifier: /^([a-zA-z]+-)?[0-9]+$/,
- pattern_timecode: /^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,
+ webvvt: {
+ // match start "chapter-" (or anythingelse)
+ pattern_identifier: /^([a-zA-z]+-)?[0-9]+$/,
+ pattern_timecode: /^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,
- split2: function (text, regex) {
- // normal version for compliant browsers
- // see below for IE fix
- return text.split(regex);
- },
- parse: function(trackText) {
- var
- i = 0,
- lines = this.split2(trackText, /\r?\n/),
- entries = {text:[], times:[]},
- timecode,
- text;
-
- for(; i<lines.length; i++) {
- // check for the line number
- if (this.pattern_identifier.exec(lines[i])){
- // skip to the next line where the start --> end time code should be
- i++;
- timecode = this.pattern_timecode.exec(lines[i]);
-
- if (timecode && i<lines.length){
+ parse: function(trackText) {
+ var
+ i = 0,
+ lines = mejs.TrackFormatParser.split2(trackText, /\r?\n/),
+ entries = {text:[], times:[]},
+ timecode,
+ text;
+ for(; i<lines.length; i++) {
+ // check for the line number
+ if (this.pattern_identifier.exec(lines[i])){
+ // skip to the next line where the start --> end time code should be
i++;
- // grab all the (possibly multi-line) text that follows
- text = lines[i];
- i++;
- while(lines[i] !== '' && i<lines.length){
- text = text + '\n' + lines[i];
+ timecode = this.pattern_timecode.exec(lines[i]);
+
+ if (timecode && i<lines.length){
i++;
+ // grab all the (possibly multi-line) text that follows
+ text = lines[i];
+ i++;
+ while(lines[i] !== '' && i<lines.length){
+ text = text + '\n' + lines[i];
+ i++;
+ }
+ text = $.trim(text).replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, "<a href='$1' target='_blank'>$1</a>");
+ // Text is in a different array so I can use .join
+ entries.text.push(text);
+ entries.times.push(
+ {
+ start: (mejs.Utility.convertSMPTEtoSeconds(timecode[1]) == 0) ? 0.200 : mejs.Utility.convertSMPTEtoSeconds(timecode[1]),
+ stop: mejs.Utility.convertSMPTEtoSeconds(timecode[3]),
+ settings: timecode[5]
+ });
}
-
- // Text is in a different array so I can use .join
- entries.text.push(text);
- entries.times.push(
- {
- start: mejs.Utility.timeCodeToSeconds(timecode[1]),
- stop: mejs.Utility.timeCodeToSeconds(timecode[3]),
- settings: timecode[5]
- });
}
}
+ return entries;
}
+ },
+ // Thanks to Justin Capella: https://github.com/johndyer/mediaelement/pull/420
+ dfxp: {
+ parse: function(trackText) {
+ trackText = $(trackText).filter("tt");
+ var
+ i = 0,
+ container = trackText.children("div").eq(0),
+ lines = container.find("p"),
+ styleNode = trackText.find("#" + container.attr("style")),
+ styles,
+ begin,
+ end,
+ text,
+ entries = {text:[], times:[]};
- return entries;
+
+ if (styleNode.length) {
+ var attributes = styleNode.removeAttr("id").get(0).attributes;
+ if (attributes.length) {
+ styles = {};
+ for (i = 0; i < attributes.length; i++) {
+ styles[attributes[i].name.split(":")[1]] = attributes[i].value;
+ }
+ }
+ }
+
+ for(i = 0; i<lines.length; i++) {
+ var style;
+ var _temp_times = {
+ start: null,
+ stop: null,
+ style: null
+ };
+ if (lines.eq(i).attr("begin")) _temp_times.start = mejs.Utility.convertSMPTEtoSeconds(lines.eq(i).attr("begin"));
+ if (!_temp_times.start && lines.eq(i-1).attr("end")) _temp_times.start = mejs.Utility.convertSMPTEtoSeconds(lines.eq(i-1).attr("end"));
+ if (lines.eq(i).attr("end")) _temp_times.stop = mejs.Utility.convertSMPTEtoSeconds(lines.eq(i).attr("end"));
+ if (!_temp_times.stop && lines.eq(i+1).attr("begin")) _temp_times.stop = mejs.Utility.convertSMPTEtoSeconds(lines.eq(i+1).attr("begin"));
+ if (styles) {
+ style = "";
+ for (var _style in styles) {
+ style += _style + ":" + styles[_style] + ";";
+ }
+ }
+ if (style) _temp_times.style = style;
+ if (_temp_times.start == 0) _temp_times.start = 0.200;
+ entries.times.push(_temp_times);
+ text = $.trim(lines.eq(i).html()).replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, "<a href='$1' target='_blank'>$1</a>");
+ entries.text.push(text);
+ if (entries.times.start == 0) entries.times.start = 2;
+ }
+ return entries;
+ }
+ },
+ split2: function (text, regex) {
+ // normal version for compliant browsers
+ // see below for IE fix
+ return text.split(regex);
}
};
// test for browsers with bad String.split method.
if ('x\n\ny'.split(/\n/gi).length != 3) {
@@ -2560,198 +2639,233 @@
}
}
})(mejs.$);
-/*
-* ContextMenu Plugin
-*
-*
-*/
-
-(function($) {
-
-$.extend(mejs.MepDefaults,
- { 'contextMenuItems': [
- // demo of a fullscreen option
- {
- render: function(player) {
-
- // check for fullscreen plugin
- if (typeof player.enterFullScreen == 'undefined')
- return null;
-
- if (player.isFullScreen) {
- return "Turn off Fullscreen";
- } else {
- return "Go Fullscreen";
- }
- },
- click: function(player) {
- if (player.isFullScreen) {
- player.exitFullScreen();
- } else {
- player.enterFullScreen();
- }
- }
- }
- ,
- // demo of a mute/unmute button
- {
- render: function(player) {
- if (player.media.muted) {
- return "Unmute";
- } else {
- return "Mute";
- }
- },
- click: function(player) {
- if (player.media.muted) {
- player.setMuted(false);
- } else {
- player.setMuted(true);
- }
- }
- },
- // separator
- {
- isSeparator: true
- }
- ,
- // demo of simple download video
- {
- render: function(player) {
- return "Download Video";
- },
- click: function(player) {
- window.location.href = player.media.currentSrc;
- }
- }
- ]}
-);
-
-
- $.extend(MediaElementPlayer.prototype, {
- buildcontextmenu: function(player, controls, layers, media) {
-
- // create context menu
- player.contextMenu = $('<div class="mejs-contextmenu"></div>')
- .appendTo($('body'))
- .hide();
-
- // create events for showing context menu
- player.container.bind('contextmenu', function(e) {
- if (player.isContextMenuEnabled) {
- e.preventDefault();
- player.renderContextMenu(e.clientX-1, e.clientY-1);
- return false;
- }
- });
- player.container.bind('click', function() {
- player.contextMenu.hide();
- });
- player.contextMenu.bind('mouseleave', function() {
-
- //console.log('context hover out');
- player.startContextMenuTimer();
-
- });
- },
-
- isContextMenuEnabled: true,
- enableContextMenu: function() {
- this.isContextMenuEnabled = true;
- },
- disableContextMenu: function() {
- this.isContextMenuEnabled = false;
- },
-
- contextMenuTimeout: null,
- startContextMenuTimer: function() {
- //console.log('startContextMenuTimer');
-
- var t = this;
-
- t.killContextMenuTimer();
-
- t.contextMenuTimer = setTimeout(function() {
- t.hideContextMenu();
- t.killContextMenuTimer();
- }, 750);
- },
- killContextMenuTimer: function() {
- var timer = this.contextMenuTimer;
-
- //console.log('killContextMenuTimer', timer);
-
- if (timer != null) {
- clearTimeout(timer);
- delete timer;
- timer = null;
- }
- },
-
- hideContextMenu: function() {
- this.contextMenu.hide();
- },
-
- renderContextMenu: function(x,y) {
-
- // alway re-render the items so that things like "turn fullscreen on" and "turn fullscreen off" are always written correctly
- var t = this,
- html = '',
- items = t.options.contextMenuItems;
-
- for (var i=0, il=items.length; i<il; i++) {
-
- if (items[i].isSeparator) {
- html += '<div class="mejs-contextmenu-separator"></div>';
- } else {
-
- var rendered = items[i].render(t);
-
- // render can return null if the item doesn't need to be used at the moment
- if (rendered != null) {
- html += '<div class="mejs-contextmenu-item" data-itemindex="' + i + '" id="element-' + (Math.random()*1000000) + '">' + rendered + '</div>';
- }
- }
- }
-
- // position and show the context menu
- t.contextMenu
- .empty()
- .append($(html))
- .css({top:y, left:x})
- .show();
-
- // bind events
- t.contextMenu.find('.mejs-contextmenu-item').each(function() {
-
- // which one is this?
- var $dom = $(this),
- itemIndex = parseInt( $dom.data('itemindex'), 10 ),
- item = t.options.contextMenuItems[itemIndex];
-
- // bind extra functionality?
- if (typeof item.show != 'undefined')
- item.show( $dom , t);
-
- // bind click action
- $dom.click(function() {
- // perform click action
- if (typeof item.click != 'undefined')
- item.click(t);
-
- // close
- t.contextMenu.hide();
- });
- });
-
- // stop the controls from hiding
- setTimeout(function() {
- t.killControlsTimer('rev3');
- }, 100);
-
- }
- });
-
+/*
+* ContextMenu Plugin
+*
+*
+*/
+
+(function($) {
+
+$.extend(mejs.MepDefaults,
+ { 'contextMenuItems': [
+ // demo of a fullscreen option
+ {
+ render: function(player) {
+
+ // check for fullscreen plugin
+ if (typeof player.enterFullScreen == 'undefined')
+ return null;
+
+ if (player.isFullScreen) {
+ return "Turn off Fullscreen";
+ } else {
+ return "Go Fullscreen";
+ }
+ },
+ click: function(player) {
+ if (player.isFullScreen) {
+ player.exitFullScreen();
+ } else {
+ player.enterFullScreen();
+ }
+ }
+ }
+ ,
+ // demo of a mute/unmute button
+ {
+ render: function(player) {
+ if (player.media.muted) {
+ return "Unmute";
+ } else {
+ return "Mute";
+ }
+ },
+ click: function(player) {
+ if (player.media.muted) {
+ player.setMuted(false);
+ } else {
+ player.setMuted(true);
+ }
+ }
+ },
+ // separator
+ {
+ isSeparator: true
+ }
+ ,
+ // demo of simple download video
+ {
+ render: function(player) {
+ return "Download Video";
+ },
+ click: function(player) {
+ window.location.href = player.media.currentSrc;
+ }
+ }
+ ]}
+);
+
+
+ $.extend(MediaElementPlayer.prototype, {
+ buildcontextmenu: function(player, controls, layers, media) {
+
+ // create context menu
+ player.contextMenu = $('<div class="mejs-contextmenu"></div>')
+ .appendTo($('body'))
+ .hide();
+
+ // create events for showing context menu
+ player.container.bind('contextmenu', function(e) {
+ if (player.isContextMenuEnabled) {
+ e.preventDefault();
+ player.renderContextMenu(e.clientX-1, e.clientY-1);
+ return false;
+ }
+ });
+ player.container.bind('click', function() {
+ player.contextMenu.hide();
+ });
+ player.contextMenu.bind('mouseleave', function() {
+
+ //console.log('context hover out');
+ player.startContextMenuTimer();
+
+ });
+ },
+
+ isContextMenuEnabled: true,
+ enableContextMenu: function() {
+ this.isContextMenuEnabled = true;
+ },
+ disableContextMenu: function() {
+ this.isContextMenuEnabled = false;
+ },
+
+ contextMenuTimeout: null,
+ startContextMenuTimer: function() {
+ //console.log('startContextMenuTimer');
+
+ var t = this;
+
+ t.killContextMenuTimer();
+
+ t.contextMenuTimer = setTimeout(function() {
+ t.hideContextMenu();
+ t.killContextMenuTimer();
+ }, 750);
+ },
+ killContextMenuTimer: function() {
+ var timer = this.contextMenuTimer;
+
+ //console.log('killContextMenuTimer', timer);
+
+ if (timer != null) {
+ clearTimeout(timer);
+ delete timer;
+ timer = null;
+ }
+ },
+
+ hideContextMenu: function() {
+ this.contextMenu.hide();
+ },
+
+ renderContextMenu: function(x,y) {
+
+ // alway re-render the items so that things like "turn fullscreen on" and "turn fullscreen off" are always written correctly
+ var t = this,
+ html = '',
+ items = t.options.contextMenuItems;
+
+ for (var i=0, il=items.length; i<il; i++) {
+
+ if (items[i].isSeparator) {
+ html += '<div class="mejs-contextmenu-separator"></div>';
+ } else {
+
+ var rendered = items[i].render(t);
+
+ // render can return null if the item doesn't need to be used at the moment
+ if (rendered != null) {
+ html += '<div class="mejs-contextmenu-item" data-itemindex="' + i + '" id="element-' + (Math.random()*1000000) + '">' + rendered + '</div>';
+ }
+ }
+ }
+
+ // position and show the context menu
+ t.contextMenu
+ .empty()
+ .append($(html))
+ .css({top:y, left:x})
+ .show();
+
+ // bind events
+ t.contextMenu.find('.mejs-contextmenu-item').each(function() {
+
+ // which one is this?
+ var $dom = $(this),
+ itemIndex = parseInt( $dom.data('itemindex'), 10 ),
+ item = t.options.contextMenuItems[itemIndex];
+
+ // bind extra functionality?
+ if (typeof item.show != 'undefined')
+ item.show( $dom , t);
+
+ // bind click action
+ $dom.click(function() {
+ // perform click action
+ if (typeof item.click != 'undefined')
+ item.click(t);
+
+ // close
+ t.contextMenu.hide();
+ });
+ });
+
+ // stop the controls from hiding
+ setTimeout(function() {
+ t.killControlsTimer('rev3');
+ }, 100);
+
+ }
+ });
+
+})(mejs.$);
+/**
+ * Postroll plugin
+ */
+(function($) {
+
+ $.extend(mejs.MepDefaults, {
+ postrollCloseText: mejs.i18n.t('Close')
+ });
+
+ // Postroll
+ $.extend(MediaElementPlayer.prototype, {
+ buildpostroll: function(player, controls, layers, media) {
+ var
+ t = this,
+ postrollLink = t.container.find('link[rel="postroll"]').attr('href');
+
+ if (typeof postrollLink !== 'undefined') {
+ player.postroll =
+ $('<div class="mejs-postroll-layer mejs-layer"><a class="mejs-postroll-close" onclick="$(this).parent().hide();return false;">' + t.options.postrollCloseText + '</a><div class="mejs-postroll-layer-content"></div></div>').prependTo(layers).hide();
+
+ t.media.addEventListener('ended', function (e) {
+ $.ajax({
+ dataType: 'html',
+ url: postrollLink,
+ success: function (data, textStatus) {
+ layers.find('.mejs-postroll-layer-content').html(data);
+ }
+ });
+ player.postroll.show();
+ }, false);
+ }
+ }
+ });
+
})(mejs.$);