From ce1c3140ab445b8ecd6b3dd51558b9f584a4758c Mon Sep 17 00:00:00 2001 From: Scott Taylor Date: Wed, 19 Mar 2014 07:01:56 +0000 Subject: [PATCH] Add MCE views for audio and video shortcodes. When the shortcode does not contain a source that supports native playback, just show the filename. * Remove the audio/video shortcode parsing from the `wpgallery` plugin. * Make `mce-view` a dependency of `media-audiovideo` * Introduce `wp.mce.video`, `wp.mce.audio`, `wp.mce.media`, and `wp.mce.media.View` * Rename `wp.media.audio|video.shortcode()` to `wp.media.audio|video.update()` since it is called on Update and returns a `wp.shortcode` object now. * In `wp.mce.View.render()`, fire a `ready` event when the placeholder is being parsed and pass the current node to the event handler. See #27389, #27437. git-svn-id: https://develop.svn.wordpress.org/trunk@27615 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/js/mce-view.js | 14 +- src/wp-includes/js/media-audiovideo.js | 165 +++++++++++++++--- .../js/tinymce/plugins/wpgallery/plugin.js | 33 +--- .../js/tinymce/skins/wordpress/wp-content.css | 66 +++++-- src/wp-includes/media-template.php | 17 ++ src/wp-includes/script-loader.php | 2 +- 6 files changed, 221 insertions(+), 76 deletions(-) diff --git a/src/wp-includes/js/mce-view.js b/src/wp-includes/js/mce-view.js index be2681a06b..73e33c9cfb 100644 --- a/src/wp-includes/js/mce-view.js +++ b/src/wp-includes/js/mce-view.js @@ -31,10 +31,14 @@ window.wp = window.wp || {}; var html = this.getHtml(); // Search all tinymce editor instances and update the placeholders _.each( tinymce.editors, function( editor ) { - var doc; + var doc, self = this; if ( editor.plugins.wpview ) { doc = editor.getDoc(); - $( doc ).find( '[data-wpview-text="' + this.encodedText + '"]' ).html( html ); + $( doc ).find( '[data-wpview-text="' + this.encodedText + '"]' ).each(function (i, elem) { + var node = $( elem ); + node.html( html ); + $( self ).trigger( 'ready', elem ); + }); } }, this ); } @@ -178,7 +182,7 @@ window.wp = window.wp || {}; /** * Refresh views after an update is made - * + * * @param view {object} being refreshed * @param text {string} textual representation of the view */ @@ -204,9 +208,9 @@ window.wp = window.wp || {}; return instances[ encodedText ]; }, - /** + /** * render( scope ) - * + * * Renders any view instances inside a DOM node `scope`. * * View instances are detected by the presence of wrapper elements. diff --git a/src/wp-includes/js/media-audiovideo.js b/src/wp-includes/js/media-audiovideo.js index 173a203ec3..c3e2910655 100644 --- a/src/wp-includes/js/media-audiovideo.js +++ b/src/wp-includes/js/media-audiovideo.js @@ -1,4 +1,4 @@ -/* global _wpMediaViewsL10n */ +/* global _wpMediaViewsL10n, _wpmejsSettings, MediaElementPlayer */ (function ($, _, Backbone) { var media = wp.media, l10n = typeof _wpMediaViewsL10n === 'undefined' ? {} : _wpMediaViewsL10n; @@ -61,7 +61,7 @@ video: ['ogg', 'webm'] }, 'chrome' : { - audio: ['ogg', 'mpeg', 'x-ms-wma'], + audio: ['ogg', 'mpeg'], video: ['ogg', 'webm', 'mp4', 'm4v', 'mpeg'] }, 'ff' : { @@ -227,20 +227,24 @@ return frame; }, - shortcode : function (shortcode) { - var self = this; + update : function (model) { + var self = this, content; - _.each( wp.media.audio.defaults, function( value, key ) { - shortcode[ key ] = self.coerce( shortcode, key ); + _.each( this.defaults, function( value, key ) { + model[ key ] = self.coerce( model, key ); - if ( value === shortcode[ key ] ) { - delete shortcode[ key ]; + if ( value === model[ key ] ) { + delete model[ key ]; } }); - return wp.shortcode.string({ - tag: 'audio', - attrs: shortcode + content = model.content; + delete model.content; + + return new wp.shortcode({ + tag: 'audio', + attrs: model, + content: content }); } }; @@ -283,21 +287,23 @@ return frame; }, - shortcode : function (shortcode) { - var self = this, content = shortcode.content; - delete shortcode.content; + update : function (model) { + var self = this, content; _.each( this.defaults, function( value, key ) { - shortcode[ key ] = self.coerce( shortcode, key ); + model[ key ] = self.coerce( model, key ); - if ( value === shortcode[ key ] ) { - delete shortcode[ key ]; + if ( value === model[ key ] ) { + delete model[ key ]; } }); - return wp.shortcode.string({ - tag: 'video', - attrs: shortcode, + content = model.content; + delete model.content; + + return new wp.shortcode({ + tag: 'video', + attrs: model, content: content }); } @@ -972,6 +978,125 @@ } } ); + wp.mce.media = { + toView: function( content ) { + var match = wp.shortcode.next( this.shortcode, content ); + + if ( ! match ) { + return; + } + + return { + index: match.index, + content: match.content, + options: { + shortcode: match.shortcode + } + }; + }, + + edit: function( node ) { + var p, + media = wp.media[ this.shortcode ], + self = this, + frame, data; + + wp.media.mixin.pauseAllPlayers(); + + data = window.decodeURIComponent( $( node ).data('wpview-text') ); + frame = media.edit( data ); + frame.on( 'close', function () { + frame.detach(); + } ); + frame.state( self.shortcode + '-details' ).on( 'update', function( selection ) { + var shortcode = wp.media[ self.shortcode ].update( selection ).string(); + $( node ).attr( 'data-wpview-text', window.encodeURIComponent( shortcode ) ); + wp.mce.views.refreshView( self, shortcode ); + frame.detach(); + } ); + frame.open(); + } + }; + + wp.mce.media.View = wp.mce.View.extend({ + initialize: function( options ) { + this.shortcode = options.shortcode; + _.bindAll( this, 'setPlayer' ); + $(this).on( 'ready', this.setPlayer ); + }, + + setPlayer: function (e, node) { + // if the ready event fires on an empty node + if ( ! node ) { + return; + } + + var self = this, + media, + settings = {}, + className = '.wp-' + this.shortcode.tag + '-shortcode'; + + if ( this.player ) { + this.unsetPlayer(); + } + + media = $( node ).find( className ); + + if ( ! _.isUndefined( window._wpmejsSettings ) ) { + settings.pluginPath = _wpmejsSettings.pluginPath; + } + + if ( ! this.isCompatible( media ) ) { + media.closest( '.wpview-wrap' ).addClass( 'wont-play' ); + if ( ! media.parent().hasClass( 'wpview-wrap' ) ) { + media.parent().replaceWith( media ); + } + media.replaceWith( '

' + media.find( 'source' ).eq(0).prop( 'src' ) + '

' ); + return; + } else { + media.closest( '.wpview-wrap' ).removeClass( 'wont-play' ); + if ( this.ua.is( 'ff' ) ) { + media.prop( 'preload', 'metadata' ); + } else { + media.prop( 'preload', 'none' ); + } + } + + media = wp.media.view.MediaDetails.prepareSrc( media.get(0) ); + + // Thanks, Firefox! + setTimeout(function () { + self.player = new MediaElementPlayer( media, settings ); + }, 50); + }, + + getHtml: function() { + var attrs = this.shortcode.attrs.named; + return this.template({ model: attrs }); + } + }); + _.extend( wp.mce.media.View.prototype, wp.media.mixin ); + + wp.mce.video = _.extend( {}, wp.mce.media, { + shortcode: 'video', + View: wp.mce.media.View.extend({ + className: 'editor-video', + template: media.template('editor-video') + }) + } ); + + wp.mce.views.register( 'video', wp.mce.video ); + + wp.mce.audio = _.extend( {}, wp.mce.media, { + shortcode: 'audio', + View: wp.mce.media.View.extend({ + className: 'editor-audio', + template: media.template('editor-audio') + }) + } ); + + wp.mce.views.register( 'audio', wp.mce.audio ); + function init() { $(document.body) .on( 'click', '.wp-switch-editor', wp.media.mixin.pauseAllPlayers ) diff --git a/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js b/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js index d33dbca088..2f0912873b 100644 --- a/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js +++ b/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js @@ -25,8 +25,8 @@ tinymce.PluginManager.add('wpgallery', function( editor ) { } function replaceAVShortcodes( content ) { - var testRegex = /\[(video-playlist|audio|video|playlist)[^\]]*\]/, - replaceRegex = /\[(video-playlist|audio|video|playlist)[^\]]*\]([\s\S]*?\[\/\1\])?/; + var testRegex = /\[(video-playlist|playlist)[^\]]*\]/, + replaceRegex = /\[(video-playlist|playlist)[^\]]*\]([\s\S]*?\[\/\1\])?/; while ( testRegex.test( content ) ) { content = content.replace( replaceRegex, replaceCallback ); @@ -92,31 +92,6 @@ tinymce.PluginManager.add('wpgallery', function( editor ) { editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) ); frame.detach(); }); - } else if ( editor.dom.hasClass( node, 'wp-video' ) ) { - frame = wp.media.video.edit( data ); - frame.on( 'close', function () { - frame.detach(); - } ); - frame.state( 'video-details' ).on( - 'update replace add-source select-poster-image add-track', - function ( selection ) { - var shortcode = wp.media.video.shortcode( selection ); - editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) ); - frame.detach(); - } - ); - frame.open(); - } else if ( editor.dom.hasClass( node, 'wp-audio' ) ) { - frame = wp.media.audio.edit( data ); - frame.on( 'close', function () { - frame.detach(); - } ); - frame.state( 'audio-details' ).on( 'update replace add-source', function ( selection ) { - var shortcode = wp.media.audio.shortcode( selection ); - editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) ); - frame.detach(); - } ); - frame.open(); } else { // temp window.console && window.console.log( 'Edit AV shortcode ' + data ); @@ -177,10 +152,6 @@ tinymce.PluginManager.add('wpgallery', function( editor ) { if ( node.nodeName === 'IMG' && dom.getAttrib( node, 'data-wp-media' ) ) { if ( dom.hasClass( node, 'wp-gallery' ) ) { event.name = 'gallery'; - } else if ( dom.hasClass( node, 'wp-video' ) ) { - event.name = 'video'; - } else if ( dom.hasClass( node, 'wp-audio' ) ) { - event.name = 'audio'; } else if ( dom.hasClass( node, 'wp-playlist' ) ) { event.name = 'playlist'; } else if ( dom.hasClass( node, 'wp-video-playlist' ) ) { diff --git a/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css b/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css index 8e208de1d3..d90dc9386d 100644 --- a/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css +++ b/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css @@ -141,15 +141,6 @@ img::selection { background-image: url(images/gallery.png); } -.mce-content-body img.wp-media.wp-video { - background-image: url(images/video.png); -} - -.mce-content-body img.wp-media.wp-audio { - height: 70px; - background-image: url(images/audio.png); -} - .mce-content-body img.wp-media.wp-playlist { background-image: url("images/playlist-audio.png"); } @@ -223,44 +214,81 @@ embed { } /** - * Gallery preview + * Media previews */ -.wpview-type-gallery { +.wpview-type-gallery, +.wpview-type-audio, +.wpview-type-video { position: relative; margin-bottom: 16px; cursor: pointer; border: 1px solid transparent; } - .wpview-type-gallery:after { +.wpview-type-audio { + padding: 24px 0 0; +} + +.wpview-type-video { + padding: 0; +} + +.wont-play { + padding: 4px 0; +} + +.wont-play p { + font-size: 13px; + line-height: 1.3; + display: block; + width: 70%; + margin: 0 15%; + text-align: center; +} + +.wpview-type-gallery:after { content: ''; display: table; clear: both; } - .wpview-type-gallery.selected { +.wpview-type-gallery.selected, +.wpview-type-audio, +.wpview-type-video { background-color: #f2f8ff; border-color: #777; } -.wpview-type-gallery .toolbar { - position: absolute; - top: 0; - right: 0; - background-color: #333; - color: white; +.wpview-type-gallery .toolbar, +.wpview-type-audio .toolbar, +.wpview-type-video .toolbar { + position: absolute; + top: 0; + right: 0; + background-color: #333; + color: white; display: none; + z-index: 100; } +.wpview-type-video .toolbar div, .wpview-type-gallery .toolbar div, #wp-image-toolbar div { margin: 5px; } +.wpview-type-audio .toolbar div { + margin: 2px 5px; +} + +.wpview-type-audio .toolbar, +.wpview-type-video .toolbar, .wpview-type-gallery.selected .toolbar { display: block; } +.wpview-type-audio .toolbar span, +.wpview-type-video .toolbar span, .wpview-type-gallery .toolbar span { cursor: pointer; } diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php index 0cad787ba3..5cde40b056 100644 --- a/src/wp-includes/media-template.php +++ b/src/wp-includes/media-template.php @@ -961,6 +961,23 @@ function wp_print_media_templates() { <# } ); #> + + + + + add( 'media-views', "/wp-includes/js/media-views$suffix.js", array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement', 'image-edit' ), false, 1 ); $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 ); - $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor' ), false, 1 ); + $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor', 'mce-view' ), false, 1 ); $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models' ), false, 1 ); if ( is_admin() ) {