Index: src/wp-includes/js/mce-view.js =================================================================== --- src/wp-includes/js/mce-view.js (revision 31909) +++ src/wp-includes/js/mce-view.js (working copy) @@ -87,6 +87,8 @@ * and creates a new instance for every match. * * @param {String} content The string to scan. + * + * @return {String} The string with markers. */ setMarkers: function( content ) { var pieces = [ { content: content } ], @@ -298,11 +300,18 @@ /** * Renders all view nodes tied to this view instance that are not yet rendered. * + * @param {String} content The content to render. Optional. * @param {Boolean} force Rerender all view nodes tied to this view instance. */ - render: function( force ) { + render: function( content, force ) { + if ( content != null ) { + this.content = content; + } + + content = this.getContent(); + // If there's nothing to render an no loader needs to be shown, stop. - if ( ! this.loader && ! this.getContent() ) { + if ( ! this.loader && ! content ) { return; } @@ -312,9 +321,10 @@ // Replace any left over markers. this.replaceMarkers(); - if ( this.getContent() ) { - this.setContent( this.getContent(), function( editor, node ) { - $( node ).data( 'rendered', true ).trigger( 'wp-mce-view-bind' ); + if ( content ) { + this.setContent( content, function( editor, node ) { + $( node ).data( 'rendered', true ); + this.bindNode.apply( this, arguments ); }, force ? null : false ); } else { this.setLoader(); @@ -322,11 +332,22 @@ }, /** + * Binds a given node after its content is added to the DOM. + */ + bindNode: function() {}, + + /** + * Unbinds a given node before its content is removed from the DOM. + */ + unbindNode: function() {}, + + /** * Unbinds all view nodes tied to this view instance. * Runs before their content is removed from the DOM. */ unbind: function() { this.getNodes( function( editor, node ) { + this.unbindNode.apply( this, arguments ); $( node ).trigger( 'wp-mce-view-unbind' ); }, true ); }, @@ -461,7 +482,8 @@ * @param {Boolean} rendered Only set for (un)rendered nodes. Optional. */ setIframes: function( head, body, callback, rendered ) { - var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; + var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver, + self = this; this.getNodes( function( editor, node, content ) { // Seems Firefox needs a bit of time to insert/set the view nodes, @@ -582,7 +604,7 @@ editor.off( 'wp-body-class-change', classChange ); } ); - callback && callback.apply( this, arguments ); + callback && callback.apply( self, arguments ); }, 50 ); }, rendered ); }, @@ -663,6 +685,7 @@ * @param {HTMLElement} node The view node to remove. */ remove: function( editor, node ) { + this.unbindNode.call( this, editor, node, $( node ).find( '.wpview-content' ).get( 0 ) ); $( node ).trigger( 'wp-mce-view-unbind' ); editor.dom.remove( node ); } @@ -726,12 +749,10 @@ } } ); - self.content = self.template( { + self.render( self.template( { attachments: attachments, columns: attrs.columns ? parseInt( attrs.columns, 10 ) : wp.media.galleryDefaults.columns - } ); - - self.render(); + } ) ); } ) .fail( function( jqXHR, textStatus ) { self.setError( textStatus ); @@ -752,16 +773,13 @@ } ); } - wp.ajax.send( this.action, { - data: { - post_ID: postID, - type: this.shortcode.tag, - shortcode: this.shortcode.string() - } + wp.ajax.post( this.action, { + post_ID: postID, + type: this.shortcode.tag, + shortcode: this.shortcode.string() } ) .done( function( response ) { - self.content = response; - self.render(); + self.render( response ); } ) .fail( function( response ) { if ( self.url ) { Index: src/wp-includes/js/tinymce/plugins/wpview/plugin.js =================================================================== --- src/wp-includes/js/tinymce/plugins/wpview/plugin.js (revision 31909) +++ src/wp-includes/js/tinymce/plugins/wpview/plugin.js (working copy) @@ -4,7 +4,8 @@ * WordPress View plugin. */ tinymce.PluginManager.add( 'wpview', function( editor ) { - var selected, + var $ = editor.$, + selected, Env = tinymce.Env, VK = tinymce.util.VK, TreeWalker = tinymce.dom.TreeWalker, @@ -153,13 +154,20 @@ // Remove the content of view wrappers from HTML string function emptyViews( content ) { - return content.replace(/
' + decodeURIComponent( arguments[1] ) + '
'; + } + + content = content.replace( /]+data-wpview-marker="([^"]+)"[^>]*>[^<]+<\/p>/g, callback ); + + return content; } // Prevent adding undo levels on changes inside a view wrapper editor.on( 'BeforeAddUndo', function( event ) { - if ( event.lastLevel && emptyViews( event.level.content ) === emptyViews( event.lastLevel.content ) ) { - event.preventDefault(); + if ( event.level.content ) { + event.level.content = emptyViews( event.level.content ); } }); @@ -169,6 +177,10 @@ editor.on( 'BeforeSetContent', function( event ) { var node; + if ( ! event.selection ) { + wp.mce.views.unbind(); + } + if ( ! event.content ) { return; } @@ -335,22 +347,32 @@ } }); - editor.on( 'PreProcess', function( event ) { - // Empty the wpview wrap nodes - tinymce.each( editor.dom.select( 'div[data-wpview-text]', event.node ), function( node ) { - node.textContent = node.innerText = '\u00a0'; - }); - }); + function resetViews( context ) { + tinymce.each( [ + 'data-wpview-text', + 'data-wpview-marker' + ], function( attr ) { + $( '[' + attr + ']', context ).each( function() { + var $this = $( this ); + + $this.replaceWith( + $( document.createElement( 'P' ) ).text( + decodeURIComponent( $this.attr( attr ) ) + ) + ); + } ); + } ); + } - editor.on( 'PostProcess', function( event ) { - if ( event.content ) { - event.content = event.content.replace( /
' + window.decodeURIComponent( shortcode ) + '
'; - } - return ''; // If error, remove the view wrapper - }); - } + editor.on( 'PreProcess', function( event ) { + // Replace the view nodes with their text in the DOM clone. + resetViews( event.node ); + }, true ); + + editor.on( 'hide', function() { + // Replace the view nodes with their text directly in the editor body. + wp.mce.views.unbind(); + resetViews(); }); // Excludes arrow keys, delete, backspace, enter, space bar.