From 63980b7cf36595929552f54f964b65a1725c7e6a Mon Sep 17 00:00:00 2001 From: Andrew Ozz Date: Tue, 26 Jul 2016 23:12:14 +0000 Subject: [PATCH] TinyMCE, wpView: - Add the `wpview-wrap` class and pass third param to the getNodes() callback for back-compat. - Attach the mutation observer that resizes a view iframe inside the iframe to minimize memory use/leaks. - Remove the `wp-mce-view-unbind` event. It has never been particularly reliable and now it doesn't fire when the user deletes a view by typing or pasting over it. - Restore changing of a view iframe body classes when the editor body classes change. Props iseulde, azaozz. Fixes #36434. git-svn-id: https://develop.svn.wordpress.org/trunk@38158 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/js/mce-view.js | 33 +++++-------------- .../js/tinymce/plugins/wpview/plugin.js | 29 ++++++++++++++++ 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/wp-includes/js/mce-view.js b/src/wp-includes/js/mce-view.js index 10e33cc3b0..3d2616d785 100644 --- a/src/wp-includes/js/mce-view.js +++ b/src/wp-includes/js/mce-view.js @@ -353,7 +353,6 @@ unbind: function() { this.getNodes( function( editor, node ) { this.unbindNode.call( this, editor, node ); - $( node ).trigger( 'wp-mce-view-unbind' ); }, true ); }, @@ -394,7 +393,7 @@ return rendered ? data : ! data; } ) .each( function() { - callback.call( self, editor, this ); + callback.call( self, editor, this, this /* back compat */ ); } ); } ); }, @@ -429,7 +428,7 @@ } $viewNode = editor.$( - '
' + '
' ); editor.$( node ).replaceWith( $viewNode ); @@ -485,8 +484,7 @@ * @param {Boolean} rendered Only set for (un)rendered nodes. Optional. */ setIframes: function( head, body, callback, rendered ) { - var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver, - self = this; + var self = this; this.getNodes( function( editor, node ) { var dom = editor.dom, @@ -516,7 +514,7 @@ // Seems the browsers need a bit of time to insert/set the view nodes, // or the iframe will fail especially when switching Text => Visual. setTimeout( function() { - var iframe, iframeDoc, observer, i, block; + var iframe, iframeWin, iframeDoc, MutationObserver, observer, i, block; editor.undoManager.transact( function() { node.innerHTML = ''; @@ -547,8 +545,8 @@ return; } - iframeDoc = iframe.contentWindow.document; - + iframeWin = iframe.contentWindow; + iframeDoc = iframeWin.document; iframeDoc.open(); iframeDoc.write( @@ -612,7 +610,9 @@ }, 3000 ); } - $( iframe.contentWindow ).on( 'load', resize ); + $( iframeWin ).on( 'load', resize ); + + MutationObserver = iframeWin.MutationObserver || iframeWin.WebKitMutationObserver || iframeWin.MozMutationObserver; if ( MutationObserver ) { observer = new MutationObserver( _.debounce( resize, 100 ) ); @@ -622,26 +622,12 @@ childList: true, subtree: true } ); - - $( node ).one( 'wp-mce-view-unbind', function() { - observer.disconnect(); - } ); } else { for ( i = 1; i < 6; i++ ) { setTimeout( resize, i * 700 ); } } - function classChange() { - iframeDoc.body.className = editor.getBody().className; - } - - editor.on( 'wp-body-class-change', classChange ); - - $( node ).one( 'wp-mce-view-unbind', function() { - editor.off( 'wp-body-class-change', classChange ); - } ); - callback && callback.call( self, editor, node ); }, 50 ); }, rendered ); @@ -726,7 +712,6 @@ */ remove: function( editor, node ) { this.unbindNode.call( this, editor, node ); - $( node ).trigger( 'wp-mce-view-unbind' ); editor.dom.remove( node ); editor.focus(); } diff --git a/src/wp-includes/js/tinymce/plugins/wpview/plugin.js b/src/wp-includes/js/tinymce/plugins/wpview/plugin.js index 0202816db9..2fc0e4b3d8 100644 --- a/src/wp-includes/js/tinymce/plugins/wpview/plugin.js +++ b/src/wp-includes/js/tinymce/plugins/wpview/plugin.js @@ -31,6 +31,35 @@ .replace( /]+data-wpview-marker="([^"]+)"[^>]*>[\s\S]*?<\/p>/g, callback ); } + editor.on( 'init', function() { + var MutationObserver = window.MutationObserver || window.WebKitMutationObserver; + + if ( MutationObserver ) { + new MutationObserver( function() { + editor.fire( 'wp-body-class-change' ); + } ) + .observe( editor.getBody(), { + attributes: true, + attributeFilter: ['class'] + } ); + } + + // Pass on body class name changes from the editor to the wpView iframes. + editor.on( 'wp-body-class-change', function() { + var className = editor.getBody().className; + + editor.$( 'iframe[class="wpview-sandbox"]' ).each( function( i, iframe ) { + // Make sure it is a local iframe + // jshint scripturl: true + if ( ! iframe.src || iframe.src === 'javascript:""' ) { + try { + iframe.contentWindow.document.body.className = className; + } catch( er ) {} + } + }); + } ); + }); + // Scan new content for matching view patterns and replace them with markers. editor.on( 'beforesetcontent', function( event ) { var node;