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.



git-svn-id: https://develop.svn.wordpress.org/trunk@32816 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Ella Iseulde Van Dorpe 2015-06-17 04:41:59 +00:00
parent 2b857dfdc3
commit 33e63b7bda
1 changed files with 65 additions and 77 deletions

View File

@ -447,9 +447,21 @@ tinymce.PluginManager.add( 'wordpress', function( editor ) {
var Factory = tinymce.ui.Factory,
settings = editor.settings,
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,
toolbarItems = [],
buttonGroup;
@ -573,107 +585,83 @@ tinymce.PluginManager.add( 'wordpress', function( editor ) {
} ]
} );
toolbar.bottom = bottom;
function hide() {
toolbar.hide();
}
function reposition() {
var top, left, minTop, className,
windowPos, adminbar, mceToolbar, boundary,
boundaryMiddle, boundaryVerticalMiddle, spaceTop,
spaceBottom, windowWidth, toolbarWidth, toolbarHalf,
iframe, iframePos, iframeWidth, iframeHeigth,
toolbarNodeHeight, verticalSpaceNeeded,
toolbarNode = this.getEl(),
var scrollX = window.pageXOffset || document.documentElement.scrollLeft,
scrollY = window.pageYOffset || document.documentElement.scrollTop,
windowWidth = window.innerWidth,
windowHeight = window.innerHeight,
iframeRect = mceIframe.getBoundingClientRect(),
toolbar = this.getEl(),
toolbarWidth = toolbar.offsetWidth,
toolbarHeight = toolbar.offsetHeight,
selection = currentSelection.getBoundingClientRect(),
selectionMiddle = ( selection.left + selection.right ) / 2,
buffer = 5,
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 ) {
return;
}
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 {
if ( this.bottom ) {
if ( spaceBottom >= spaceNeeded ) {
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 {
minTop = iframePos.y;
}
// Make sure the image toolbar is below the adminbar (if visible) or below the top of the window.
if ( windowPos ) {
if ( adminbar && adminbar.getBoundingClientRect().top === 0 ) {
adminbarHeight = adminbar.clientHeight;
}
if ( windowPos + adminbarHeight > minTop ) {
minTop = windowPos + adminbarHeight;
if ( spaceTop >= spaceNeeded ) {
className = ' mce-arrow-down';
top = selection.top + iframeRect.top + scrollY - toolbarHeight - margin;
} else if ( spaceBottom >= spaceNeeded && editorHeight / 2 > selection.bottom + iframeRect.top - blockedTop ) {
className = ' mce-arrow-up';
top = selection.bottom + iframeRect.top + scrollY;
}
}
if ( top && minTop && ( minTop + buffer > top ) ) {
top = minTop + buffer;
className = '';
if ( typeof top === 'undefined' ) {
top = scrollY + blockedTop + buffer;
}
left = boundaryMiddle - toolbarHalf;
left += iframePos.x;
left = selectionMiddle - toolbarWidth / 2 + iframeRect.left + scrollX;
if ( boundary.left < 0 || boundary.right > iframeWidth ) {
left = iframePos.x + ( iframeWidth - toolbarWidth ) / 2;
if ( selection.left < 0 || selection.right > iframeRect.width ) {
left = iframeRect.left + scrollX + ( iframeRect.width - toolbarWidth ) / 2;
} else if ( toolbarWidth >= windowWidth ) {
className += ' mce-arrow-full';
left = 0;
} else if ( ( left < 0 && boundary.left + toolbarWidth > windowWidth ) ||
( left + toolbarWidth > windowWidth && boundary.right - toolbarWidth < 0 ) ) {
} else if ( ( left < 0 && selection.left + toolbarWidth > windowWidth ) || ( left + toolbarWidth > windowWidth && selection.right - toolbarWidth < 0 ) ) {
left = ( windowWidth - toolbarWidth ) / 2;
} else if ( left < iframePos.x ) {
} else if ( left < iframeRect.left + scrollX ) {
className += ' mce-arrow-left';
left = boundary.left + iframePos.x;
} else if ( left + toolbarWidth > iframeWidth + iframePos.x ) {
left = selection.left + iframeRect.left + scrollX;
} else if ( left + toolbarWidth > iframeRect.width + iframeRect.left + scrollX ) {
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, '' );
toolbarNode.className += className;
toolbar.className = toolbar.className.replace( / ?mce-arrow-[\w]+/g, '' ) + className;
DOM.setStyles( toolbarNode, { 'left': left, 'top': top } );
DOM.setStyles( toolbar, {
'left': left,
'top': top
} );
return this;
}