From 33e63b7bdabaf55d49a0175bf165e3cb0c4b2f4a Mon Sep 17 00:00:00 2001 From: Ella Iseulde Van Dorpe Date: Wed, 17 Jun 2015 04:41:59 +0000 Subject: [PATCH] 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 --- .../js/tinymce/plugins/wordpress/plugin.js | 142 ++++++++---------- 1 file changed, 65 insertions(+), 77 deletions(-) diff --git a/src/wp-includes/js/tinymce/plugins/wordpress/plugin.js b/src/wp-includes/js/tinymce/plugins/wordpress/plugin.js index 57b09a4a8e..245debbc5e 100644 --- a/src/wp-includes/js/tinymce/plugins/wordpress/plugin.js +++ b/src/wp-includes/js/tinymce/plugins/wordpress/plugin.js @@ -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; }