Update mce-view.js and the wpview TinyMCE plugin, and use them to show gallery previews in the Visual editor, props gcorne, see #26959
Built from https://develop.svn.wordpress.org/trunk@27408 git-svn-id: http://core.svn.wordpress.org/trunk@27255 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
@@ -2,190 +2,366 @@
|
||||
/**
|
||||
* WordPress View plugin.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var VK = tinymce.VK,
|
||||
tinymce.PluginManager.add( 'wpview', function( editor ) {
|
||||
var selected,
|
||||
VK = tinymce.util.VK,
|
||||
TreeWalker = tinymce.dom.TreeWalker,
|
||||
selected;
|
||||
toRemove = false;
|
||||
|
||||
tinymce.create('tinymce.plugins.wpView', {
|
||||
init : function( editor ) {
|
||||
var wpView = this;
|
||||
|
||||
// Check if the `wp.mce` API exists.
|
||||
if ( typeof wp === 'undefined' || ! wp.mce ) {
|
||||
return;
|
||||
function getParentView( node ) {
|
||||
while ( node && node.nodeName !== 'BODY' ) {
|
||||
if ( isView( node ) ) {
|
||||
return node;
|
||||
}
|
||||
|
||||
editor.on( 'PreInit', function() {
|
||||
// Add elements so we can set `contenteditable` to false.
|
||||
editor.schema.addValidElements('div[*],span[*]');
|
||||
});
|
||||
node = node.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
// When the editor's content changes, scan the new content for
|
||||
// matching view patterns, and transform the matches into
|
||||
// view wrappers. Since the editor's DOM is outdated at this point,
|
||||
// we'll wait to render the views.
|
||||
editor.on( 'BeforeSetContent', function( e ) {
|
||||
if ( ! e.content ) {
|
||||
return;
|
||||
}
|
||||
function isView( node ) {
|
||||
return node && /\bwpview-wrap\b/.test( node.className );
|
||||
}
|
||||
|
||||
e.content = wp.mce.view.toViews( e.content );
|
||||
});
|
||||
function createPadNode() {
|
||||
return editor.dom.create( 'p', { 'data-wpview-pad': 1 },
|
||||
( tinymce.Env.ie && tinymce.Env.ie < 11 ) ? '' : '<br data-mce-bogus="1" />' );
|
||||
}
|
||||
|
||||
// When the editor's content has been updated and the DOM has been
|
||||
// processed, render the views in the document.
|
||||
editor.on( 'SetContent', function() {
|
||||
wp.mce.view.render( editor.getDoc() );
|
||||
});
|
||||
/**
|
||||
* Get the text/shortcode string for a view.
|
||||
*
|
||||
* @param view The view wrapper's HTML id or node
|
||||
* @returns string The text/shoercode string of the view
|
||||
*/
|
||||
function getViewText( view ) {
|
||||
view = getParentView( typeof view === 'string' ? editor.dom.get( view ) : view );
|
||||
|
||||
editor.on( 'init', function() {
|
||||
var selection = editor.selection;
|
||||
// When a view is selected, ensure content that is being pasted
|
||||
// or inserted is added to a text node (instead of the view).
|
||||
editor.on( 'BeforeSetContent', function() {
|
||||
var walker, target,
|
||||
view = wpView.getParentView( selection.getNode() );
|
||||
if ( view ) {
|
||||
return window.decodeURIComponent( editor.dom.getAttrib( view, 'data-wpview-text' ) || '' );
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// If the selection is not within a view, bail.
|
||||
if ( ! view ) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Set the view's original text/shortcode string
|
||||
*
|
||||
* @param view The view wrapper's HTML id or node
|
||||
* @param text The text string to be set
|
||||
*/
|
||||
function setViewText( view, text ) {
|
||||
view = getParentView( typeof view === 'string' ? editor.dom.get( view ) : view );
|
||||
|
||||
// If there are no additional nodes or the next node is a
|
||||
// view, create a text node after the current view.
|
||||
if ( ! view.nextSibling || wpView.isView( view.nextSibling ) ) {
|
||||
target = editor.getDoc().createTextNode('');
|
||||
editor.dom.insertAfter( target, view );
|
||||
if ( view ) {
|
||||
editor.dom.setAttrib( view, 'data-wpview-text', window.encodeURIComponent( text || '' ) );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, find the next text node.
|
||||
} else {
|
||||
walker = new TreeWalker( view.nextSibling, view.nextSibling );
|
||||
target = walker.next();
|
||||
}
|
||||
function _stop( event ) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
// Select the `target` text node.
|
||||
selection.select( target );
|
||||
selection.collapse( true );
|
||||
});
|
||||
function select( viewNode ) {
|
||||
var clipboard,
|
||||
dom = editor.dom;
|
||||
|
||||
// When the selection's content changes, scan any new content
|
||||
// for matching views and immediately render them.
|
||||
//
|
||||
// Runs on paste and on inserting nodes/html.
|
||||
editor.on( 'SetContent', function( e ) {
|
||||
if ( ! e.context ) {
|
||||
return;
|
||||
}
|
||||
// Bail if node is already selected.
|
||||
if ( viewNode === selected ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var node = selection.getNode();
|
||||
deselect();
|
||||
selected = viewNode;
|
||||
dom.addClass( viewNode, 'selected' );
|
||||
|
||||
if ( ! node.innerHTML ) {
|
||||
return;
|
||||
}
|
||||
clipboard = dom.create( 'div', {
|
||||
'class': 'wpview-clipboard',
|
||||
'contenteditable': 'true'
|
||||
}, getViewText( viewNode ) );
|
||||
|
||||
node.innerHTML = wp.mce.view.toViews( node.innerHTML );
|
||||
wp.mce.view.render( node );
|
||||
});
|
||||
});
|
||||
viewNode.appendChild( clipboard );
|
||||
|
||||
// When the editor's contents are being accessed as a string,
|
||||
// transform any views back to their text representations.
|
||||
editor.on( 'PostProcess', function( e ) {
|
||||
if ( ( ! e.get && ! e.save ) || ! e.content ) {
|
||||
return;
|
||||
}
|
||||
// Both of the following are necessary to prevent manipulating the selection/focus
|
||||
editor.dom.bind( clipboard, 'beforedeactivate focusin focusout', _stop );
|
||||
editor.dom.bind( selected, 'beforedeactivate focusin focusout', _stop );
|
||||
|
||||
e.content = wp.mce.view.toText( e.content );
|
||||
});
|
||||
// select the hidden div
|
||||
editor.selection.select( clipboard, true );
|
||||
}
|
||||
|
||||
// Triggers when the selection is changed.
|
||||
// Add the event handler to the top of the stack.
|
||||
editor.on( 'NodeChange', function( e ) {
|
||||
var view = wpView.getParentView( e.element );
|
||||
/**
|
||||
* Deselect a selected view and remove clipboard
|
||||
*/
|
||||
function deselect() {
|
||||
var clipboard,
|
||||
dom = editor.dom;
|
||||
|
||||
// Update the selected view.
|
||||
if ( view ) {
|
||||
wpView.select( view );
|
||||
if ( selected ) {
|
||||
clipboard = editor.dom.select( '.wpview-clipboard', selected )[0];
|
||||
dom.unbind( clipboard );
|
||||
dom.remove( clipboard );
|
||||
|
||||
// Prevent the selection from propagating to other plugins.
|
||||
return false;
|
||||
dom.unbind( selected, 'beforedeactivate focusin focusout click mouseup', _stop );
|
||||
dom.removeClass( selected, 'selected' );
|
||||
|
||||
// If we've clicked off of the selected view, deselect it.
|
||||
} else {
|
||||
wpView.deselect();
|
||||
}
|
||||
});
|
||||
editor.selection.select( selected.nextSibling );
|
||||
editor.selection.collapse();
|
||||
|
||||
editor.on( 'keydown', function( event ) {
|
||||
var keyCode = event.keyCode,
|
||||
view, instance;
|
||||
}
|
||||
|
||||
// If a view isn't selected, let the event go on its merry way.
|
||||
if ( ! selected ) {
|
||||
return;
|
||||
}
|
||||
selected = null;
|
||||
}
|
||||
|
||||
// If the caret is not within the selected view, deselect the
|
||||
// view and bail.
|
||||
view = wpView.getParentView( editor.selection.getNode() );
|
||||
if ( view !== selected ) {
|
||||
wpView.deselect();
|
||||
return;
|
||||
}
|
||||
// Check if the `wp.mce` API exists.
|
||||
if ( typeof wp === 'undefined' || ! wp.mce ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If delete or backspace is pressed, delete the view.
|
||||
if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) {
|
||||
if ( (instance = wp.mce.view.instance( selected )) ) {
|
||||
instance.remove();
|
||||
wpView.deselect();
|
||||
}
|
||||
}
|
||||
|
||||
// Let keypresses that involve the command or control keys through.
|
||||
// Also, let any of the F# keys through.
|
||||
if ( event.metaKey || event.ctrlKey || ( keyCode >= 112 && keyCode <= 123 ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
});
|
||||
},
|
||||
|
||||
getParentView : function( node ) {
|
||||
while ( node ) {
|
||||
if ( this.isView( node ) ) {
|
||||
return node;
|
||||
}
|
||||
|
||||
node = node.parentNode;
|
||||
}
|
||||
},
|
||||
|
||||
isView : function( node ) {
|
||||
return (/(?:^|\s)wp-view-wrap(?:\s|$)/).test( node.className );
|
||||
},
|
||||
|
||||
select : function( view ) {
|
||||
if ( view === selected ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.deselect();
|
||||
selected = view;
|
||||
wp.mce.view.select( selected );
|
||||
},
|
||||
|
||||
deselect : function() {
|
||||
if ( selected ) {
|
||||
wp.mce.view.deselect( selected );
|
||||
}
|
||||
|
||||
selected = null;
|
||||
editor.on( 'BeforeAddUndo', function( event ) {
|
||||
if ( selected && ! toRemove ) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// Register plugin
|
||||
tinymce.PluginManager.add( 'wpview', tinymce.plugins.wpView );
|
||||
})();
|
||||
// When the editor's content changes, scan the new content for
|
||||
// matching view patterns, and transform the matches into
|
||||
// view wrappers.
|
||||
editor.on( 'BeforeSetContent', function( e ) {
|
||||
if ( ! e.content ) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.content = wp.mce.views.toViews( e.content );
|
||||
});
|
||||
|
||||
// When the editor's content has been updated and the DOM has been
|
||||
// processed, render the views in the document.
|
||||
editor.on( 'SetContent', function( event ) {
|
||||
var body, padNode;
|
||||
|
||||
wp.mce.views.render();
|
||||
|
||||
// Add padding <p> if the noneditable node is last
|
||||
if ( event.load || ! event.set ) {
|
||||
body = editor.getBody();
|
||||
|
||||
if ( isView( body.lastChild ) ) {
|
||||
padNode = createPadNode();
|
||||
body.appendChild( padNode );
|
||||
editor.selection.setCursorLocation( padNode, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
// refreshEmptyContentNode();
|
||||
});
|
||||
|
||||
// Detect mouse down events that are adjacent to a view when a view is the first view or the last view
|
||||
editor.on( 'click', function( event ) {
|
||||
var body = editor.getBody(),
|
||||
doc = editor.getDoc(),
|
||||
scrollTop = doc.documentElement.scrollTop || body.scrollTop || 0,
|
||||
x, y, firstNode, lastNode, padNode;
|
||||
|
||||
if ( event.target.nodeName === 'HTML' && ! event.metaKey && ! event.ctrlKey ) {
|
||||
firstNode = body.firstChild;
|
||||
lastNode = body.lastChild;
|
||||
x = event.clientX;
|
||||
y = event.clientY;
|
||||
|
||||
if ( isView( firstNode ) && ( ( x < firstNode.offsetLeft && y < ( firstNode.offsetHeight - scrollTop ) ) ||
|
||||
y < firstNode.offsetTop ) ) {
|
||||
// detect events above or to the left of the first view
|
||||
|
||||
padNode = createPadNode();
|
||||
body.insertBefore( padNode, firstNode );
|
||||
} else if ( isView( lastNode ) && ( x > ( lastNode.offsetLeft + lastNode.offsetWidth ) ||
|
||||
( ( scrollTop + y ) - ( lastNode.offsetTop + lastNode.offsetHeight ) ) > 0 ) ) {
|
||||
// detect events to the right and below the last view
|
||||
|
||||
padNode = createPadNode();
|
||||
body.appendChild( padNode );
|
||||
}
|
||||
|
||||
if ( padNode ) {
|
||||
editor.selection.setCursorLocation( padNode, 0 );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
editor.on( 'init', function() {
|
||||
var selection = editor.selection;
|
||||
// When a view is selected, ensure content that is being pasted
|
||||
// or inserted is added to a text node (instead of the view).
|
||||
editor.on( 'BeforeSetContent', function() {
|
||||
var walker, target,
|
||||
view = getParentView( selection.getNode() );
|
||||
|
||||
// If the selection is not within a view, bail.
|
||||
if ( ! view ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! view.nextSibling || isView( view.nextSibling ) ) {
|
||||
// If there are no additional nodes or the next node is a
|
||||
// view, create a text node after the current view.
|
||||
target = editor.getDoc().createTextNode('');
|
||||
editor.dom.insertAfter( target, view );
|
||||
} else {
|
||||
// Otherwise, find the next text node.
|
||||
walker = new TreeWalker( view.nextSibling, view.nextSibling );
|
||||
target = walker.next();
|
||||
}
|
||||
|
||||
// Select the `target` text node.
|
||||
selection.select( target );
|
||||
selection.collapse( true );
|
||||
});
|
||||
|
||||
// When the selection's content changes, scan any new content
|
||||
// for matching views.
|
||||
//
|
||||
// Runs on paste and on inserting nodes/html.
|
||||
editor.on( 'SetContent', function( e ) {
|
||||
if ( ! e.context ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var node = selection.getNode();
|
||||
|
||||
if ( ! node.innerHTML ) {
|
||||
return;
|
||||
}
|
||||
|
||||
node.innerHTML = wp.mce.views.toViews( node.innerHTML );
|
||||
});
|
||||
|
||||
editor.dom.bind( editor.getBody(), 'mousedown mouseup click', function( event ) {
|
||||
var view = getParentView( event.target );
|
||||
|
||||
// Contain clicks inside the view wrapper
|
||||
if ( view ) {
|
||||
event.stopPropagation();
|
||||
|
||||
if ( event.type === 'click' ) {
|
||||
if ( ! event.metaKey && ! event.ctrlKey ) {
|
||||
if ( editor.dom.hasClass( event.target, 'edit' ) ) {
|
||||
wp.mce.views.edit( view );
|
||||
} else if ( editor.dom.hasClass( event.target, 'remove' ) ) {
|
||||
editor.dom.remove( view );
|
||||
}
|
||||
}
|
||||
}
|
||||
select( view );
|
||||
// returning false stops the ugly bars from appearing in IE11 and stops the view being selected as a range in FF
|
||||
// unfortunately, it also inhibits the dragging fo views to a new location
|
||||
return false;
|
||||
} else {
|
||||
if ( event.type === 'click' ) {
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
editor.on( 'PreProcess', function( event ) {
|
||||
var dom = editor.dom;
|
||||
|
||||
// Remove empty padding nodes
|
||||
tinymce.each( dom.select( 'p[data-wpview-pad]', event.node ), function( node ) {
|
||||
if ( dom.isEmpty( node ) ) {
|
||||
dom.remove( node );
|
||||
} else {
|
||||
dom.setAttrib( node, 'data-wpview-pad', null );
|
||||
}
|
||||
});
|
||||
|
||||
// Replace the wpview node with the wpview string/shortcode?
|
||||
tinymce.each( dom.select( 'div[data-wpview-text]', event.node ), function( node ) {
|
||||
// Empty the wrap node
|
||||
if ( 'textContent' in node ) {
|
||||
node.textContent = '';
|
||||
} else {
|
||||
node.innerText = '';
|
||||
}
|
||||
|
||||
// TODO: that makes all views into block tags (as we use <div>).
|
||||
// Can use 'PostProcess' and a regex instead.
|
||||
dom.replace( dom.create( 'p', null, window.decodeURIComponent( dom.getAttrib( node, 'data-wpview-text' ) ) ), node );
|
||||
});
|
||||
});
|
||||
|
||||
editor.on( 'keydown', function( event ) {
|
||||
var keyCode = event.keyCode,
|
||||
view;
|
||||
|
||||
// If a view isn't selected, let the event go on its merry way.
|
||||
if ( ! selected ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let keypresses that involve the command or control keys through.
|
||||
// Also, let any of the F# keys through.
|
||||
if ( event.metaKey || event.ctrlKey || ( keyCode >= 112 && keyCode <= 123 ) ) {
|
||||
if ( ( event.metaKey || event.ctrlKey ) && keyCode === 88 ) {
|
||||
toRemove = selected;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If the caret is not within the selected view, deselect the
|
||||
// view and bail.
|
||||
view = getParentView( editor.selection.getNode() );
|
||||
|
||||
if ( view !== selected ) {
|
||||
deselect();
|
||||
return;
|
||||
}
|
||||
|
||||
// If delete or backspace is pressed, delete the view.
|
||||
if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) {
|
||||
editor.dom.remove( selected );
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
editor.on( 'keyup', function( event ) {
|
||||
var padNode,
|
||||
keyCode = event.keyCode,
|
||||
body = editor.getBody(),
|
||||
range;
|
||||
|
||||
if ( toRemove ) {
|
||||
editor.dom.remove( toRemove );
|
||||
toRemove = false;
|
||||
}
|
||||
|
||||
if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) {
|
||||
// Make sure there is padding if the last element is a view
|
||||
if ( isView( body.lastChild ) ) {
|
||||
padNode = createPadNode();
|
||||
body.appendChild( padNode );
|
||||
|
||||
if ( body.childNodes.length === 2 ) {
|
||||
editor.selection.setCursorLocation( padNode, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
range = editor.selection.getRng();
|
||||
|
||||
// Allow an initial element in the document to be removed when it is before a view
|
||||
if ( body.firstChild === range.startContainer && range.collapsed === true &&
|
||||
isView( range.startContainer.nextSibling ) && range.startOffset === 0 ) {
|
||||
|
||||
editor.dom.remove( range.startContainer );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
getViewText: getViewText,
|
||||
setViewText: setViewText
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1 +1 @@
|
||||
!function(){var a,b=tinymce.VK,c=tinymce.dom.TreeWalker;tinymce.create("tinymce.plugins.wpView",{init:function(d){var e=this;"undefined"!=typeof wp&&wp.mce&&(d.on("PreInit",function(){d.schema.addValidElements("div[*],span[*]")}),d.on("BeforeSetContent",function(a){a.content&&(a.content=wp.mce.view.toViews(a.content))}),d.on("SetContent",function(){wp.mce.view.render(d.getDoc())}),d.on("init",function(){var a=d.selection;d.on("BeforeSetContent",function(){var b,f,g=e.getParentView(a.getNode());g&&(!g.nextSibling||e.isView(g.nextSibling)?(f=d.getDoc().createTextNode(""),d.dom.insertAfter(f,g)):(b=new c(g.nextSibling,g.nextSibling),f=b.next()),a.select(f),a.collapse(!0))}),d.on("SetContent",function(b){if(b.context){var c=a.getNode();c.innerHTML&&(c.innerHTML=wp.mce.view.toViews(c.innerHTML),wp.mce.view.render(c))}})}),d.on("PostProcess",function(a){(a.get||a.save)&&a.content&&(a.content=wp.mce.view.toText(a.content))}),d.on("NodeChange",function(a){var b=e.getParentView(a.element);return b?(e.select(b),!1):void e.deselect()}),d.on("keydown",function(c){var f,g,h=c.keyCode;if(a){if(f=e.getParentView(d.selection.getNode()),f!==a)return void e.deselect();(h===b.DELETE||h===b.BACKSPACE)&&(g=wp.mce.view.instance(a))&&(g.remove(),e.deselect()),c.metaKey||c.ctrlKey||h>=112&&123>=h||c.preventDefault()}}))},getParentView:function(a){for(;a;){if(this.isView(a))return a;a=a.parentNode}},isView:function(a){return/(?:^|\s)wp-view-wrap(?:\s|$)/.test(a.className)},select:function(b){b!==a&&(this.deselect(),a=b,wp.mce.view.select(a))},deselect:function(){a&&wp.mce.view.deselect(a),a=null}}),tinymce.PluginManager.add("wpview",tinymce.plugins.wpView)}();
|
||||
tinymce.PluginManager.add("wpview",function(a){function b(a){for(;a&&"BODY"!==a.nodeName;){if(c(a))return a;a=a.parentNode}}function c(a){return a&&/\bwpview-wrap\b/.test(a.className)}function d(){return a.dom.create("p",{"data-wpview-pad":1},tinymce.Env.ie&&tinymce.Env.ie<11?"":'<br data-mce-bogus="1" />')}function e(c){return c=b("string"==typeof c?a.dom.get(c):c),c?window.decodeURIComponent(a.dom.getAttrib(c,"data-wpview-text")||""):""}function f(c,d){return c=b("string"==typeof c?a.dom.get(c):c),c?(a.dom.setAttrib(c,"data-wpview-text",window.encodeURIComponent(d||"")),!0):!1}function g(a){a.stopPropagation()}function h(b){var c,d=a.dom;b!==j&&(i(),j=b,d.addClass(b,"selected"),c=d.create("div",{"class":"wpview-clipboard",contenteditable:"true"},e(b)),b.appendChild(c),a.dom.bind(c,"beforedeactivate focusin focusout",g),a.dom.bind(j,"beforedeactivate focusin focusout",g),a.selection.select(c,!0))}function i(){var b,c=a.dom;j&&(b=a.dom.select(".wpview-clipboard",j)[0],c.unbind(b),c.remove(b),c.unbind(j,"beforedeactivate focusin focusout click mouseup",g),c.removeClass(j,"selected"),a.selection.select(j.nextSibling),a.selection.collapse()),j=null}var j,k=tinymce.util.VK,l=tinymce.dom.TreeWalker,m=!1;if("undefined"!=typeof wp&&wp.mce)return a.on("BeforeAddUndo",function(a){j&&!m&&a.preventDefault()}),a.on("BeforeSetContent",function(a){a.content&&(a.content=wp.mce.views.toViews(a.content))}),a.on("SetContent",function(b){var e,f;wp.mce.views.render(),(b.load||!b.set)&&(e=a.getBody(),c(e.lastChild)&&(f=d(),e.appendChild(f),a.selection.setCursorLocation(f,0)))}),a.on("click",function(b){var e,f,g,h,i,j=a.getBody(),k=a.getDoc(),l=k.documentElement.scrollTop||j.scrollTop||0;"HTML"!==b.target.nodeName||b.metaKey||b.ctrlKey||(g=j.firstChild,h=j.lastChild,e=b.clientX,f=b.clientY,c(g)&&(e<g.offsetLeft&&f<g.offsetHeight-l||f<g.offsetTop)?(i=d(),j.insertBefore(i,g)):c(h)&&(e>h.offsetLeft+h.offsetWidth||l+f-(h.offsetTop+h.offsetHeight)>0)&&(i=d(),j.appendChild(i)),i&&a.selection.setCursorLocation(i,0))}),a.on("init",function(){var d=a.selection;a.on("BeforeSetContent",function(){var e,f,g=b(d.getNode());g&&(!g.nextSibling||c(g.nextSibling)?(f=a.getDoc().createTextNode(""),a.dom.insertAfter(f,g)):(e=new l(g.nextSibling,g.nextSibling),f=e.next()),d.select(f),d.collapse(!0))}),a.on("SetContent",function(a){if(a.context){var b=d.getNode();b.innerHTML&&(b.innerHTML=wp.mce.views.toViews(b.innerHTML))}}),a.dom.bind(a.getBody(),"mousedown mouseup click",function(c){var d=b(c.target);return d?(c.stopPropagation(),"click"===c.type&&(c.metaKey||c.ctrlKey||(a.dom.hasClass(c.target,"edit")?wp.mce.views.edit(d):a.dom.hasClass(c.target,"remove")&&a.dom.remove(d))),h(d),!1):void("click"===c.type&&i())})}),a.on("PreProcess",function(b){var c=a.dom;tinymce.each(c.select("p[data-wpview-pad]",b.node),function(a){c.isEmpty(a)?c.remove(a):c.setAttrib(a,"data-wpview-pad",null)}),tinymce.each(c.select("div[data-wpview-text]",b.node),function(a){"textContent"in a?a.textContent="":a.innerText="",c.replace(c.create("p",null,window.decodeURIComponent(c.getAttrib(a,"data-wpview-text"))),a)})}),a.on("keydown",function(c){var d,e=c.keyCode;if(j){if(c.metaKey||c.ctrlKey||e>=112&&123>=e)return void((c.metaKey||c.ctrlKey)&&88===e&&(m=j));if(d=b(a.selection.getNode()),d!==j)return void i();(e===k.DELETE||e===k.BACKSPACE)&&a.dom.remove(j),c.preventDefault()}}),a.on("keyup",function(b){var e,f,g=b.keyCode,h=a.getBody();m&&(a.dom.remove(m),m=!1),(g===k.DELETE||g===k.BACKSPACE)&&(c(h.lastChild)&&(e=d(),h.appendChild(e),2===h.childNodes.length&&a.selection.setCursorLocation(e,0)),f=a.selection.getRng(),h.firstChild===f.startContainer&&f.collapsed===!0&&c(f.startContainer.nextSibling)&&0===f.startOffset&&a.dom.remove(f.startContainer))}),{getViewText:e,setViewText:f}});
|
||||
Reference in New Issue
Block a user