From 43a8fb1bd206c9f3daa4c11c8382bf99a6e92af8 Mon Sep 17 00:00:00 2001 From: Scott Taylor Date: Fri, 7 Mar 2014 05:51:25 +0000 Subject: [PATCH] Support the `autoplay` attribute, even when the plugin type for a MediaElement instance is Flash. In the media modal, `wp.media.view.VideoDetails` and `wp.media.view.AudioDetails` now extend a unified `wp.media.view.MediaDetails` class which contains all of the player creation and destruction logic. The `remove()` method mimics the `mejs.MediaElementPlayer.remove()` method, but does not re-add the audio/video tag to the DOM. The MEjs method is especially problematic when the tag has `autoplay="true"` and the view has been detached but not destroyed. Fixes #25077. See #27016. git-svn-id: https://develop.svn.wordpress.org/trunk@27450 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/js/media-views.js | 196 ++++++++++-------- .../js/mediaelement/wp-mediaelement.js | 12 +- 2 files changed, 126 insertions(+), 82 deletions(-) diff --git a/src/wp-includes/js/media-views.js b/src/wp-includes/js/media-views.js index 375ad42c05..8d4bf43d00 100644 --- a/src/wp-includes/js/media-views.js +++ b/src/wp-includes/js/media-views.js @@ -6370,7 +6370,7 @@ }); /** - * wp.media.view.AudioDetails + * wp.media.view.MediaDetails * * @contructor * @augments wp.media.view.Settings.AttachmentDisplay @@ -6379,12 +6379,9 @@ * @augments wp.Backbone.View * @augments Backbone.View */ - media.view.AudioDetails = media.view.Settings.AttachmentDisplay.extend({ - className: 'audio-details', - template: media.template('audio-details'), - + media.view.MediaDetails = media.view.Settings.AttachmentDisplay.extend({ initialize: function() { - _.bindAll(this, 'player', 'close'); + _.bindAll(this, 'success', 'close'); this.listenTo( this.controller, 'close', this.close ); @@ -6403,81 +6400,74 @@ }, this.options ); }, - close : function() { - this.mejs.pause(); + prepareSrc : function (media) { + media.src = [ + media.src, + media.src.indexOf('?') > -1 ? '&' : '?', + (new Date()).getTime() + ].join(''); + + return media; }, - player : function (mejs) { + setPlayer : function () { + this.player = false; + }, + + /** + * Override the MediaElement method for removing a player. + * MediaElement tries to pull the audio/video tag out of + * its container and re-add it to the DOM. + */ + remove: function() { + var t = this.player, featureIndex, feature; + + // invoke features cleanup + for ( featureIndex in t.options.features ) { + feature = t.options.features[featureIndex]; + if ( t['clean' + feature] ) { + try { + t['clean' + feature](t); + } catch (e) {} + } + } + + if ( ! t.isDynamic ) { + t.$node.remove(); + } + + if ( 'native' !== t.media.pluginType ) { + t.media.remove(); + } + + delete mejs.players[t.id]; + + t.container.remove(); + t.globalUnbind(); + delete t.node.player; + }, + + close : function() { + if ( this.player ) { + this.mejs.pause(); + this.remove(); + } + }, + + success : function (mejs) { + var autoplay = mejs.attributes.autoplay && 'false' !== mejs.attributes.autoplay; + + if ( 'flash' === mejs.pluginType && autoplay ) { + mejs.addEventListener( 'canplay', function () { + mejs.play(); + }, false ); + } + this.mejs = mejs; }, render: function() { var self = this, settings = { - success : this.player - }; - - if ( ! _.isUndefined( window._wpmejsSettings ) ) { - settings.pluginPath = _wpmejsSettings.pluginPath; - } - - media.view.Settings.AttachmentDisplay.prototype.render.apply( this, arguments ); - setTimeout( function() { self.resetFocus(); }, 10 ); - - new MediaElementPlayer( this.$('.wp-audio-shortcode').get(0), settings ); - - return this; - }, - - resetFocus: function() { - this.$( '.embed-media-settings' ).scrollTop( 0 ); - } - }); - - /** - * wp.media.view.VideoDetails - * - * @contructor - * @augments wp.media.view.Settings.AttachmentDisplay - * @augments wp.media.view.Settings - * @augments wp.media.View - * @augments wp.Backbone.View - * @augments Backbone.View - */ - media.view.VideoDetails = media.view.Settings.AttachmentDisplay.extend({ - className: 'video-details', - template: media.template('video-details'), - - initialize: function() { - _.bindAll(this, 'success'); - - this.listenTo( this.controller, 'close', this.close ); - - media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments ); - }, - - prepare: function() { - var attachment = false; - - if ( this.model.attachment ) { - attachment = this.model.attachment.toJSON(); - } - return _.defaults({ - model: this.model.toJSON(), - attachment: attachment - }, this.options ); - }, - - close : function() { - this.mejs.pause(); - this.player.remove(); - }, - - success : function (mejs) { - this.mejs = mejs; - }, - - render: function() { - var video, self = this, settings = { success : this.success }; @@ -6488,14 +6478,8 @@ media.view.Settings.AttachmentDisplay.prototype.render.apply( this, arguments ); setTimeout( function() { self.resetFocus(); }, 10 ); - video = this.$('.wp-video-shortcode').get(0); - video.src = [ - video.src, - video.src.indexOf('?') > -1 ? '&' : '?', - (new Date()).getTime() - ].join(''); + this.setPlayer( settings ); - this.player = new MediaElementPlayer( video, settings ); return this; }, @@ -6504,6 +6488,56 @@ } }); + /** + * wp.media.view.AudioDetails + * + * @contructor + * @augments wp.media.view.MediaDetails + * @augments wp.media.view.Settings.AttachmentDisplay + * @augments wp.media.view.Settings + * @augments wp.media.View + * @augments wp.Backbone.View + * @augments Backbone.View + */ + media.view.AudioDetails = media.view.MediaDetails.extend({ + className: 'audio-details', + template: media.template('audio-details'), + + setPlayer: function( settings ) { + var audio = this.$('.wp-audio-shortcode').get(0); + + audio = this.prepareSrc( audio ); + + this.player = new MediaElementPlayer( audio, settings ); + return this; + } + }); + + /** + * wp.media.view.VideoDetails + * + * @contructor + * @augments wp.media.view.MediaDetails + * @augments wp.media.view.Settings.AttachmentDisplay + * @augments wp.media.view.Settings + * @augments wp.media.View + * @augments wp.Backbone.View + * @augments Backbone.View + */ + media.view.VideoDetails = media.view.MediaDetails.extend({ + className: 'video-details', + template: media.template('video-details'), + + setPlayer: function( settings ) { + var video = this.$('.wp-video-shortcode').get(0); + + video = this.prepareSrc( video ); + + this.player = new MediaElementPlayer( video, settings ); + return this; + } + }); + /** * wp.media.view.Spinner * diff --git a/src/wp-includes/js/mediaelement/wp-mediaelement.js b/src/wp-includes/js/mediaelement/wp-mediaelement.js index 505decd040..2e22dc07ce 100644 --- a/src/wp-includes/js/mediaelement/wp-mediaelement.js +++ b/src/wp-includes/js/mediaelement/wp-mediaelement.js @@ -7,8 +7,18 @@ $(function () { var settings = {}; - if ( typeof _wpmejsSettings !== 'undefined' ) + if ( typeof _wpmejsSettings !== 'undefined' ) { settings.pluginPath = _wpmejsSettings.pluginPath; + } + + settings.success = function (mejs) { + var autoplay = mejs.attributes.autoplay && 'false' !== mejs.attributes.autoplay; + if ( 'flash' === mejs.pluginType && autoplay ) { + mejs.addEventListener( 'canplay', function () { + mejs.play(); + }, false ); + } + }; $('.wp-audio-shortcode, .wp-video-shortcode').mediaelementplayer( settings ); });