Index: src/wp-includes/js/mce-view.js =================================================================== --- src/wp-includes/js/mce-view.js (revision 27532) +++ src/wp-includes/js/mce-view.js (working copy) @@ -1,4 +1,4 @@ -/* global tinymce */ +/* global tinymce, _wpmejsSettings, MediaElementPlayer */ // Ensure the global `wp` object exists. window.wp = window.wp || {}; @@ -31,10 +31,14 @@ 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 @@ /** * Refresh views after an update is made - * + * * @param view {object} being refreshed * @param text {string} textual representation of the view */ @@ -204,9 +208,9 @@ return instances[ encodedText ]; }, - /** + /** * render( scope ) - * + * * Renders any view instances inside a DOM node `scope`. * * View instances are detected by the presence of wrapper elements. @@ -302,4 +306,119 @@ }; wp.mce.views.register( 'gallery', wp.mce.gallery ); + + 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' ); + media.prop( 'preload', 'none' ); + } + + media = wp.media.view.MediaDetails.prepareSrc( media.get(0) ); + + // Thanks, Firefox! + setTimeout(function () { + self.player = new MediaElementPlayer( media, settings ); + }, 10); + }, + + 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 ); }(jQuery)); Index: src/wp-includes/js/media-editor.js =================================================================== --- src/wp-includes/js/media-editor.js (revision 27539) +++ src/wp-includes/js/media-editor.js (working copy) @@ -328,7 +328,7 @@ if ( isOpera ) { opera = false; media.find( 'source' ).each(function (i, elem) { - if ( elem.type.match(/video\/(ogv|webm)/gi) !== null || + if ( elem.type.match(/video\/(ogg|webm)/gi) !== null || ( elem.type.match(/audio\/(ogg|wav)/gi) !== null ) ) { opera = true; } @@ -705,20 +705,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 }); } }; @@ -757,21 +761,24 @@ return frame; }, - shortcode : function (shortcode) { - var self = this, content = shortcode.content; - delete shortcode.content; + update : function (model) { + var self = this, content = model.content; + delete model.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 }); } Index: src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js =================================================================== --- src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js (revision 27532) +++ src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js (working copy) @@ -25,8 +25,8 @@ } 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 @@ 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 @@ 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' ) ) { Index: src/wp-includes/js/tinymce/skins/wordpress/wp-content.css =================================================================== --- src/wp-includes/js/tinymce/skins/wordpress/wp-content.css (revision 27534) +++ src/wp-includes/js/tinymce/skins/wordpress/wp-content.css (working copy) @@ -242,9 +242,11 @@ } /** - * Gallery preview + * Media previews */ -.wpview-type-gallery { +.wpview-type-gallery, +.wpview-type-audio, +.wpview-type-video { position: relative; padding: 0 0 12px; margin-bottom: 16px; @@ -251,7 +253,25 @@ cursor: pointer; } - .wpview-type-gallery:after { +.wpview-type-audio { + padding: 32px 0 0; +} + +.wpview-type-video { + padding: 16px 0 0; +} + +.wont-play { + padding: 8px 0; +} + +.wont-play p { + display: block; + width: 80%; + margin: 0 5% 0 15%; +} + +.wpview-type-gallery:after { content: ''; display: block; height: 0; @@ -259,11 +279,15 @@ visibility: hidden; } - .wpview-type-gallery.selected { +.wpview-type-gallery.selected, +.wpview-type-audio, +.wpview-type-video { background-color: #efefef; } -.wpview-type-gallery .toolbar { +.wpview-type-gallery .toolbar, +.wpview-type-audio .toolbar, +.wpview-type-video .toolbar { position: absolute; top: 0; left: 0; @@ -271,12 +295,17 @@ color: white; padding: 4px; display: none; + z-index: 100; } +.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; } Index: src/wp-includes/media-template.php =================================================================== --- src/wp-includes/media-template.php (revision 27533) +++ src/wp-includes/media-template.php (working copy) @@ -927,6 +927,23 @@ <# } ); #> + + + + +