diff --git a/src/wp-admin/edit-form-advanced.php b/src/wp-admin/edit-form-advanced.php index 709779b6be..158271d195 100644 --- a/src/wp-admin/edit-form-advanced.php +++ b/src/wp-admin/edit-form-advanced.php @@ -512,7 +512,6 @@ if ( post_type_supports($post_type, 'editor') ) {
post_content, 'content', array( - 'dfw' => true, 'drag_drop_upload' => true, 'tabfocus_elements' => 'content-html,save-post', 'editor_height' => 300, diff --git a/src/wp-admin/js/editor-expand.js b/src/wp-admin/js/editor-expand.js index b877565b8c..9085c27b16 100644 --- a/src/wp-admin/js/editor-expand.js +++ b/src/wp-admin/js/editor-expand.js @@ -1,409 +1,357 @@ -/* global tinymce */ +( function( window, $, undefined ) { + 'use strict'; -window.wp = window.wp || {}; - -jQuery( document ).ready( function( $ ) { var $window = $( window ), $document = $( document ), $adminBar = $( '#wpadminbar' ), - $footer = $( '#wpfooter' ), - $wrap = $( '#postdivrich' ), - $contentWrap = $( '#wp-content-wrap' ), - $tools = $( '#wp-content-editor-tools' ), - $visualTop = $(), - $visualEditor = $(), - $textTop = $( '#ed_toolbar' ), - $textEditor = $( '#content' ), - $textEditorClone = $( '
' ), - $bottom = $( '#post-status-info' ), - $menuBar = $(), - $statusBar = $(), - $sideSortables = $( '#side-sortables' ), - $postboxContainer = $( '#postbox-container-1' ), - $postBody = $('#post-body'), - fullscreen = window.wp.editor && window.wp.editor.fullscreen, - mceEditor, - mceBind = function(){}, - mceUnbind = function(){}, - fixedTop = false, - fixedBottom = false, - fixedSideTop = false, - fixedSideBottom = false, - scrollTimer, - lastScrollPosition = 0, - pageYOffsetAtTop = 130, - pinnedToolsTop = 56, - sidebarBottom = 20, - autoresizeMinHeight = 300, - initialMode = window.getUserSetting( 'editor' ), - // 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 - }; + $footer = $( '#wpfooter' ); - $textEditorClone.insertAfter( $textEditor ); + /* Autoresize editor. */ + $( function() { + var $wrap = $( '#postdivrich' ), + $contentWrap = $( '#wp-content-wrap' ), + $tools = $( '#wp-content-editor-tools' ), + $visualTop = $(), + $visualEditor = $(), + $textTop = $( '#ed_toolbar' ), + $textEditor = $( '#content' ), + $textEditorClone = $( '
' ), + $bottom = $( '#post-status-info' ), + $menuBar = $(), + $statusBar = $(), + $sideSortables = $( '#side-sortables' ), + $postboxContainer = $( '#postbox-container-1' ), + $postBody = $('#post-body'), + fullscreen = window.wp.editor && window.wp.editor.fullscreen, + mceEditor, + mceBind = function(){}, + mceUnbind = function(){}, + fixedTop = false, + fixedBottom = false, + fixedSideTop = false, + fixedSideBottom = false, + scrollTimer, + lastScrollPosition = 0, + pageYOffsetAtTop = 130, + pinnedToolsTop = 56, + sidebarBottom = 20, + autoresizeMinHeight = 300, + initialMode = window.getUserSetting( 'editor' ), + advanced = !! parseInt( window.getUserSetting( 'hidetb' ), 10 ), + // 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.css( { - 'font-family': $textEditor.css( 'font-family' ), - 'font-size': $textEditor.css( 'font-size' ), - 'line-height': $textEditor.css( 'line-height' ), - 'white-space': 'pre-wrap', - 'word-wrap': 'break-word' - } ); + $textEditorClone.insertAfter( $textEditor ); - function getHeights() { - var windowWidth = $window.width(); + $textEditorClone.css( { + 'font-family': $textEditor.css( 'font-family' ), + 'font-size': $textEditor.css( 'font-size' ), + 'line-height': $textEditor.css( 'line-height' ), + 'white-space': 'pre-wrap', + 'word-wrap': 'break-word' + } ); - 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 getHeights() { + var windowWidth = $window.width(); - // Adjust for hidden - if ( heights.menuBarHeight < 3 ) { - heights.menuBarHeight = 0; - } - } + 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, - range = document.createRange(), - selStart = $textEditor[0].selectionStart, - selEnd = $textEditor[0].selectionEnd, - textNode = $textEditorClone[0].firstChild, - buffer = 10, - offset, cursorTop, cursorBottom, editorTop, editorBottom; - - if ( selStart && selEnd && selStart !== selEnd ) { - return; - } - - // These are not TinyMCE ranges. - try { - range.setStart( textNode, selStart ); - range.setEnd( textNode, selEnd + 1 ); - } catch ( ex ) {} - - offset = range.getBoundingClientRect(); - - if ( ! offset.height ) { - return; - } - - cursorTop = offset.top - buffer; - cursorBottom = cursorTop + offset.height + buffer; - 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 ); - } else if ( cursorBottom > editorBottom ) { - window.scrollTo( window.pageXOffset, cursorBottom + window.pageYOffset - editorBottom ); - } - } - - function textEditorResize() { - if ( ( mceEditor && ! mceEditor.isHidden() ) || ( ! mceEditor && initialMode === 'tinymce' ) ) { - return; - } - - var textEditorHeight = $textEditor.height(), - hiddenHeight; - - $textEditorClone.width( $textEditor.width() - 22 ); - $textEditorClone.text( $textEditor.val() + ' ' ); - - hiddenHeight = $textEditorClone.height(); - - if ( hiddenHeight < autoresizeMinHeight ) { - hiddenHeight = autoresizeMinHeight; - } - - if ( hiddenHeight === textEditorHeight ) { - return; - } - - $textEditor.height( hiddenHeight ); - - adjust(); - } - - // We need to wait for TinyMCE to initialize. - $document.on( 'tinymce-editor-init.editor-expand', function( event, editor ) { - var hideFloatPanels = _.debounce( function() { - ! $( '.mce-floatpanel:hover' ).length && tinymce.ui.FloatPanel.hideAll(); - $( '.mce-tooltip' ).hide(); - }, 1000, true ); - - // Make sure it's the main editor. - if ( editor.id !== 'content' ) { - return; - } - - // Copy the editor instance. - mceEditor = editor; - - // Set the minimum height to the initial viewport height. - editor.settings.autoresize_min_height = autoresizeMinHeight; - - // Get the necessary UI elements. - $visualTop = $contentWrap.find( '.mce-toolbar-grp' ); - $visualEditor = $contentWrap.find( '.mce-edit-area' ); - $statusBar = $contentWrap.find( '.mce-statusbar' ); - $menuBar = $contentWrap.find( '.mce-menubar' ); - - function mceGetCursorOffset() { - var node = editor.selection.getNode(), - range, view, offset; - - if ( editor.plugins.wpview && ( view = editor.plugins.wpview.getView( node ) ) ) { - offset = view.getBoundingClientRect(); - } else { - range = editor.selection.getRng(); - - try { - offset = range.getClientRects()[0]; - } catch( er ) {} - - if ( ! offset ) { - offset = node.getBoundingClientRect(); - } + // Adjust for hidden + if ( heights.menuBarHeight < 3 ) { + heights.menuBarHeight = 0; } - - return offset.height ? offset : false; } - // Make sure the cursor is always visible. - // This is not only necessary to keep the cursor between the toolbars, - // but also to scroll the window when the cursor moves out of the viewport to a wpview. - // Setting a buffer > 0 will prevent the browser default. - // Some browsers will scroll to the middle, - // others to the top/bottom of the *window* when moving the cursor out of the viewport. - function mceKeyup( event ) { - var VK = tinymce.util.VK, - key = event.keyCode; - - // Bail on special keys. - if ( key <= 47 && ! ( key === VK.SPACEBAR || key === VK.ENTER || key === VK.DELETE || key === VK.BACKSPACE || - key === VK.UP || key === VK.RIGHT || key === VK.DOWN || key === VK.LEFT ) ) { - - return; - // OS keys, function keys, num lock, scroll lock - } else if ( ( key >= 91 && key <= 93 ) || ( key >= 112 && key <= 123 ) || key === 144 || key === 145 ) { - return; - } - - mceScroll( key ); - } - - function mceScroll( key ) { - var VK = tinymce.util.VK, - offset = mceGetCursorOffset(), + function textEditorKeyup( event ) { + var VK = jQuery.ui.keyCode, + key = event.keyCode, + range = document.createRange(), + selStart = $textEditor[0].selectionStart, + selEnd = $textEditor[0].selectionEnd, + textNode = $textEditorClone[0].firstChild, buffer = 10, - cursorTop, cursorBottom, editorTop, editorBottom; + offset, cursorTop, cursorBottom, editorTop, editorBottom; - if ( ! offset ) { + if ( selStart && selEnd && selStart !== selEnd ) { return; } - cursorTop = offset.top + editor.iframeElement.getBoundingClientRect().top; + // These are not TinyMCE ranges. + try { + range.setStart( textNode, selStart ); + range.setEnd( textNode, selEnd + 1 ); + } catch ( ex ) {} + + offset = range.getBoundingClientRect(); + + if ( ! offset.height ) { + return; + } + + cursorTop = offset.top - buffer; cursorBottom = cursorTop + offset.height + buffer; - cursorTop -= buffer; - 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 ) { - return; - } - - // WebKit browsers scroll-into-view to the middle of the window but not for arrow keys/backspace. - // The others scroll to the top of the window, we need to account for the adminbar and editor toolbar(s). - if ( cursorTop < editorTop && ( ! tinymce.Env.webkit || - ( key === VK.UP || key === VK.RIGHT || key === VK.DOWN || key === VK.LEFT || key === VK.BACKSPACE ) ) ) { + 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 ); } else if ( cursorBottom > editorBottom ) { window.scrollTo( window.pageXOffset, cursorBottom + window.pageYOffset - editorBottom ); } } - // Adjust when switching editor modes. - function mceShow() { - $window.on( 'scroll.mce-float-panels', hideFloatPanels ); + function textEditorResize() { + if ( ( mceEditor && ! mceEditor.isHidden() ) || ( ! mceEditor && initialMode === 'tinymce' ) ) { + return; + } - setTimeout( function() { - editor.execCommand( 'wpAutoResize' ); - adjust(); - }, 300 ); - } + var textEditorHeight = $textEditor.height(), + hiddenHeight; - function mceHide() { - $window.off( 'scroll.mce-float-panels' ); + $textEditorClone.width( $textEditor.width() - 22 ); + $textEditorClone.text( $textEditor.val() + ' ' ); - setTimeout( function() { - var top = $contentWrap.offset().top; + hiddenHeight = $textEditorClone.height(); - if ( window.pageYOffset > top ) { - window.scrollTo( window.pageXOffset, top - heights.adminBarHeight ); - } + if ( hiddenHeight < autoresizeMinHeight ) { + hiddenHeight = autoresizeMinHeight; + } - textEditorResize(); - adjust(); - }, 100 ); + if ( hiddenHeight === textEditorHeight ) { + return; + } + + $textEditor.height( hiddenHeight ); adjust(); } - mceBind = function() { - editor.on( 'keyup', mceKeyup ); - editor.on( 'show', mceShow ); - editor.on( 'hide', mceHide ); - // Adjust when the editor resizes. - editor.on( 'setcontent wp-autoresize wp-toolbar-toggle', adjust ); - // Scroll to the caret or selection after undo/redo - editor.on( 'undo redo', mceScroll ); + // We need to wait for TinyMCE to initialize. + $document.on( 'tinymce-editor-init.editor-expand', function( event, editor ) { + var VK = window.tinymce.util.VK, + hideFloatPanels = _.debounce( function() { + ! $( '.mce-floatpanel:hover' ).length && window.tinymce.ui.FloatPanel.hideAll(); + $( '.mce-tooltip' ).hide(); + }, 1000, true ); - $window.off( 'scroll.mce-float-panels' ).on( 'scroll.mce-float-panels', hideFloatPanels ); - }; - - mceUnbind = function() { - editor.off( 'keyup', mceKeyup ); - editor.off( 'show', mceShow ); - editor.off( 'hide', mceHide ); - editor.off( 'setcontent wp-autoresize wp-toolbar-toggle', adjust ); - editor.off( 'undo redo', mceScroll ); - - $window.off( 'scroll.mce-float-panels' ); - }; - - if ( $wrap.hasClass( 'wp-editor-expand' ) ) { - // Adjust "immediately" - mceBind(); - initialResize( adjust ); - } - } ); - - // Adjust the toolbars based on the active editor mode. - function adjust( type ) { - // Make sure we're not in fullscreen mode. - if ( fullscreen && fullscreen.settings.visible ) { - return; - } - - var windowPos = $window.scrollTop(), - resize = type !== 'scroll', - visual = ( mceEditor && ! mceEditor.isHidden() ), - buffer = autoresizeMinHeight, - postBodyTop = $postBody.offset().top, - borderWidth = 1, - contentWrapWidth = $contentWrap.width(), - $top, $editor, sidebarTop, footerTop, canPin, - topPos, topHeight, editorPos, editorHeight; - - // Refresh the heights - if ( resize || ! heights.windowHeight ) { - getHeights(); - } - - if ( ! visual && type === 'resize' ) { - textEditorResize(); - } - - if ( visual ) { - $top = $visualTop; - $editor = $visualEditor; - topHeight = heights.visualTopHeight; - } else { - $top = $textTop; - $editor = $textEditor; - topHeight = heights.textTopHeight; - } - - topPos = $top.parent().offset().top; - editorPos = $editor.offset().top; - editorHeight = $editor.outerHeight(); - - // Should we pin? - canPin = visual ? autoresizeMinHeight + topHeight : autoresizeMinHeight + 20; // 20px from textarea padding - canPin = editorHeight > ( canPin + 5 ); - - if ( ! canPin ) { - if ( resize ) { - $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() ) ) - } ); - - $statusBar.add( $bottom ).attr( 'style', '' ); + // Make sure it's the main editor. + if ( editor.id !== 'content' ) { + return; } - } else { - // Maybe pin the top. - if ( ( ! fixedTop || resize ) && - // Handle scrolling down. - ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight ) && - // Handle scrolling up. - windowPos <= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) ) { - fixedTop = true; - $tools.css( { - position: 'fixed', - top: heights.adminBarHeight, - width: contentWrapWidth - } ); + // Copy the editor instance. + mceEditor = editor; - if ( visual && $menuBar.length ) { - $menuBar.css( { - position: 'fixed', - top: heights.adminBarHeight + heights.toolsHeight, - width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) - } ); + // Set the minimum height to the initial viewport height. + editor.settings.autoresize_min_height = autoresizeMinHeight; + + // Get the necessary UI elements. + $visualTop = $contentWrap.find( '.mce-toolbar-grp' ); + $visualEditor = $contentWrap.find( '.mce-edit-area' ); + $statusBar = $contentWrap.find( '.mce-statusbar' ); + $menuBar = $contentWrap.find( '.mce-menubar' ); + + function mceGetCursorOffset() { + var node = editor.selection.getNode(), + range, view, offset; + + if ( editor.plugins.wpview && ( view = editor.plugins.wpview.getView( node ) ) ) { + offset = view.getBoundingClientRect(); + } else { + range = editor.selection.getRng(); + + try { + offset = range.getClientRects()[0]; + } catch( er ) {} + + if ( ! offset ) { + offset = node.getBoundingClientRect(); + } } - $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 - heights.toolsHeight - heights.adminBarHeight ) ) { - fixedTop = false; + return offset.height ? offset : false; + } + // Make sure the cursor is always visible. + // This is not only necessary to keep the cursor between the toolbars, + // but also to scroll the window when the cursor moves out of the viewport to a wpview. + // Setting a buffer > 0 will prevent the browser default. + // Some browsers will scroll to the middle, + // others to the top/bottom of the *window* when moving the cursor out of the viewport. + function mceKeyup( event ) { + var key = event.keyCode; + + // Bail on special keys. + if ( key <= 47 && ! ( key === VK.SPACEBAR || key === VK.ENTER || key === VK.DELETE || key === VK.BACKSPACE || key === VK.UP || key === VK.LEFT || key === VK.DOWN || key === VK.UP ) ) { + return; + // OS keys, function keys, num lock, scroll lock + } else if ( ( key >= 91 && key <= 93 ) || ( key >= 112 && key <= 123 ) || key === 144 || key === 145 ) { + return; + } + + mceScroll( key ); + } + + function mceScroll( key ) { + var offset = mceGetCursorOffset(), + buffer = 50, + cursorTop, cursorBottom, editorTop, editorBottom; + + if ( ! offset ) { + return; + } + + cursorTop = offset.top + editor.iframeElement.getBoundingClientRect().top; + cursorBottom = cursorTop + offset.height; + cursorTop = cursorTop - buffer; + cursorBottom = cursorBottom + buffer; + editorTop = heights.adminBarHeight + heights.toolsHeight + heights.menuBarHeight + heights.visualTopHeight; + editorBottom = heights.windowHeight - ( advanced ? heights.bottomHeight + heights.statusBarHeight : 0 ); + + // Don't scroll if the node is taller than the visible part of the editor + if ( editorBottom - editorTop < offset.height ) { + return; + } + + if ( cursorTop < editorTop && ( key === VK.UP || key === VK.LEFT || key === VK.BACKSPACE ) ) { + window.scrollTo( window.pageXOffset, cursorTop + window.pageYOffset - editorTop ); + } else if ( cursorBottom > editorBottom ) { + window.scrollTo( window.pageXOffset, cursorBottom + window.pageYOffset - editorBottom ); + } + } + + // Adjust when switching editor modes. + function mceShow() { + $window.on( 'scroll.mce-float-panels', hideFloatPanels ); + + setTimeout( function() { + editor.execCommand( 'wpAutoResize' ); + adjust(); + }, 300 ); + } + + function mceHide() { + $window.off( 'scroll.mce-float-panels' ); + + setTimeout( function() { + var top = $contentWrap.offset().top; + + if ( window.pageYOffset > top ) { + window.scrollTo( window.pageXOffset, top - heights.adminBarHeight ); + } + + textEditorResize(); + adjust(); + }, 100 ); + + adjust(); + } + + function toggleAdvanced() { + advanced = ! advanced; + } + + mceBind = function() { + editor.on( 'keyup', mceKeyup ); + editor.on( 'show', mceShow ); + editor.on( 'hide', mceHide ); + editor.on( 'wp-toolbar-toggle', toggleAdvanced ); + // Adjust when the editor resizes. + editor.on( 'setcontent wp-autoresize wp-toolbar-toggle', adjust ); + // Don't hide the caret after undo/redo + editor.on( 'undo redo', mceScroll ); + + $window.off( 'scroll.mce-float-panels' ).on( 'scroll.mce-float-panels', hideFloatPanels ); + }; + + mceUnbind = function() { + editor.off( 'keyup', mceKeyup ); + editor.off( 'show', mceShow ); + editor.off( 'hide', mceHide ); + editor.off( 'wp-toolbar-toggle', toggleAdvanced ); + editor.off( 'setcontent wp-autoresize wp-toolbar-toggle', adjust ); + editor.off( 'undo redo', mceScroll ); + + $window.off( 'scroll.mce-float-panels' ); + }; + + if ( $wrap.hasClass( 'wp-editor-expand' ) ) { + // Adjust "immediately" + mceBind(); + initialResize( adjust ); + } + } ); + + // Adjust the toolbars based on the active editor mode. + function adjust( event ) { + var type = event && event.type; + + // Make sure we're not in fullscreen mode. + if ( fullscreen && fullscreen.settings.visible ) { + return; + } + + var windowPos = $window.scrollTop(), + resize = type !== 'scroll', + visual = ( mceEditor && ! mceEditor.isHidden() ), + buffer = autoresizeMinHeight, + postBodyTop = $postBody.offset().top, + borderWidth = 1, + contentWrapWidth = $contentWrap.width(), + $top, $editor, sidebarTop, footerTop, canPin, + topPos, topHeight, editorPos, editorHeight; + + // Refresh the heights + if ( resize || ! heights.windowHeight ) { + getHeights(); + } + + if ( ! visual && type === 'resize' ) { + textEditorResize(); + } + + if ( visual ) { + $top = $visualTop; + $editor = $visualEditor; + topHeight = heights.visualTopHeight; + } else { + $top = $textTop; + $editor = $textEditor; + topHeight = heights.textTopHeight; + } + + topPos = $top.parent().offset().top; + editorPos = $editor.offset().top; + editorHeight = $editor.outerHeight(); + + // Should we pin? + canPin = visual ? autoresizeMinHeight + topHeight : autoresizeMinHeight + 20; // 20px from textarea padding + canPin = editorHeight > ( canPin + 5 ); + + if ( ! canPin ) { + if ( resize ) { $tools.css( { position: 'absolute', top: 0, @@ -423,311 +371,812 @@ jQuery( document ).ready( function( $ ) { top: heights.menuBarHeight, width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) } ); - // Handle scrolling down. - } else if ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) { - fixedTop = false; + + $statusBar.add( $bottom ).attr( 'style', '' ); + } + } else { + // Maybe pin the top. + if ( ( ! fixedTop || resize ) && + // Handle scrolling down. + ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight ) && + // Handle scrolling up. + windowPos <= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) ) { + fixedTop = true; $tools.css( { - position: 'absolute', - top: editorHeight - buffer, + position: 'fixed', + top: heights.adminBarHeight, width: contentWrapWidth } ); if ( visual && $menuBar.length ) { $menuBar.css( { - position: 'absolute', - top: editorHeight - buffer, - width: contentWrapWidth - ( borderWidth * 2 ) + position: 'fixed', + top: heights.adminBarHeight + heights.toolsHeight, + width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) } ); } $top.css( { - position: 'absolute', - top: editorHeight - buffer + heights.menuBarHeight, + 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 - heights.toolsHeight - heights.adminBarHeight ) ) { + fixedTop = false; - // Maybe adjust the bottom bar. - if ( ( ! fixedBottom || resize ) && - // +[n] for the border around the .wp-editor-container. - ( windowPos + heights.windowHeight ) <= ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight + borderWidth ) ) { - fixedBottom = true; + $tools.css( { + position: 'absolute', + top: 0, + width: contentWrapWidth + } ); - $statusBar.css( { - position: 'fixed', - bottom: heights.bottomHeight, - width: contentWrapWidth - ( borderWidth * 2 ) - } ); - - $bottom.css( { - position: 'fixed', - bottom: 0, - width: contentWrapWidth - } ); - } else if ( ( fixedBottom || resize ) && - ( windowPos + heights.windowHeight ) > ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight - borderWidth ) ) { - fixedBottom = false; - - $statusBar.add( $bottom ).attr( 'style', '' ); - } - } - - // Sidebar pinning - 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 - heights.windowHeight < editorHeight ) { // the editor is taller than the viewport - - if ( ( heights.sideSortablesHeight + pinnedToolsTop + sidebarBottom ) > heights.windowHeight || fixedSideTop || fixedSideBottom ) { - // Reset when scrolling to the top - if ( windowPos + pinnedToolsTop <= postBodyTop ) { - $sideSortables.attr( 'style', '' ); - fixedSideTop = fixedSideBottom = false; - } else { - if ( windowPos > lastScrollPosition ) { - // Scrolling down - if ( fixedSideTop ) { - // let it scroll - fixedSideTop = false; - sidebarTop = $sideSortables.offset().top - heights.adminBarHeight; - footerTop = $footer.offset().top; - - // don't get over the footer - if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) { - sidebarTop = footerTop - heights.sideSortablesHeight - 12; - } - - $sideSortables.css({ + if ( visual && $menuBar.length ) { + $menuBar.css( { position: 'absolute', - top: sidebarTop, - bottom: '' - }); - } else if ( ! fixedSideBottom && heights.sideSortablesHeight + $sideSortables.offset().top + sidebarBottom < windowPos + heights.windowHeight ) { - // pin the bottom - fixedSideBottom = true; - - $sideSortables.css({ - position: 'fixed', - top: 'auto', - bottom: sidebarBottom - }); + top: 0, + width: contentWrapWidth - ( borderWidth * 2 ) + } ); } - } else if ( windowPos < lastScrollPosition ) { - // Scrolling up - if ( fixedSideBottom ) { - // let it scroll - fixedSideBottom = false; - sidebarTop = $sideSortables.offset().top - sidebarBottom; - footerTop = $footer.offset().top; - // don't get over the footer - if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) { - sidebarTop = footerTop - heights.sideSortablesHeight - 12; - } + $top.css( { + position: 'absolute', + top: heights.menuBarHeight, + width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) ) + } ); + // Handle scrolling down. + } else if ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) { + fixedTop = false; - $sideSortables.css({ + $tools.css( { + position: 'absolute', + top: editorHeight - buffer, + width: contentWrapWidth + } ); + + if ( visual && $menuBar.length ) { + $menuBar.css( { position: 'absolute', - top: sidebarTop, - bottom: '' - }); - } else if ( ! fixedSideTop && $sideSortables.offset().top >= windowPos + pinnedToolsTop ) { - // pin the top - fixedSideTop = true; - - $sideSortables.css({ - position: 'fixed', - top: pinnedToolsTop, - bottom: '' - }); + 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() ) ) + } ); } } - } else { - // if the sidebar container is smaller than the viewport, then pin/unpin the top when scrolling - if ( windowPos >= ( postBodyTop - pinnedToolsTop ) ) { - $sideSortables.css( { - position: 'fixed', - top: pinnedToolsTop - } ); + // Maybe adjust the bottom bar. + if ( ( ! fixedBottom || ( resize && advanced ) ) && + // +[n] for the border around the .wp-editor-container. + ( windowPos + heights.windowHeight ) <= ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight + borderWidth ) ) { + + if ( event && event.deltaHeight > 0 ) { + window.scrollBy( 0, event.deltaHeight ); + } else if ( advanced ) { + fixedBottom = true; + + $statusBar.css( { + position: 'fixed', + bottom: heights.bottomHeight, + visibility: '', + width: contentWrapWidth - ( borderWidth * 2 ) + } ); + + $bottom.css( { + position: 'fixed', + bottom: 0, + width: contentWrapWidth + } ); + } + } else if ( ( ! advanced && fixedBottom ) || + ( ( fixedBottom || resize ) && + ( windowPos + heights.windowHeight ) > ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight - borderWidth ) ) ) { + fixedBottom = false; + + $statusBar.add( $bottom ).attr( 'style', '' ); + + ! advanced && $statusBar.css( 'visibility', 'hidden' ); + } + } + + // Sidebar pinning + 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 + heights.windowHeight < editorHeight ) { // the editor is taller than the viewport + + if ( ( heights.sideSortablesHeight + pinnedToolsTop + sidebarBottom ) > heights.windowHeight || fixedSideTop || fixedSideBottom ) { + // Reset when scrolling to the top + if ( windowPos + pinnedToolsTop <= postBodyTop ) { + $sideSortables.attr( 'style', '' ); + fixedSideTop = fixedSideBottom = false; + } else { + if ( windowPos > lastScrollPosition ) { + // Scrolling down + if ( fixedSideTop ) { + // let it scroll + fixedSideTop = false; + sidebarTop = $sideSortables.offset().top - heights.adminBarHeight; + footerTop = $footer.offset().top; + + // don't get over the footer + if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) { + sidebarTop = footerTop - heights.sideSortablesHeight - 12; + } + + $sideSortables.css({ + position: 'absolute', + top: sidebarTop, + bottom: '' + }); + } else if ( ! fixedSideBottom && heights.sideSortablesHeight + $sideSortables.offset().top + sidebarBottom < windowPos + heights.windowHeight ) { + // pin the bottom + fixedSideBottom = true; + + $sideSortables.css({ + position: 'fixed', + top: 'auto', + bottom: sidebarBottom + }); + } + } else if ( windowPos < lastScrollPosition ) { + // Scrolling up + if ( fixedSideBottom ) { + // let it scroll + fixedSideBottom = false; + sidebarTop = $sideSortables.offset().top - sidebarBottom; + footerTop = $footer.offset().top; + + // don't get over the footer + if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) { + sidebarTop = footerTop - heights.sideSortablesHeight - 12; + } + + $sideSortables.css({ + position: 'absolute', + top: sidebarTop, + bottom: '' + }); + } else if ( ! fixedSideTop && $sideSortables.offset().top >= windowPos + pinnedToolsTop ) { + // pin the top + fixedSideTop = true; + + $sideSortables.css({ + position: 'fixed', + top: pinnedToolsTop, + bottom: '' + }); + } + } + } } else { - $sideSortables.attr( 'style', '' ); + // if the sidebar container is smaller than the viewport, then pin/unpin the top when scrolling + if ( windowPos >= ( postBodyTop - pinnedToolsTop ) ) { + + $sideSortables.css( { + position: 'fixed', + top: pinnedToolsTop + } ); + } else { + $sideSortables.attr( 'style', '' ); + } + + fixedSideTop = fixedSideBottom = false; } + lastScrollPosition = windowPos; + } else { + $sideSortables.attr( 'style', '' ); fixedSideTop = fixedSideBottom = false; } - lastScrollPosition = windowPos; - } else { - $sideSortables.attr( 'style', '' ); - fixedSideTop = fixedSideBottom = false; - } - - if ( resize ) { - $contentWrap.css( { - paddingTop: heights.toolsHeight - } ); - - if ( visual ) { - $visualEditor.css( { - paddingTop: heights.visualTopHeight + heights.menuBarHeight - } ); - } else { - $textEditor.css( { - marginTop: heights.textTopHeight + if ( resize ) { + $contentWrap.css( { + paddingTop: heights.toolsHeight } ); - $textEditorClone.width( contentWrapWidth - 20 - ( borderWidth * 2 ) ); + if ( visual ) { + $visualEditor.css( { + paddingTop: heights.visualTopHeight + heights.menuBarHeight + } ); + } else { + $textEditor.css( { + marginTop: heights.textTopHeight + } ); + + $textEditorClone.width( contentWrapWidth - 20 - ( borderWidth * 2 ) ); + } } } - } - function fullscreenHide() { - textEditorResize(); - adjust(); - } - - function initialResize( callback ) { - for ( var i = 1; i < 6; i++ ) { - setTimeout( callback, 500 * i ); - } - } - - function afterScroll() { - clearTimeout( scrollTimer ); - scrollTimer = setTimeout( adjust, 100 ); - } - - function on() { - // Scroll to the top when triggering this from JS. - // Ensures toolbars are pinned properly. - if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) { - window.scrollTo( window.pageXOffset, 0 ); + function fullscreenHide() { + textEditorResize(); + adjust(); } - $wrap.addClass( 'wp-editor-expand' ); + function initialResize( callback ) { + for ( var i = 1; i < 6; i++ ) { + setTimeout( callback, 500 * i ); + } + } - // Adjust when the window is scrolled or resized. - $window.on( 'scroll.editor-expand resize.editor-expand', function( event ) { - adjust( event.type ); - afterScroll(); - } ); + function afterScroll() { + clearTimeout( scrollTimer ); + scrollTimer = setTimeout( adjust, 100 ); + } + + function on() { + // Scroll to the top when triggering this from JS. + // Ensures toolbars are pinned properly. + if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) { + window.scrollTo( window.pageXOffset, 0 ); + } + + $wrap.addClass( 'wp-editor-expand' ); + + // Adjust when the window is scrolled or resized. + $window.on( 'scroll.editor-expand resize.editor-expand', function( event ) { + adjust( event.type ); + afterScroll(); + } ); + + // Adjust when collapsing the menu, changing the columns, changing the body class. + $document.on( 'wp-collapse-menu.editor-expand postboxes-columnchange.editor-expand editor-classchange.editor-expand', adjust ) + .on( 'postbox-toggled.editor-expand', function() { + if ( ! fixedSideTop && ! fixedSideBottom && window.pageYOffset > pinnedToolsTop ) { + fixedSideBottom = true; + window.scrollBy( 0, -1 ); + adjust(); + window.scrollBy( 0, 1 ); + } - // Adjust when collapsing the menu, changing the columns, changing the body class. - $document.on( 'wp-collapse-menu.editor-expand postboxes-columnchange.editor-expand editor-classchange.editor-expand', adjust ) - .on( 'postbox-toggled.editor-expand', function() { - if ( ! fixedSideTop && ! fixedSideBottom && window.pageYOffset > pinnedToolsTop ) { - fixedSideBottom = true; - window.scrollBy( 0, -1 ); adjust(); - window.scrollBy( 0, 1 ); - } + }).on( 'wp-window-resized.editor-expand', function() { + if ( mceEditor && ! mceEditor.isHidden() ) { + mceEditor.execCommand( 'wpAutoResize' ); + } else { + textEditorResize(); + } + }); - adjust(); - }).on( 'wp-window-resized.editor-expand', function() { - if ( mceEditor && ! mceEditor.isHidden() ) { + $textEditor.on( 'focus.editor-expand input.editor-expand propertychange.editor-expand', textEditorResize ); + $textEditor.on( 'keyup.editor-expand', textEditorKeyup ); + mceBind(); + + // Adjust when entering/exiting fullscreen mode. + fullscreen && fullscreen.pubsub.subscribe( 'hidden', fullscreenHide ); + + if ( mceEditor ) { + mceEditor.settings.wp_autoresize_on = true; + mceEditor.execCommand( 'wpAutoResizeOn' ); + + if ( ! mceEditor.isHidden() ) { mceEditor.execCommand( 'wpAutoResize' ); - } else { - textEditorResize(); } + } + + if ( ! mceEditor || mceEditor.isHidden() ) { + textEditorResize(); + } + + adjust(); + + $document.trigger( 'editor-expand-on' ); + } + + function off() { + var height = window.getUserSetting('ed_size'); + + // Scroll to the top when triggering this from JS. + // Ensures toolbars are reset properly. + if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) { + window.scrollTo( window.pageXOffset, 0 ); + } + + $wrap.removeClass( 'wp-editor-expand' ); + + $window.off( '.editor-expand' ); + $document.off( '.editor-expand' ); + $textEditor.off( '.editor-expand' ); + mceUnbind(); + + // Adjust when entering/exiting fullscreen mode. + fullscreen && fullscreen.pubsub.unsubscribe( 'hidden', fullscreenHide ); + + // Reset all css + $.each( [ $visualTop, $textTop, $tools, $menuBar, $bottom, $statusBar, $contentWrap, $visualEditor, $textEditor, $sideSortables ], function( i, element ) { + element && element.attr( 'style', '' ); }); - $textEditor.on( 'focus.editor-expand input.editor-expand propertychange.editor-expand', textEditorResize ); - $textEditor.on( 'keyup.editor-expand', textEditorKeyup ); - mceBind(); + fixedTop = fixedBottom = fixedSideTop = fixedSideBottom = false; - // Adjust when entering/exiting fullscreen mode. - fullscreen && fullscreen.pubsub.subscribe( 'hidden', fullscreenHide ); + if ( mceEditor ) { + mceEditor.settings.wp_autoresize_on = false; + mceEditor.execCommand( 'wpAutoResizeOff' ); - if ( mceEditor ) { - mceEditor.settings.wp_autoresize_on = true; - mceEditor.execCommand( 'wpAutoResizeOn' ); + if ( ! mceEditor.isHidden() ) { + $textEditor.hide(); - if ( ! mceEditor.isHidden() ) { - mceEditor.execCommand( 'wpAutoResize' ); - } - } - - if ( ! mceEditor || mceEditor.isHidden() ) { - textEditorResize(); - } - - adjust(); - } - - function off() { - var height = window.getUserSetting('ed_size'); - - // Scroll to the top when triggering this from JS. - // Ensures toolbars are reset properly. - if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) { - window.scrollTo( window.pageXOffset, 0 ); - } - - $wrap.removeClass( 'wp-editor-expand' ); - - $window.off( '.editor-expand' ); - $document.off( '.editor-expand' ); - $textEditor.off( '.editor-expand' ); - mceUnbind(); - - // Adjust when entering/exiting fullscreen mode. - fullscreen && fullscreen.pubsub.unsubscribe( 'hidden', fullscreenHide ); - - // Reset all css - $.each( [ $visualTop, $textTop, $tools, $menuBar, $bottom, $statusBar, $contentWrap, $visualEditor, $textEditor, $sideSortables ], function( i, element ) { - element && element.attr( 'style', '' ); - }); - - fixedTop = fixedBottom = fixedSideTop = fixedSideBottom = false; - - if ( mceEditor ) { - mceEditor.settings.wp_autoresize_on = false; - mceEditor.execCommand( 'wpAutoResizeOff' ); - - if ( ! mceEditor.isHidden() ) { - $textEditor.hide(); - - if ( height ) { - mceEditor.theme.resizeTo( null, height ); + if ( height ) { + mceEditor.theme.resizeTo( null, height ); + } } } + + if ( height ) { + $textEditor.height( height ); + } + + $document.trigger( 'editor-expand-off' ); } - if ( height ) { - $textEditor.height( height ); - } - } - - // Start on load - if ( $wrap.hasClass( 'wp-editor-expand' ) ) { - on(); - - // Ideally we need to resize just after CSS has fully loaded and QuickTags is ready. - if ( $contentWrap.hasClass( 'html-active' ) ) { - initialResize( function() { - adjust(); - textEditorResize(); - } ); - } - } - - // Show the on/off checkbox - $( '#adv-settings .editor-expand' ).show(); - $( '#editor-expand-toggle' ).on( 'change.editor-expand', function() { - if ( $(this).prop( 'checked' ) ) { + // Start on load + if ( $wrap.hasClass( 'wp-editor-expand' ) ) { on(); - window.setUserSetting( 'editor_expand', 'on' ); - } else { - off(); - window.setUserSetting( 'editor_expand', 'off' ); - } - }); - // Expose on() and off() - window.editorExpand = { - on: on, - off: off - }; -}); + // Ideally we need to resize just after CSS has fully loaded and QuickTags is ready. + if ( $contentWrap.hasClass( 'html-active' ) ) { + initialResize( function() { + adjust(); + textEditorResize(); + } ); + } + } + + // Show the on/off checkbox + $( '#adv-settings .editor-expand' ).show(); + $( '#editor-expand-toggle' ).on( 'change.editor-expand', function() { + if ( $(this).prop( 'checked' ) ) { + on(); + window.setUserSetting( 'editor_expand', 'on' ); + } else { + off(); + window.setUserSetting( 'editor_expand', 'off' ); + } + }); + + // Expose on() and off() + window.editorExpand = { + on: on, + off: off + }; + } ); + + /* DFW. */ + $( function() { + var $body = $( document.body ), + $wrap = $( '#wpcontent' ), + $editor = $( '#post-body-content' ), + $title = $( '#title' ), + $content = $( '#content' ), + $overlay = $( document.createElement( 'DIV' ) ), + $slug = $( '#edit-slug-box' ), + $slugFocusEl = $slug.find( 'a' ) + .add( $slug.find( 'button' ) ) + .add( $slug.find( 'input' ) ), + $menuWrap = $( '#adminmenuwrap' ), + $editorWindow = $(), + $editorIframe = $(), + _isActive = window.getUserSetting( 'editor_expand', 'on' ) === 'on', + _isOn = _isActive ? !! parseInt( window.getUserSetting( 'dfw', '1' ), 10 ) : false, + traveledX = 0, + traveledY = 0, + buffer = 20, + faded, fadedAdminBar, fadedSlug, + editorRect, x, y, mouseY, scrollY, + focusLostTimer, overlayTimer, editorHasFocus; + + $body.append( $overlay ); + + $overlay.css( { + display: 'none', + position: 'fixed', + top: $adminBar.height(), + right: 0, + bottom: 0, + left: 0, + 'z-index': 9997 + } ); + + $editor.css( { + position: 'relative' + } ); + + $window.on( 'mousemove.focus', function( event ) { + mouseY = event.pageY; + } ); + + function activate() { + if ( ! _isActive ) { + _isActive = true; + + $document.trigger( 'dfw-activate' ); + } + } + + function deactivate() { + if ( _isActive ) { + off(); + + _isActive = false; + + $document.trigger( 'dfw-deactivate' ); + } + } + + function isActive() { + return _isActive; + } + + function on() { + if ( ! _isOn && _isActive ) { + _isOn = true; + + $content.on( 'keydown.focus', fadeOut ); + + $title.add( $content ).on( 'blur.focus', maybeFadeIn ); + + fadeOut(); + + window.setUserSetting( 'dfw', '1' ); + + $document.trigger( 'dfw-on' ); + } + } + + function off() { + if ( _isOn ) { + _isOn = false; + + $title.add( $content ).off( '.focus' ); + + fadeIn(); + + $editor.off( '.focus' ); + + window.setUserSetting( 'dfw', '0' ); + + $document.trigger( 'dfw-off' ); + } + } + + function toggle() { + ( _isOn ? off : on )(); + } + + function isOn() { + return _isOn; + } + + function fadeOut( event ) { + var key = event && event.keyCode; + + if ( key === 27 ) { + fadeIn(); + return; + } + + if ( event && ( event.metaKey || ( event.ctrlKey && ! event.altKey ) || ( key && ( + // Special keys ( tab, ctrl, alt, esc, arrow keys... ) + ( key <= 47 && key !== 8 && key !== 13 && key !== 32 && key !== 46 ) || + // Windows keys + ( key >= 91 && key <= 93 ) || + // F keys + ( key >= 112 && key <= 135 ) || + // Num Lock, Scroll Lock, OEM + ( key >= 144 && key <= 150 ) || + // OEM or non-printable + key >= 224 + ) ) ) ) { + return; + } + + if ( ! faded ) { + faded = true; + + clearTimeout( overlayTimer ); + + overlayTimer = setTimeout( function() { + $overlay.show(); + }, 600 ); + + $editor.css( 'z-index', 9998 ); + + $overlay + // Always recalculate the editor area entering the overlay with the mouse. + .on( 'mouseenter.focus', function() { + editorRect = $editor.offset(); + editorRect.right = editorRect.left + $editor.outerWidth(); + editorRect.bottom = editorRect.top + $editor.outerHeight(); + + $window.on( 'scroll.focus', function() { + var nScrollY = window.pageYOffset; + + if ( ( + scrollY && mouseY && + scrollY !== nScrollY + ) && ( + mouseY < editorRect.top - buffer || + mouseY > editorRect.bottom + buffer + ) ) { + fadeIn(); + } + + scrollY = nScrollY; + } ); + } ) + .on( 'mouseleave.focus', function() { + x = y = null; + traveledX = traveledY = 0; + + $window.off( 'scroll.focus' ); + } ) + // Fade in when the mouse moves away form the editor area. + .on( 'mousemove.focus', function( event ) { + var nx = event.pageX, + ny = event.pageY; + + if ( x && y && ( nx !== x || ny !== y ) ) { + if ( + ( ny <= y && ny < editorRect.top ) || + ( ny >= y && ny > editorRect.bottom ) || + ( nx <= x && nx < editorRect.left ) || + ( nx >= x && nx > editorRect.right ) + ) { + traveledX += Math.abs( x - nx ); + traveledY += Math.abs( y - ny ); + + if ( ( + ny <= editorRect.top - buffer || + ny >= editorRect.bottom + buffer || + nx <= editorRect.left - buffer || + nx >= editorRect.right + buffer + ) && ( + traveledX > 10 || + traveledY > 10 + ) ) { + fadeIn(); + + x = y = null; + traveledX = traveledY = 0; + + return; + } + } else { + traveledX = traveledY = 0; + } + } + + x = nx; + y = ny; + } ) + // When the overlay is touched, always fade in and cancel the event. + .on( 'touchstart.focus', function( event ) { + event.preventDefault(); + fadeIn(); + } ); + + $editor.off( 'mouseenter.focus' ); + + if ( focusLostTimer ) { + clearTimeout( focusLostTimer ); + focusLostTimer = null; + } + + $body.addClass( 'focus-on' ).removeClass( 'focus-off' ); + } + + fadeOutAdminBar(); + fadeOutSlug(); + } + + function fadeIn() { + if ( faded ) { + faded = false; + + clearTimeout( overlayTimer ); + + overlayTimer = setTimeout( function() { + $overlay.hide(); + }, 200 ); + + $editor.css( 'z-index', '' ); + + $overlay.off( 'mouseenter.focus mouseleave.focus mousemove.focus touchstart.focus' ); + + $editor.on( 'mouseenter.focus', function() { + if ( $.contains( $editor.get( 0 ), document.activeElement ) || editorHasFocus ) { + fadeOut(); + } + } ); + + focusLostTimer = setTimeout( function() { + focusLostTimer = null; + $editor.off( 'mouseenter.focus' ); + }, 1000 ); + + $body.addClass( 'focus-off' ).removeClass( 'focus-on' ); + } + + fadeInAdminBar(); + fadeInSlug(); + } + + function maybeFadeIn() { + setTimeout( function() { + var position = document.activeElement.compareDocumentPosition( $editor.get( 0 ) ); + + function hasFocus( $el ) { + return $.contains( $el.get( 0 ), document.activeElement ); + } + + // The focussed node is before or behind the editor area, and not ouside the wrap. + if ( ( position === 2 || position === 4 ) && ( hasFocus( $menuWrap ) || hasFocus( $wrap ) || hasFocus( $footer ) ) ) { + fadeIn(); + } + }, 0 ); + } + + function fadeOutAdminBar() { + if ( ! fadedAdminBar && faded ) { + fadedAdminBar = true; + + $adminBar + .on( 'mouseenter.focus', function() { + $adminBar.addClass( 'focus-off' ); + } ) + .on( 'mouseleave.focus', function() { + $adminBar.removeClass( 'focus-off' ); + } ); + } + } + + function fadeInAdminBar() { + if ( fadedAdminBar ) { + fadedAdminBar = false; + + $adminBar.off( '.focus' ); + } + } + + function fadeOutSlug() { + if ( ! fadedSlug && faded && ! $slug.find( ':focus').length ) { + fadedSlug = true; + + $slug.stop().fadeTo( 'fast', 0.3 ).on( 'mouseenter.focus', fadeInSlug ).off( 'mouseleave.focus' ); + + $slugFocusEl.on( 'focus.focus', fadeInSlug ).off( 'blur.focus' ); + } + } + + function fadeInSlug() { + if ( fadedSlug ) { + fadedSlug = false; + + $slug.stop().fadeTo( 'fast', 1 ).on( 'mouseleave.focus', fadeOutSlug ).off( 'mouseenter.focus' ); + + $slugFocusEl.on( 'blur.focus', fadeOutSlug ).off( 'focus.focus' ); + } + } + + $document.on( 'tinymce-editor-setup.focus', function( event, editor ) { + editor.addButton( 'dfw', { + active: _isOn, + classes: 'wp-dfw btn widget', + disabled: ! _isActive, + onclick: toggle, + onPostRender: function() { + var button = this; + + $document + .on( 'dfw-activate.focus', function() { + button.disabled( false ); + } ) + .on( 'dfw-deactivate.focus', function() { + button.disabled( true ); + } ) + .on( 'dfw-on.focus', function() { + button.active( true ); + } ) + .on( 'dfw-off.focus', function() { + button.active( false ); + } ); + }, + tooltip: 'Distraction Free Writing' + } ); + } ); + + $document.on( 'tinymce-editor-init.focus', function( event, editor ) { + var mceBind, mceUnbind; + + function focus() { + editorHasFocus = true; + } + + function blur() { + editorHasFocus = false; + } + + if ( editor.id === 'content' ) { + $editorWindow = $( editor.getWin() ); + $editorIframe = $( editor.getContentAreaContainer() ).find( 'iframe' ); + + mceBind = function() { + editor.on( 'keydown', fadeOut ); + editor.on( 'blur', maybeFadeIn ); + editor.on( 'focus', focus ); + editor.on( 'blur', blur ); + }; + + mceUnbind = function() { + editor.off( 'keydown', fadeOut ); + editor.off( 'blur', maybeFadeIn ); + editor.off( 'focus', focus ); + editor.off( 'blur', blur ); + }; + + if ( _isOn ) { + mceBind(); + } + + $document.on( 'dfw-on.focus', mceBind ).on( 'dfw-off.focus', mceUnbind ); + + // Make sure the body focusses when clicking outside it. + editor.on( 'click', function( event ) { + if ( event.target === editor.getDoc().documentElement ) { + editor.focus(); + } + } ); + } + } ); + + $document.on( 'quicktags-init', function( event, editor ) { + var $button; + + if ( editor.settings.buttons && ( ',' + editor.settings.buttons + ',' ).indexOf( ',dfw,' ) !== -1 ) { + $button = $( '#' + editor.name + '_dfw' ); + + $( document ) + .on( 'dfw-activate', function() { + $button.prop( 'disabled', false ); + } ) + .on( 'dfw-deactivate', function() { + $button.prop( 'disabled', true ); + } ) + .on( 'dfw-on', function() { + $button.addClass( 'active' ); + } ) + .on( 'dfw-off', function() { + $button.removeClass( 'active' ); + } ); + } + } ); + + $document.on( 'editor-expand-on.focus', activate ).on( 'editor-expand-off.focus', deactivate ); + + if ( _isOn ) { + $content.on( 'keydown.focus', fadeOut ); + + $title.add( $content ).on( 'blur.focus', maybeFadeIn ); + } + + window.wp = window.wp || {}; + window.wp.editor = window.wp.editor || {}; + window.wp.editor.dfw = { + activate: activate, + deactivate: deactivate, + isActive: isActive, + on: on, + off: off, + toggle: toggle, + isOn: isOn + }; + } ); +} )( window, window.jQuery ); diff --git a/src/wp-includes/class-wp-editor.php b/src/wp-includes/class-wp-editor.php index 0b62a4223b..98daeb8351 100644 --- a/src/wp-includes/class-wp-editor.php +++ b/src/wp-includes/class-wp-editor.php @@ -278,6 +278,9 @@ final class _WP_Editors { if ( $set['dfw'] ) $qtInit['buttons'] .= ',fullscreen'; + if ( $editor_id === 'content' && ! wp_is_mobile() ) + $qtInit['buttons'] .= ',dfw'; + /** * Filter the Quicktags settings. * @@ -546,6 +549,13 @@ final class _WP_Editors { $mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold', 'italic', 'underline', 'blockquote', 'strikethrough', 'bullist', 'numlist', 'alignleft', 'aligncenter', 'alignright', 'undo', 'redo', 'link', 'unlink', 'fullscreen'), $editor_id ); $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = array(); } else { + $mce_buttons = array( 'bold', 'italic', 'strikethrough', 'bullist', 'numlist', 'blockquote', 'hr', 'alignleft', 'aligncenter', 'alignright', 'link', 'unlink', 'wp_more', 'spellchecker', 'wp_adv' ); + + if ( $editor_id ) { + $mce_buttons[] = 'dfw'; + } else { + $mce_buttons[] = 'fullscreen'; + } /** * Filter the first-row list of TinyMCE buttons (Visual tab). @@ -555,7 +565,7 @@ final class _WP_Editors { * @param array $buttons First-row list of buttons. * @param string $editor_id Unique editor identifier, e.g. 'content'. */ - $mce_buttons = apply_filters( 'mce_buttons', array('bold', 'italic', 'strikethrough', 'bullist', 'numlist', 'blockquote', 'hr', 'alignleft', 'aligncenter', 'alignright', 'link', 'unlink', 'wp_more', 'spellchecker', 'fullscreen', 'wp_adv' ), $editor_id ); + $mce_buttons = apply_filters( 'mce_buttons', $mce_buttons, $editor_id ); /** * Filter the second-row list of TinyMCE buttons (Visual tab). diff --git a/src/wp-includes/css/editor.css b/src/wp-includes/css/editor.css index b6694f7d7c..15ff729d16 100644 --- a/src/wp-includes/css/editor.css +++ b/src/wp-includes/css/editor.css @@ -283,7 +283,7 @@ div.mce-path { } .mce-toolbar .mce-btn, -.qt-fullscreen { +.qt-dfw { border-color: transparent; background: transparent; -webkit-box-shadow: none; @@ -294,7 +294,7 @@ div.mce-path { #wp-fullscreen-buttons .mce-btn, .mce-toolbar .mce-btn-group .mce-btn, -.qt-fullscreen { +.qt-dfw { border: 1px solid transparent; margin: 2px; background-image: none; @@ -308,19 +308,21 @@ div.mce-path { .mce-toolbar .mce-btn-group .mce-btn:hover, #wp-fullscreen-buttons .mce-btn:focus, .mce-toolbar .mce-btn-group .mce-btn:focus, -.qt-fullscreen:hover, -.qt-fullscreen:focus { +.qt-dfw:hover, +.qt-dfw:focus { background: #fafafa; border-color: #999; color: #222; -webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba( 0, 0, 0, 0.08 ); box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba( 0, 0, 0, 0.08 ); + outline: none; } .mce-toolbar .mce-btn-group .mce-btn.mce-active, #wp-fullscreen-buttons .mce-btn.mce-active, .mce-toolbar .mce-btn-group .mce-btn:active, -#wp-fullscreen-buttons .mce-btn:active { +#wp-fullscreen-buttons .mce-btn:active, +.qt-dfw.active { background: #ebebeb; border-color: #999; -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.3 ); @@ -353,7 +355,7 @@ div.mce-path { } .mce-toolbar .mce-btn button, -.qt-fullscreen { +.qt-dfw { padding: 2px 3px; line-height: normal; } @@ -668,7 +670,7 @@ div.mce-menu .mce-menu-item-sep, padding: 0; } -.qt-fullscreen { +.qt-dfw { color: #777; line-height: 20px; width: 28px; @@ -702,6 +704,7 @@ i.mce-i-strikethrough, i.mce-i-spellchecker, i.mce-i-fullscreen, i.mce-i-wp_fullscreen, +i.mce-i-dfw, i.mce-i-wp_adv, i.mce-i-underline, i.mce-i-alignjustify, @@ -733,7 +736,7 @@ i.mce-i-dashicon, padding-right: 2px; } -.qt-fullscreen { +.qt-dfw { font: normal 20px/1 'dashicons'; vertical-align: top; speak: none; @@ -795,7 +798,8 @@ i.mce-i-spellchecker:before { i.mce-i-fullscreen:before, i.mce-i-wp_fullscreen:before, -.qt-fullscreen:before { +i.mce-i-dfw:before, +.qt-dfw:before { content: '\f211'; } @@ -1071,8 +1075,8 @@ i.mce-i-hr:before { font-weight: bold; } -.mce-toolbar .mce-btn-group .mce-btn.mce-wp-fullscreen, -.qt-fullscreen { +.mce-toolbar .mce-btn-group .mce-btn.mce-wp-dfw, +.qt-dfw { position: absolute; top: 0; right: 0; @@ -1081,7 +1085,7 @@ i.mce-i-hr:before { @media screen and ( max-width: 782px ) { .mce-toolbar .mce-btn button, - .qt-fullscreen { + .qt-dfw { padding: 6px 7px; } @@ -1090,12 +1094,12 @@ i.mce-i-hr:before { margin: 1px; } - .qt-fullscreen { + .qt-dfw { width: 36px; height: 34px; } - .mce-toolbar .mce-btn-group .mce-btn.mce-wp-fullscreen { + .mce-toolbar .mce-btn-group .mce-btn.mce-wp-dfw { margin: 4px 4px 0 0; } @@ -2109,3 +2113,78 @@ html:lang(he-il) .rtl .quicktags-toolbar input { } /* TODO: DFW responsive */ + +/* DFW 2 +-------------------------------------------------------------- */ + +.focus-on .wrap > h2, +.focus-on #wpfooter, +.focus-on .postbox-container, +.focus-on div.updated, +.focus-on div.error, +.focus-on #wp-toolbar { + opacity: 0; + -webkit-transition-duration: 0.6s; + transition-duration: 0.6s; + -webkit-transition-property: opacity; + transition-property: opacity; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; +} + +.focus-on #wp-toolbar { + opacity: 0.3; +} + +.focus-off .wrap > h2, +.focus-off #wpfooter, +.focus-off .postbox-container, +.focus-off div.updated, +.focus-off div.error, +.focus-off #wp-toolbar { + opacity: 1; + -webkit-transition-duration: 0.2s; + transition-duration: 0.2s; + -webkit-transition-property: opacity; + transition-property: opacity; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; +} + +.focus-on #adminmenuback, +.focus-on #adminmenuwrap, +.focus-on .screen-meta-toggle { + -webkit-transition-duration: 0.6s; + transition-duration: 0.6s; + -webkit-transition-property: -webkit-transform; + transition-property: transform; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; +} + +.focus-on #adminmenuback, +.focus-on #adminmenuwrap { + -webkit-transform: translateX( -100% ); + -ms-transform: translateX( -100% ); + transform: translateX( -100% ); +} + +.focus-on .screen-meta-toggle { + -webkit-transform: translateY( -100% ); + -ms-transform: translateY( -100% ); + transform: translateY( -100% ); +} + +.focus-off #adminmenuback, +.focus-off #adminmenuwrap, +.focus-off .screen-meta-toggle { + -webkit-transform: translateX( 0 ); + -ms-transform: translateX( 0 ); + transform: translateX( 0 ); + -webkit-transition-duration: 0.2s; + transition-duration: 0.2s; + -webkit-transition-property: -webkit-transform; + transition-property: transform; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; +} diff --git a/src/wp-includes/js/quicktags.js b/src/wp-includes/js/quicktags.js index ee3e658044..ecb5a4104c 100644 --- a/src/wp-includes/js/quicktags.js +++ b/src/wp-includes/js/quicktags.js @@ -288,6 +288,10 @@ function edButton(id, display, tagStart, tagEnd, access) { html += theButtons.fullscreen.html(name + '_'); } + if ( use && use.indexOf(',dfw,') !== -1 ) { + theButtons.dfw = new qt.DFWButton(); + html += theButtons.dfw.html( name + '_' ); + } if ( 'rtl' === document.getElementsByTagName('html')[0].dir ) { theButtons.textdirection = new qt.TextDirectionButton(); @@ -296,6 +300,8 @@ function edButton(id, display, tagStart, tagEnd, access) { ed.toolbar.innerHTML = html; ed.theButtons = theButtons; + + window.jQuery && window.jQuery( document ).trigger( 'quicktags-init', [ ed ] ); } t.buttonsInitDone = true; }; @@ -405,11 +411,19 @@ function edButton(id, display, tagStart, tagEnd, access) { t.instance = instance || ''; }; qt.Button.prototype.html = function(idPrefix) { - var title = this.title ? ' title="' + this.title + '"' : ''; + var title = this.title ? ' title="' + this.title + '"' : '', + active, on, wp, + dfw = ( wp = window.wp ) && wp.editor && wp.editor.dfw; if ( this.id === 'fullscreen' ) { - return ''; + return ''; + } else if ( this.id === 'dfw' ) { + active = dfw && dfw.isActive() ? '' : ' disabled="disabled"'; + on = dfw && dfw.isOn() ? ' active' : ''; + + return ''; } + return ''; }; qt.Button.prototype.callback = function(){}; @@ -619,6 +633,20 @@ function edButton(id, display, tagStart, tagEnd, access) { wp.editor.fullscreen.on(); }; + qt.DFWButton = function() { + qt.Button.call( this, 'dfw', '', 'f', quicktagsL10n.dfw ); + }; + qt.DFWButton.prototype = new qt.Button(); + qt.DFWButton.prototype.callback = function() { + var wp; + + if ( ! ( wp = window.wp ) || ! wp.editor || ! wp.editor.dfw ) { + return; + } + + window.wp.editor.dfw.toggle(); + }; + qt.TextDirectionButton = function() { qt.Button.call(this, 'textdirection', quicktagsL10n.textdirection, '', quicktagsL10n.toggleTextdirection); }; diff --git a/src/wp-includes/js/tinymce/plugins/wordpress/plugin.js b/src/wp-includes/js/tinymce/plugins/wordpress/plugin.js index 15f0ccf541..004f19f614 100644 --- a/src/wp-includes/js/tinymce/plugins/wordpress/plugin.js +++ b/src/wp-includes/js/tinymce/plugins/wordpress/plugin.js @@ -7,6 +7,10 @@ tinymce.PluginManager.add( 'wordpress', function( editor ) { var DOM = tinymce.DOM, wpAdvButton, modKey, style, last = 0; + if ( typeof window.jQuery !== 'undefined' ) { + window.jQuery( document ).triggerHandler( 'tinymce-editor-setup', [ editor ] ); + } + function toggleToolbars( state ) { var iframe, initial, toolbars, pixels = 0; diff --git a/src/wp-includes/js/tinymce/plugins/wpautoresize/plugin.js b/src/wp-includes/js/tinymce/plugins/wpautoresize/plugin.js index dc1f524437..38ee2f8ed3 100644 --- a/src/wp-includes/js/tinymce/plugins/wpautoresize/plugin.js +++ b/src/wp-includes/js/tinymce/plugins/wpautoresize/plugin.js @@ -117,7 +117,7 @@ tinymce.PluginManager.add( 'wpautoresize', function( editor ) { resize( e ); } - editor.fire( 'wp-autoresize', { height: resizeHeight } ); + editor.fire( 'wp-autoresize', { height: resizeHeight, deltaHeight: e.type === 'nodechange' ? deltaSize : null } ); } } diff --git a/src/wp-includes/js/tinymce/plugins/wpfullscreen/plugin.js b/src/wp-includes/js/tinymce/plugins/wpfullscreen/plugin.js index 9e0940e9e7..f5d80e6576 100644 --- a/src/wp-includes/js/tinymce/plugins/wpfullscreen/plugin.js +++ b/src/wp-includes/js/tinymce/plugins/wpfullscreen/plugin.js @@ -65,7 +65,7 @@ tinymce.PluginManager.add( 'wpfullscreen', function( editor ) { tooltip: 'Distraction Free Writing', shortcut: 'Alt+Shift+W', onclick: toggleFullscreen, - classes: 'wp-fullscreen btn widget' // This overwrites all classes on the container! + classes: 'wp-dfw btn widget' // This overwrites all classes on the container! }); editor.addMenuItem( 'wp_fullscreen', { diff --git a/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css b/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css index a2f49c797c..3ad4b6656f 100644 --- a/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css +++ b/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css @@ -16,6 +16,7 @@ body { color: #333; margin: 9px 10px; max-width: 100%; + -webkit-font-smoothing: antialiased !important; } body.rtl { diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index df09c8345f..94c28f3c68 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -94,7 +94,8 @@ function wp_default_scripts( &$scripts ) { 'fullscreen' => __( 'fullscreen' ), 'toggleFullscreen' => esc_attr__( 'Toggle fullscreen mode' ), 'textdirection' => esc_attr__( 'text direction' ), - 'toggleTextdirection' => esc_attr__( 'Toggle Editor Text Direction' ) + 'toggleTextdirection' => esc_attr__( 'Toggle Editor Text Direction' ), + 'dfw' => esc_attr__( 'Distraction Free Writing' ) ) ); $scripts->add( 'colorpicker', "/wp-includes/js/colorpicker$suffix.js", array('prototype'), '3517m' ); diff --git a/src/wp-includes/version.php b/src/wp-includes/version.php index db9af0ac98..153546e101 100644 --- a/src/wp-includes/version.php +++ b/src/wp-includes/version.php @@ -18,7 +18,7 @@ $wp_db_version = 30133; * * @global string $tinymce_version */ -$tinymce_version = '4106-20141022'; +$tinymce_version = '4106-20141113'; /** * Holds the required PHP version