From 46457ead23ff76066944897b4659e6519d794670 Mon Sep 17 00:00:00 2001 From: Andrew Ozz Date: Sun, 24 Aug 2014 05:10:52 +0000 Subject: [PATCH] Editor scrolling: - Pin the TinyMCE statusbar (elements path) to the bottom. - Add support for pinning the menu when present. - Add borders from CSS. - Optimize getting most elements outerHeight. Part props avryl, fixes #29293, see #28328. git-svn-id: https://develop.svn.wordpress.org/trunk@29579 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/css/edit.css | 32 ++++ src/wp-admin/js/editor-expand.js | 221 +++++++++++++++++----------- src/wp-includes/css/editor.css | 9 +- src/wp-includes/css/media-views.css | 1 + src/wp-includes/js/mce-view.js | 2 +- 5 files changed, 174 insertions(+), 91 deletions(-) diff --git a/src/wp-admin/css/edit.css b/src/wp-admin/css/edit.css index c6fbb92d97..d119d9e3c8 100644 --- a/src/wp-admin/css/edit.css +++ b/src/wp-admin/css/edit.css @@ -406,6 +406,38 @@ td.plugin-title p { } /* end editor-expand.js override */ +.wp-editor-expand #wp-content-editor-tools { + z-index: 1000; + border-bottom: 1px solid #e5e5e5; +} + +.wp-editor-expand #wp-content-editor-container { + -webkit-box-shadow: none; + box-shadow: none; + margin-top: -1px; +} + +.wp-editor-expand #wp-content-editor-container { + border-bottom: 0 none; +} + +.wp-editor-expand div.mce-statusbar { + z-index: 1; +} + +.wp-editor-expand #post-status-info { + border-top: 1px solid #e5e5e5; +} + +.wp-editor-expand div.mce-toolbar-grp { + z-index: 999; +} + +#wp-content-editor-tools { + background-color: #f1f1f1; + padding-top: 20px; +} + #poststuff #post-body.columns-2 #side-sortables { width: 280px; } diff --git a/src/wp-admin/js/editor-expand.js b/src/wp-admin/js/editor-expand.js index 04289e3cc0..6cd217f41c 100644 --- a/src/wp-admin/js/editor-expand.js +++ b/src/wp-admin/js/editor-expand.js @@ -10,13 +10,14 @@ jQuery( document ).ready( function($) { $wrap = $( '#postdivrich' ), $contentWrap = $( '#wp-content-wrap' ), $tools = $( '#wp-content-editor-tools' ), - $visualTop, - $visualEditor, + $visualTop = $(), + $visualEditor = $(), $textTop = $( '#ed_toolbar' ), $textEditor = $( '#content' ), $textEditorClone = $( '
' ), $bottom = $( '#post-status-info' ), - $statusBar, + $menuBar = $(), + $statusBar = $(), $sideSortables = $( '#side-sortables' ), $postboxContainer = $( '#postbox-container-1' ), $postBody = $('#post-body'), @@ -32,7 +33,20 @@ jQuery( document ).ready( function($) { lastScrollPosition = 0, pageYOffsetAtTop = 130, pinnedToolsTop = 56, - autoresizeMinHeight = 300; + autoresizeMinHeight = 300, + // These are corrected when adjust() runs, except on scrolling if already set. + heights = { + windowHeight: 0, + windowWidth: 0, + adminBarHeight: 0, + toolsHeight: 0, + menuBarHeight: 0, + visualTopHeight: 0, + textTopHeight: 0, + bottomHeight: 0, + statusBarHeight: 0, + sideSortablesHeight: 0 + }; $textEditorClone.insertAfter( $textEditor ); @@ -44,6 +58,23 @@ jQuery( document ).ready( function($) { 'word-wrap': 'break-word' } ); + function getHeights() { + var windowWidth = $window.width(); + + heights = { + windowHeight: $window.height(), + windowWidth: windowWidth, + adminBarHeight: ( windowWidth > 600 ? $adminBar.outerHeight() : 0 ), + toolsHeight: $tools.outerHeight() || 0, + menuBarHeight: $menuBar.outerHeight() || 0, + visualTopHeight: $visualTop.outerHeight() || 0, + textTopHeight: $textTop.outerHeight() || 0, + bottomHeight: $bottom.outerHeight() || 0, + statusBarHeight: $statusBar.outerHeight() || 0, + sideSortablesHeight: $sideSortables.height() || 0 + }; + } + function textEditorKeyup( event ) { var VK = jQuery.ui.keyCode, key = event.keyCode, @@ -51,7 +82,6 @@ jQuery( document ).ready( function($) { selStart = $textEditor[0].selectionStart, selEnd = $textEditor[0].selectionEnd, textNode = $textEditorClone[0].firstChild, - windowHeight = $window.height(), buffer = 10, offset, cursorTop, cursorBottom, editorTop, editorBottom; @@ -73,8 +103,8 @@ jQuery( document ).ready( function($) { cursorTop = offset.top - buffer; cursorBottom = cursorTop + offset.height + buffer; - editorTop = $adminBar.outerHeight() + $tools.outerHeight() + $textTop.outerHeight(); - editorBottom = windowHeight - $bottom.outerHeight(); + editorTop = heights.adminBarHeight + heights.toolsHeight + heights.textTopHeight; + editorBottom = heights.windowHeight - heights.bottomHeight; if ( cursorTop < editorTop && ( key === VK.UP || key === VK.LEFT || key === VK.BACKSPACE ) ) { window.scrollTo( window.pageXOffset, cursorTop + window.pageYOffset - editorTop ); @@ -125,7 +155,8 @@ jQuery( document ).ready( function($) { // Get the necessary UI elements. $visualTop = $contentWrap.find( '.mce-toolbar-grp' ); $visualEditor = $contentWrap.find( '.mce-edit-area' ); - $statusBar = $contentWrap.find( '.mce-statusbar' ).filter( ':visible' ); + $statusBar = $contentWrap.find( '.mce-statusbar' ); + $menuBar = $contentWrap.find( '.mce-menubar' ); function mceGetCursorOffset() { var node = editor.selection.getNode(), @@ -150,7 +181,6 @@ jQuery( document ).ready( function($) { var VK = tinymce.util.VK, key = event.keyCode, offset = mceGetCursorOffset(), - windowHeight = $window.height(), buffer = 10, cursorTop, cursorBottom, editorTop, editorBottom; @@ -158,12 +188,12 @@ jQuery( document ).ready( function($) { return; } - cursorTop = offset.top + editor.getContentAreaContainer().firstChild.getBoundingClientRect().top; + cursorTop = offset.top + editor.iframeElement.getBoundingClientRect().top; cursorBottom = cursorTop + offset.height; cursorTop = cursorTop - buffer; cursorBottom = cursorBottom + buffer; - editorTop = $adminBar.outerHeight() + $tools.outerHeight() + $visualTop.outerHeight(); - editorBottom = windowHeight - $bottom.outerHeight(); + editorTop = heights.adminBarHeight + heights.toolsHeight + heights.menuBarHeight + heights.visualTopHeight; + editorBottom = heights.windowHeight - heights.bottomHeight - heights.statusBarHeight; // Don't scroll if the node is taller than the visible part of the editor if ( editorBottom - editorTop < offset.height ) { @@ -219,35 +249,34 @@ jQuery( document ).ready( function($) { return; } - var bottomHeight = $bottom.outerHeight(), - windowPos = $window.scrollTop(), - windowHeight = $window.height(), - windowWidth = $window.width(), - adminBarHeight = windowWidth > 600 ? $adminBar.height() : 0, + var windowPos = $window.scrollTop(), resize = type !== 'scroll', visual = ( mceEditor && ! mceEditor.isHidden() ), buffer = autoresizeMinHeight, postBodyTop = $postBody.offset().top, borderWidth = 1, contentWrapWidth = $contentWrap.width(), - sideSortablesHeight = $sideSortables.height(), $top, $editor, sidebarTop, footerTop, canPin, - toolsHeight, topPos, topHeight, editorPos, editorHeight, statusBarHeight; + topPos, topHeight, editorPos, editorHeight; + + // Refresh the heights + if ( resize || ! heights.windowHeight ) { + getHeights(); + } if ( visual ) { $top = $visualTop; $editor = $visualEditor; + topHeight = heights.visualTopHeight; } else { $top = $textTop; $editor = $textEditor; + topHeight = heights.textTopHeight; } - toolsHeight = $tools.outerHeight(); topPos = $top.parent().offset().top; - topHeight = $top.outerHeight(); editorPos = $editor.offset().top; editorHeight = $editor.outerHeight(); - statusBarHeight = visual ? $statusBar.outerHeight() : 0; // Should we pin? canPin = visual ? autoresizeMinHeight + topHeight : autoresizeMinHeight + 20; // 20px from textarea padding @@ -255,116 +284,138 @@ jQuery( document ).ready( function($) { if ( ! canPin ) { if ( resize ) { - $top.css( { - position: 'absolute', - top: 0, - borderTop: 'none', - width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) - } ); - $tools.css( { position: 'absolute', top: 0, width: contentWrapWidth } ); - $bottom.css( { - position: 'relative', - bottom: 'auto', - width: '100%', - borderTop: 'none' + if ( visual && $menuBar.length ) { + $menuBar.css( { + position: 'absolute', + top: 0, + width: contentWrapWidth - ( borderWidth * 2 ) + } ); + } + + $top.css( { + position: 'absolute', + top: heights.menuBarHeight, + width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) } ); + + $statusBar.add( $bottom ).attr( 'style', '' ); } } else { // Maybe pin the top. if ( ( ! fixedTop || resize ) && // Handle scrolling down. - ( windowPos >= ( topPos - toolsHeight - adminBarHeight ) && + ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight ) && // Handle scrolling up. - windowPos <= ( topPos - toolsHeight - adminBarHeight + editorHeight - buffer ) ) ) { - + windowPos <= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) ) { fixedTop = true; - $top.css( { - position: 'fixed', - top: adminBarHeight + toolsHeight, - width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ), - borderTop: '1px solid #e5e5e5' - } ); - $tools.css( { position: 'fixed', - top: adminBarHeight, + top: heights.adminBarHeight, width: contentWrapWidth } ); + + if ( visual && $menuBar.length ) { + $menuBar.css( { + position: 'fixed', + top: heights.adminBarHeight + heights.toolsHeight, + width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) + } ); + } + + $top.css( { + position: 'fixed', + top: heights.adminBarHeight + heights.toolsHeight + heights.menuBarHeight, + width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) + } ); // Maybe unpin the top. } else if ( fixedTop || resize ) { // Handle scrolling up. - if ( windowPos <= ( topPos - toolsHeight - adminBarHeight ) ) { + if ( windowPos <= ( topPos - heights.toolsHeight - heights.adminBarHeight ) ) { fixedTop = false; - $top.css( { - position: 'absolute', - top: 0, - borderTop: 'none', - width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) - } ); - $tools.css( { position: 'absolute', top: 0, width: contentWrapWidth } ); + + if ( visual && $menuBar.length ) { + $menuBar.css( { + position: 'absolute', + top: 0, + width: contentWrapWidth - ( borderWidth * 2 ) + } ); + } + + $top.css( { + position: 'absolute', + top: heights.menuBarHeight, + width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) + } ); // Handle scrolling down. - } else if ( windowPos >= ( topPos - toolsHeight - adminBarHeight + editorHeight - buffer ) ) { + } else if ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) { fixedTop = false; - $top.css( { - position: 'absolute', - top: editorHeight - buffer, - width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) - } ); - $tools.css( { position: 'absolute', - top: editorHeight - buffer + borderWidth, // border + top: editorHeight - buffer, width: contentWrapWidth } ); + + if ( visual && $menuBar.length ) { + $menuBar.css( { + position: 'absolute', + top: editorHeight - buffer, + width: contentWrapWidth - ( borderWidth * 2 ) + } ); + } + + $top.css( { + position: 'absolute', + top: editorHeight - buffer + heights.menuBarHeight, + width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) + } ); } } // Maybe adjust the bottom bar. if ( ( ! fixedBottom || resize ) && // +[n] for the border around the .wp-editor-container. - ( windowPos + windowHeight ) <= ( editorPos + editorHeight + bottomHeight + statusBarHeight + borderWidth ) ) { - + ( windowPos + heights.windowHeight ) <= ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight + borderWidth ) ) { fixedBottom = true; + $statusBar.css( { + position: 'fixed', + bottom: heights.bottomHeight, + width: contentWrapWidth - ( borderWidth * 2 ) + } ); + $bottom.css( { position: 'fixed', bottom: 0, - width: contentWrapWidth, - borderTop: '1px solid #dedede' + width: contentWrapWidth } ); } else if ( ( fixedBottom || resize ) && - ( windowPos + windowHeight ) > ( editorPos + editorHeight + bottomHeight + statusBarHeight - borderWidth ) ) { + ( windowPos + heights.windowHeight ) > ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight - borderWidth ) ) { fixedBottom = false; - $bottom.css( { - position: 'relative', - bottom: 'auto', - width: '100%', - borderTop: 'none' - } ); + $statusBar.add( $bottom ).attr( 'style', '' ); } } // Sidebar pinning - if ( $postboxContainer.width() < 300 && windowWidth > 600 && // sidebar position is changed with @media from CSS, make sure it is on the side + if ( $postboxContainer.width() < 300 && heights.windowWidth > 600 && // sidebar position is changed with @media from CSS, make sure it is on the side $document.height() > ( $sideSortables.height() + postBodyTop + 120 ) && // the sidebar is not the tallest element - windowHeight < editorHeight ) { // the editor is taller than the viewport + heights.windowHeight < editorHeight ) { // the editor is taller than the viewport - if ( sideSortablesHeight > windowHeight || fixedSideTop || fixedSideBottom ) { + if ( heights.sideSortablesHeight > heights.windowHeight || fixedSideTop || fixedSideBottom ) { // Reset when scrolling to the top if ( windowPos + pinnedToolsTop <= postBodyTop ) { $sideSortables.attr( 'style', '' ); @@ -375,12 +426,12 @@ jQuery( document ).ready( function($) { if ( fixedSideTop ) { // let it scroll fixedSideTop = false; - sidebarTop = $sideSortables.offset().top - adminBarHeight; + sidebarTop = $sideSortables.offset().top - heights.adminBarHeight; footerTop = $footer.offset().top; // don't get over the footer - if ( footerTop < sidebarTop + sideSortablesHeight + 20 ) { - sidebarTop = footerTop - sideSortablesHeight - 20; + if ( footerTop < sidebarTop + heights.sideSortablesHeight + 20 ) { + sidebarTop = footerTop - heights.sideSortablesHeight - 20; } $sideSortables.css({ @@ -388,7 +439,7 @@ jQuery( document ).ready( function($) { top: sidebarTop, bottom: '' }); - } else if ( ! fixedSideBottom && sideSortablesHeight + $sideSortables.offset().top + 20 < windowPos + windowHeight ) { + } else if ( ! fixedSideBottom && heights.sideSortablesHeight + $sideSortables.offset().top + 20 < windowPos + heights.windowHeight ) { // pin the bottom fixedSideBottom = true; @@ -407,8 +458,8 @@ jQuery( document ).ready( function($) { footerTop = $footer.offset().top; // don't get over the footer - if ( footerTop < sidebarTop + sideSortablesHeight + 20 ) { - sidebarTop = footerTop - sideSortablesHeight - 20; + if ( footerTop < sidebarTop + heights.sideSortablesHeight + 20 ) { + sidebarTop = footerTop - heights.sideSortablesHeight - 20; } $sideSortables.css({ @@ -450,16 +501,16 @@ jQuery( document ).ready( function($) { if ( resize ) { $contentWrap.css( { - paddingTop: $tools.outerHeight() + paddingTop: heights.toolsHeight } ); if ( visual ) { $visualEditor.css( { - paddingTop: $visualTop.outerHeight() + paddingTop: heights.visualTopHeight + heights.menuBarHeight } ); } else { $textEditor.css( { - marginTop: $textTop.outerHeight() + marginTop: heights.textTopHeight } ); $textEditorClone.width( contentWrapWidth - 20 - ( borderWidth * 2 ) ); @@ -554,7 +605,7 @@ jQuery( document ).ready( function($) { fullscreen && fullscreen.pubsub.unsubscribe( 'hidden', fullscreenHide ); // Reset all css - $.each( [ $visualTop, $textTop, $tools, $bottom, $contentWrap, $visualEditor, $textEditor, $sideSortables ], function( i, element ) { + $.each( [ $visualTop, $textTop, $tools, $menuBar, $bottom, $statusBar, $contentWrap, $visualEditor, $textEditor, $sideSortables ], function( i, element ) { element && element.attr( 'style', '' ); }); diff --git a/src/wp-includes/css/editor.css b/src/wp-includes/css/editor.css index 897bfa9f31..084f606ee6 100644 --- a/src/wp-includes/css/editor.css +++ b/src/wp-includes/css/editor.css @@ -152,7 +152,6 @@ div.mce-toolbar-grp { background: #f5f5f5; padding: 0; position: relative; - z-index: 999; } div.mce-toolbar-grp > div { @@ -368,6 +367,8 @@ div.mce-path { /* Menubar */ .mce-menubar { border-color: #e5e5e5; + background: #fff; + border-width: 0px 0px 1px; } .mce-menubar .mce-btn:focus { @@ -759,11 +760,9 @@ i.mce-i-hr:before { position: relative; } -#wp-content-editor-tools { - background-color: #f1f1f1; - padding-top: 20px; +.wp-editor-tools { position: relative; - z-index: 1000; + z-index: 1; } .wp-editor-tools:after { diff --git a/src/wp-includes/css/media-views.css b/src/wp-includes/css/media-views.css index 0835faa675..65293740c2 100644 --- a/src/wp-includes/css/media-views.css +++ b/src/wp-includes/css/media-views.css @@ -150,6 +150,7 @@ } .media-modal-close:active { + -webkit-box-shadow: none; box-shadow: none; } diff --git a/src/wp-includes/js/mce-view.js b/src/wp-includes/js/mce-view.js index d3ea8fc4ae..a5b1806af4 100644 --- a/src/wp-includes/js/mce-view.js +++ b/src/wp-includes/js/mce-view.js @@ -592,7 +592,7 @@ window.wp = window.wp || {}; fail: function( error ) { if ( ! this.error ) { if ( error ) { - this.error = error + this.error = error; } else { return; }