TinyMCE: improve reposition method inline toolbars

* Make sure the toolbar does not overlap the target, unless it is higher than half the visible editor area's height.
* Allow the toolbar to have the preference to position itself above or below the target.
* Cache DOM lookups.
* Simplify the logic and fix various positioning issues.

See #32604.


Built from https://develop.svn.wordpress.org/trunk@32816


git-svn-id: http://core.svn.wordpress.org/trunk@32787 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Ella Iseulde Van Dorpe 2015-06-17 04:42:25 +00:00
parent 1a4c6ad45d
commit a31d79196d
4 changed files with 67 additions and 79 deletions

View File

@ -447,9 +447,21 @@ tinymce.PluginManager.add( 'wordpress', function( editor ) {
var Factory = tinymce.ui.Factory, var Factory = tinymce.ui.Factory,
settings = editor.settings, settings = editor.settings,
currentToolbar, currentToolbar,
currentSelection; currentSelection,
wpAdminbar = document.getElementById( 'wpadminbar' ),
mceIframe, mceToolbar, mceStatusbar, wpStatusbar;
function create( buttons ) { editor.on( 'init', function() {
mceIframe = document.getElementById( editor.id + '_ifr' );
mceToolbar = tinymce.$( '.mce-toolbar-grp', editor.getContainer() )[0];
mceStatusbar = tinymce.$( '.mce-statusbar', editor.getContainer() )[0];
if ( editor.id === 'content' ) {
wpStatusbar = document.getElementById( 'post-status-info' );
}
} );
function create( buttons, bottom ) {
var toolbar, var toolbar,
toolbarItems = [], toolbarItems = [],
buttonGroup; buttonGroup;
@ -573,107 +585,83 @@ tinymce.PluginManager.add( 'wordpress', function( editor ) {
} ] } ]
} ); } );
toolbar.bottom = bottom;
function hide() { function hide() {
toolbar.hide(); toolbar.hide();
} }
function reposition() { function reposition() {
var top, left, minTop, className, var scrollX = window.pageXOffset || document.documentElement.scrollLeft,
windowPos, adminbar, mceToolbar, boundary, scrollY = window.pageYOffset || document.documentElement.scrollTop,
boundaryMiddle, boundaryVerticalMiddle, spaceTop, windowWidth = window.innerWidth,
spaceBottom, windowWidth, toolbarWidth, toolbarHalf, windowHeight = window.innerHeight,
iframe, iframePos, iframeWidth, iframeHeigth, iframeRect = mceIframe.getBoundingClientRect(),
toolbarNodeHeight, verticalSpaceNeeded, toolbar = this.getEl(),
toolbarNode = this.getEl(), toolbarWidth = toolbar.offsetWidth,
toolbarHeight = toolbar.offsetHeight,
selection = currentSelection.getBoundingClientRect(),
selectionMiddle = ( selection.left + selection.right ) / 2,
buffer = 5, buffer = 5,
margin = 8, margin = 8,
adminbarHeight = 0; spaceNeeded = toolbarHeight + margin + buffer,
wpAdminbarBottom = wpAdminbar ? wpAdminbar.getBoundingClientRect().bottom : 0,
mceToolbarBottom = mceToolbar ? mceToolbar.getBoundingClientRect().bottom : 0,
mceStatusbarTop = mceStatusbar ? windowHeight - mceStatusbar.getBoundingClientRect().top : 0,
wpStatusbarTop = wpStatusbar ? windowHeight - wpStatusbar.getBoundingClientRect().top : 0,
blockedTop = Math.max( 0, wpAdminbarBottom, mceToolbarBottom, iframeRect.top ),
blockedBottom = Math.max( 0, mceStatusbarTop, wpStatusbarTop, windowHeight - iframeRect.bottom ),
spaceTop = selection.top + iframeRect.top - blockedTop,
spaceBottom = windowHeight - iframeRect.top - selection.bottom - blockedBottom,
editorHeight = windowHeight - blockedTop - blockedBottom,
className = '',
top, left;
if ( ! currentSelection ) { if ( this.bottom ) {
return; if ( spaceBottom >= spaceNeeded ) {
}
windowPos = window.pageYOffset || document.documentElement.scrollTop;
adminbar = tinymce.$( '#wpadminbar' )[0];
mceToolbar = tinymce.$( '.mce-toolbar-grp', editor.getContainer() )[0];
boundary = currentSelection.getBoundingClientRect();
boundaryMiddle = ( boundary.left + boundary.right ) / 2;
boundaryVerticalMiddle = ( boundary.top + boundary.bottom ) / 2;
spaceTop = boundary.top;
spaceBottom = iframeHeigth - boundary.bottom;
windowWidth = window.innerWidth;
toolbarWidth = toolbarNode.offsetWidth;
toolbarHalf = toolbarWidth / 2;
iframe = document.getElementById( editor.id + '_ifr' );
iframePos = DOM.getPos( iframe );
iframeWidth = iframe.offsetWidth;
iframeHeigth = iframe.offsetHeight;
toolbarNodeHeight = toolbarNode.offsetHeight;
verticalSpaceNeeded = toolbarNodeHeight + margin + buffer;
if ( spaceTop >= verticalSpaceNeeded ) {
className = ' mce-arrow-down';
top = boundary.top + iframePos.y - toolbarNodeHeight - margin;
} else if ( spaceBottom >= verticalSpaceNeeded ) {
className = ' mce-arrow-up';
top = boundary.bottom + iframePos.y;
} else {
top = buffer;
if ( boundaryVerticalMiddle >= verticalSpaceNeeded ) {
className = ' mce-arrow-down';
} else {
className = ' mce-arrow-up'; className = ' mce-arrow-up';
top = selection.bottom + iframeRect.top + scrollY;
} else if ( spaceTop >= spaceNeeded ) {
className = ' mce-arrow-down';
top = selection.top + iframeRect.top + scrollY - toolbarHeight - margin;
} }
}
// Make sure the image toolbar is below the main toolbar.
if ( mceToolbar ) {
minTop = DOM.getPos( mceToolbar ).y + mceToolbar.clientHeight;
} else { } else {
minTop = iframePos.y; if ( spaceTop >= spaceNeeded ) {
} className = ' mce-arrow-down';
top = selection.top + iframeRect.top + scrollY - toolbarHeight - margin;
// Make sure the image toolbar is below the adminbar (if visible) or below the top of the window. } else if ( spaceBottom >= spaceNeeded && editorHeight / 2 > selection.bottom + iframeRect.top - blockedTop ) {
if ( windowPos ) { className = ' mce-arrow-up';
if ( adminbar && adminbar.getBoundingClientRect().top === 0 ) { top = selection.bottom + iframeRect.top + scrollY;
adminbarHeight = adminbar.clientHeight;
}
if ( windowPos + adminbarHeight > minTop ) {
minTop = windowPos + adminbarHeight;
} }
} }
if ( top && minTop && ( minTop + buffer > top ) ) { if ( typeof top === 'undefined' ) {
top = minTop + buffer; top = scrollY + blockedTop + buffer;
className = '';
} }
left = boundaryMiddle - toolbarHalf; left = selectionMiddle - toolbarWidth / 2 + iframeRect.left + scrollX;
left += iframePos.x;
if ( boundary.left < 0 || boundary.right > iframeWidth ) { if ( selection.left < 0 || selection.right > iframeRect.width ) {
left = iframePos.x + ( iframeWidth - toolbarWidth ) / 2; left = iframeRect.left + scrollX + ( iframeRect.width - toolbarWidth ) / 2;
} else if ( toolbarWidth >= windowWidth ) { } else if ( toolbarWidth >= windowWidth ) {
className += ' mce-arrow-full'; className += ' mce-arrow-full';
left = 0; left = 0;
} else if ( ( left < 0 && boundary.left + toolbarWidth > windowWidth ) || } else if ( ( left < 0 && selection.left + toolbarWidth > windowWidth ) || ( left + toolbarWidth > windowWidth && selection.right - toolbarWidth < 0 ) ) {
( left + toolbarWidth > windowWidth && boundary.right - toolbarWidth < 0 ) ) {
left = ( windowWidth - toolbarWidth ) / 2; left = ( windowWidth - toolbarWidth ) / 2;
} else if ( left < iframePos.x ) { } else if ( left < iframeRect.left + scrollX ) {
className += ' mce-arrow-left'; className += ' mce-arrow-left';
left = boundary.left + iframePos.x; left = selection.left + iframeRect.left + scrollX;
} else if ( left + toolbarWidth > iframeWidth + iframePos.x ) { } else if ( left + toolbarWidth > iframeRect.width + iframeRect.left + scrollX ) {
className += ' mce-arrow-right'; className += ' mce-arrow-right';
left = boundary.right - toolbarWidth + iframePos.x; left = selection.right - toolbarWidth + iframeRect.left + scrollX;
} }
toolbarNode.className = toolbarNode.className.replace( / ?mce-arrow-[\w]+/g, '' ); toolbar.className = toolbar.className.replace( / ?mce-arrow-[\w]+/g, '' ) + className;
toolbarNode.className += className;
DOM.setStyles( toolbarNode, { 'left': left, 'top': top } ); DOM.setStyles( toolbar, {
'left': left,
'top': top
} );
return this; return this;
} }

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.3-alpha-32815'; $wp_version = '4.3-alpha-32816';
/** /**
* 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.