TinyMCE wpView:

- Fix editor undo levels.
- Remove views and markers in the DOM before serialization.
- Unbind views before removing them on hide.
- Empty the content in the timeout, so it doesn't render iframes twice.
Props iseulde. Fixes #31669.
Built from https://develop.svn.wordpress.org/trunk@32022


git-svn-id: http://core.svn.wordpress.org/trunk@32001 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Andrew Ozz 2015-04-04 23:00:26 +00:00
parent a7341b7c3f
commit 0186bbcb95
6 changed files with 93 additions and 62 deletions

View File

@ -87,6 +87,8 @@ window.wp = window.wp || {};
* and creates a new instance for every match. * and creates a new instance for every match.
* *
* @param {String} content The string to scan. * @param {String} content The string to scan.
*
* @return {String} The string with markers.
*/ */
setMarkers: function( content ) { setMarkers: function( content ) {
var pieces = [ { content: content } ], var pieces = [ { content: content } ],
@ -298,11 +300,18 @@ window.wp = window.wp || {};
/** /**
* Renders all view nodes tied to this view instance that are not yet rendered. * 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. * @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 there's nothing to render an no loader needs to be shown, stop.
if ( ! this.loader && ! this.getContent() ) { if ( ! this.loader && ! content ) {
return; return;
} }
@ -312,21 +321,33 @@ window.wp = window.wp || {};
// Replace any left over markers. // Replace any left over markers.
this.replaceMarkers(); this.replaceMarkers();
if ( this.getContent() ) { if ( content ) {
this.setContent( this.getContent(), function( editor, node ) { this.setContent( content, function( editor, node ) {
$( node ).data( 'rendered', true ).trigger( 'wp-mce-view-bind' ); $( node ).data( 'rendered', true );
this.bindNode.call( this, editor, node );
}, force ? null : false ); }, force ? null : false );
} else { } else {
this.setLoader(); this.setLoader();
} }
}, },
/**
* 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. * Unbinds all view nodes tied to this view instance.
* Runs before their content is removed from the DOM. * Runs before their content is removed from the DOM.
*/ */
unbind: function() { unbind: function() {
this.getNodes( function( editor, node ) { this.getNodes( function( editor, node ) {
this.unbindNode.call( this, editor, node );
$( node ).trigger( 'wp-mce-view-unbind' ); $( node ).trigger( 'wp-mce-view-unbind' );
}, true ); }, true );
}, },
@ -447,7 +468,7 @@ window.wp = window.wp || {};
contentNode.innerHTML = ''; contentNode.innerHTML = '';
contentNode.appendChild( _.isString( content ) ? editor.dom.createFragment( content ) : content ); contentNode.appendChild( _.isString( content ) ? editor.dom.createFragment( content ) : content );
callback && callback.apply( this, arguments ); callback && callback.call( this, editor, node, contentNode );
}, rendered ); }, rendered );
} }
}, },
@ -461,30 +482,27 @@ window.wp = window.wp || {};
* @param {Boolean} rendered Only set for (un)rendered nodes. Optional. * @param {Boolean} rendered Only set for (un)rendered nodes. Optional.
*/ */
setIframes: function( head, body, callback, rendered ) { 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 ) { this.getNodes( function( editor, node, content ) {
// Seems Firefox needs a bit of time to insert/set the view nodes, var dom = editor.dom,
styles = '',
bodyClasses = editor.getBody().className || '',
editorHead = editor.getDoc().getElementsByTagName( 'head' )[0],
iframe, iframeDoc, observer, i;
tinymce.each( dom.$( 'link[rel="stylesheet"]', editorHead ), function( link ) {
if ( link.href && link.href.indexOf( 'skins/lightgray/content.min.css' ) === -1 &&
link.href.indexOf( 'skins/wordpress/wp-content.css' ) === -1 ) {
styles += dom.getOuterHTML( link );
}
} );
// Seems the browsers need a bit of time to insert/set the view nodes,
// or the iframe will fail especially when switching Text => Visual. // or the iframe will fail especially when switching Text => Visual.
setTimeout( function() { setTimeout( function() {
var dom = editor.dom,
styles = '',
bodyClasses = editor.getBody().className || '',
iframe, iframeDoc, observer, i;
tinymce.each( dom.$(
'link[rel="stylesheet"]',
editor.getDoc().getElementsByTagName( 'head' )[0]
), function( link ) {
if (
link.href &&
link.href.indexOf( 'skins/lightgray/content.min.css' ) === -1 &&
link.href.indexOf( 'skins/wordpress/wp-content.css' ) === -1
) {
styles += dom.getOuterHTML( link );
}
} );
content.innerHTML = ''; content.innerHTML = '';
iframe = dom.add( content, 'iframe', { iframe = dom.add( content, 'iframe', {
@ -582,7 +600,7 @@ window.wp = window.wp || {};
editor.off( 'wp-body-class-change', classChange ); editor.off( 'wp-body-class-change', classChange );
} ); } );
callback && callback.apply( this, arguments ); callback && callback.call( self, editor, node );
}, 50 ); }, 50 );
}, rendered ); }, rendered );
}, },
@ -664,6 +682,7 @@ window.wp = window.wp || {};
* @param {HTMLElement} node The view node to remove. * @param {HTMLElement} node The view node to remove.
*/ */
remove: function( editor, node ) { remove: function( editor, node ) {
this.unbindNode.call( this, editor, node, $( node ).find( '.wpview-content' ).get( 0 ) );
$( node ).trigger( 'wp-mce-view-unbind' ); $( node ).trigger( 'wp-mce-view-unbind' );
editor.dom.remove( node ); editor.dom.remove( node );
editor.focus(); editor.focus();
@ -728,12 +747,10 @@ window.wp = window.wp || {};
} }
} ); } );
self.content = self.template( { self.render( self.template( {
attachments: attachments, attachments: attachments,
columns: attrs.columns ? parseInt( attrs.columns, 10 ) : wp.media.galleryDefaults.columns columns: attrs.columns ? parseInt( attrs.columns, 10 ) : wp.media.galleryDefaults.columns
} ); } ) );
self.render();
} ) } )
.fail( function( jqXHR, textStatus ) { .fail( function( jqXHR, textStatus ) {
self.setError( textStatus ); self.setError( textStatus );
@ -754,16 +771,13 @@ window.wp = window.wp || {};
} ); } );
} }
wp.ajax.send( this.action, { wp.ajax.post( this.action, {
data: { post_ID: postID,
post_ID: postID, type: this.shortcode.tag,
type: this.shortcode.tag, shortcode: this.shortcode.string()
shortcode: this.shortcode.string()
}
} ) } )
.done( function( response ) { .done( function( response ) {
self.content = response; self.render( response );
self.render();
} ) } )
.fail( function( response ) { .fail( function( response ) {
if ( self.url ) { if ( self.url ) {

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,8 @@
* WordPress View plugin. * WordPress View plugin.
*/ */
tinymce.PluginManager.add( 'wpview', function( editor ) { tinymce.PluginManager.add( 'wpview', function( editor ) {
var selected, var $ = editor.$,
selected,
Env = tinymce.Env, Env = tinymce.Env,
VK = tinymce.util.VK, VK = tinymce.util.VK,
TreeWalker = tinymce.dom.TreeWalker, TreeWalker = tinymce.dom.TreeWalker,
@ -153,13 +154,17 @@ tinymce.PluginManager.add( 'wpview', function( editor ) {
// Remove the content of view wrappers from HTML string // Remove the content of view wrappers from HTML string
function emptyViews( content ) { function emptyViews( content ) {
return content.replace(/<div[^>]+data-wpview-text=\"([^"]+)"[^>]*>[\s\S]+?wpview-selection-after[^>]+>(?:&nbsp;|\u00a0)*<\/p><\/div>/g, '$1' ); content = content.replace( /<div[^>]+data-wpview-text="([^"]+)"[^>]*>[\s\S]+?wpview-selection-after[^>]+>[^<>]*<\/p>\s*<\/div>/g, function( all, match ) {
return '<p>' + window.decodeURIComponent( match ) + '</p>';
});
return content.replace( / data-wpview-marker="[^"]+"/g, '' );
} }
// Prevent adding undo levels on changes inside a view wrapper // Prevent adding undo levels on changes inside a view wrapper
editor.on( 'BeforeAddUndo', function( event ) { editor.on( 'BeforeAddUndo', function( event ) {
if ( event.lastLevel && emptyViews( event.level.content ) === emptyViews( event.lastLevel.content ) ) { if ( event.level.content ) {
event.preventDefault(); event.level.content = emptyViews( event.level.content );
} }
}); });
@ -169,6 +174,10 @@ tinymce.PluginManager.add( 'wpview', function( editor ) {
editor.on( 'BeforeSetContent', function( event ) { editor.on( 'BeforeSetContent', function( event ) {
var node; var node;
if ( ! event.selection ) {
wp.mce.views.unbind();
}
if ( ! event.content ) { if ( ! event.content ) {
return; return;
} }
@ -339,22 +348,30 @@ tinymce.PluginManager.add( 'wpview', function( editor ) {
} }
}); });
editor.on( 'PreProcess', function( event ) { function resetViews( rootNode ) {
// Empty the wpview wrap nodes // Replace view nodes
tinymce.each( editor.dom.select( 'div[data-wpview-text]', event.node ), function( node ) { $( 'div[data-wpview-text]', rootNode ).each( function( i, node ) {
node.textContent = node.innerText = '\u00a0'; var $node = $( node ),
}); text = window.decodeURIComponent( $node.attr( 'data-wpview-text' ) || '' );
});
editor.on( 'PostProcess', function( event ) { if ( text && node.parentNode ) {
if ( event.content ) { $node.replaceWith( $( editor.dom.create('p') ).text( text ) );
event.content = event.content.replace( /<div [^>]*?data-wpview-text="([^"]*)"[^>]*>[\s\S]*?<\/div>/g, function( match, shortcode ) { }
if ( shortcode ) { });
return '<p>' + window.decodeURIComponent( shortcode ) + '</p>';
} // Remove marker attributes
return ''; // If error, remove the view wrapper $( 'p[data-wpview-marker]', rootNode ).attr( 'data-wpview-marker', null );
}); }
}
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( editor.getBody() );
}); });
// Excludes arrow keys, delete, backspace, enter, space bar. // Excludes arrow keys, delete, backspace, enter, space bar.

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '4.2-beta4-32021'; $wp_version = '4.2-beta4-32022';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
@ -18,7 +18,7 @@ $wp_db_version = 31532;
* *
* @global string $tinymce_version * @global string $tinymce_version
*/ */
$tinymce_version = '4109-20150310'; $tinymce_version = '4109-20150404';
/** /**
* Holds the required PHP version * Holds the required PHP version