2018-06-28 02:30:15 +00:00
/**
* @output wp-admin/js/editor-expand.js
*/
2014-11-13 22:31:22 +00:00
( function ( window , $ , undefined ) {
'use strict' ;
2014-07-09 22:06:15 +00:00
var $window = $ ( window ),
$document = $ ( document ),
$adminBar = $ ( '#wpadminbar' ),
2014-11-13 22:31:22 +00:00
$footer = $ ( '#wpfooter' );
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Handles the resizing of the editor.
2017-08-24 17:48:45 +00:00
*
* @since 4.0.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
$ ( function () {
var $wrap = $ ( '#postdivrich' ),
$contentWrap = $ ( '#wp-content-wrap' ),
$tools = $ ( '#wp-content-editor-tools' ),
$visualTop = $ (),
$visualEditor = $ (),
$textTop = $ ( '#ed_toolbar' ),
$textEditor = $ ( '#content' ),
2016-05-30 20:32:30 +00:00
textEditor = $textEditor [ 0 ],
2016-06-01 10:24:30 +00:00
oldTextLength = 0 ,
2014-11-13 22:31:22 +00:00
$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 ,
2014-12-05 01:53:22 +00:00
initialMode = $contentWrap . hasClass ( 'tmce-active' ) ? 'tinymce' : 'html' ,
2014-11-13 22:31:22 +00:00
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
};
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Resizes textarea based on scroll height and width.
2017-08-24 17:48:45 +00:00
*
2017-12-18 14:14:53 +00:00
* Doesn't shrink the editor size below the 300px auto resize minimum height.
2017-08-24 17:48:45 +00:00
*
* @since 4.6.1
*
* @returns {void}
*/
2016-08-28 18:40:31 +00:00
var shrinkTextarea = window . _ . throttle ( function () {
var x = window . scrollX || document . documentElement . scrollLeft ;
var y = window . scrollY || document . documentElement . scrollTop ;
var height = parseInt ( textEditor . style . height , 10 );
textEditor . style . height = autoresizeMinHeight + 'px' ;
if ( textEditor . scrollHeight > autoresizeMinHeight ) {
textEditor . style . height = textEditor . scrollHeight + 'px' ;
}
if ( typeof x !== 'undefined' ) {
window . scrollTo ( x , y );
}
if ( textEditor . scrollHeight < height ) {
adjust ();
}
}, 300 );
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Resizes the text editor depending on the old text length.
2017-08-24 17:48:45 +00:00
*
* If there is an mceEditor and it is hidden, it resizes the editor depending
* on the old text length. If the current length of the text is smaller than
* the old text length, it shrinks the text area. Otherwise it resizes the editor to
* the scroll height.
*
* @since 4.6.1
*
* @returns {void}
*/
2016-08-28 18:40:31 +00:00
function textEditorResize () {
var length = textEditor . value . length ;
if ( mceEditor && ! mceEditor . isHidden () ) {
return ;
}
if ( ! mceEditor && initialMode === 'tinymce' ) {
return ;
}
if ( length < oldTextLength ) {
shrinkTextarea ();
} else if ( parseInt ( textEditor . style . height , 10 ) < textEditor . scrollHeight ) {
textEditor . style . height = Math . ceil ( textEditor . scrollHeight ) + 'px' ;
adjust ();
}
oldTextLength = length ;
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Gets the height and widths of elements.
2017-08-24 17:48:45 +00:00
*
* Gets the heights of the window, the adminbar, the tools, the menu,
* the visualTop, the textTop, the bottom, the statusbar and sideSortables
* and stores these in the heights object. Defaults to 0.
* Gets the width of the window and stores this in the heights object.
*
* @since 4.0.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
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
};
2017-08-24 17:48:45 +00:00
// Adjust for hidden menubar.
2014-11-13 22:31:22 +00:00
if ( heights . menuBarHeight < 3 ) {
heights . menuBarHeight = 0 ;
}
2014-07-09 22:06:15 +00:00
}
2014-11-13 22:31:22 +00:00
// We need to wait for TinyMCE to initialize.
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Binds all necessary functions for editor expand to the editor when the editor
* is initialized.
2017-08-24 17:48:45 +00:00
*
* @since 4.0.0
*
* @param {event} event The TinyMCE editor init event.
* @param {object} editor The editor to bind the vents on.
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
$document . on ( 'tinymce-editor-init.editor-expand' , function ( event , editor ) {
2017-08-24 17:48:45 +00:00
// VK contains the type of key pressed. VK = virtual keyboard.
2014-11-13 22:31:22 +00:00
var VK = window . tinymce . util . VK ,
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Hides any float panel with a hover state. Additionally hides tooltips.
2017-08-24 17:48:45 +00:00
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
hideFloatPanels = _ . debounce ( function () {
! $ ( '.mce-floatpanel:hover' ). length && window . tinymce . ui . FloatPanel . hideAll ();
$ ( '.mce-tooltip' ). hide ();
}, 1000 , true );
2014-10-16 21:31:18 +00:00
2014-11-13 22:31:22 +00:00
// Make sure it's the main editor.
if ( editor . id !== 'content' ) {
2014-09-03 09:38:16 +00:00
return ;
}
2014-11-13 22:31:22 +00:00
// Copy the editor instance.
mceEditor = editor ;
2014-10-16 21:31:18 +00:00
2014-11-13 22:31:22 +00:00
// Set the minimum height to the initial viewport height.
editor . settings . autoresize_min_height = autoresizeMinHeight ;
2014-10-16 21:31:18 +00:00
2014-11-13 22:31:22 +00:00
// 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' );
2014-10-16 21:31:18 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Gets the offset of the editor.
2017-08-24 17:48:45 +00:00
*
* @returns {Number|Boolean} Returns the offset of the editor
* or false if there is no offset height.
*/
2014-11-13 22:31:22 +00:00
function mceGetCursorOffset () {
var node = editor . selection . getNode (),
range , view , offset ;
2014-07-09 22:06:15 +00:00
2017-08-24 17:48:45 +00:00
/*
* If editor.wp.getView and the selection node from the editor selection
* are defined, use this as a view for the offset.
*/
2015-03-11 19:12:28 +00:00
if ( editor . wp && editor . wp . getView && ( view = editor . wp . getView ( node ) ) ) {
2014-11-13 22:31:22 +00:00
offset = view . getBoundingClientRect ();
} else {
range = editor . selection . getRng ();
2014-07-26 00:08:19 +00:00
2017-08-24 17:48:45 +00:00
// Try to get the offset from a range.
2014-11-13 22:31:22 +00:00
try {
offset = range . getClientRects ()[ 0 ];
} catch ( er ) {}
2014-10-16 21:31:18 +00:00
2017-08-24 17:48:45 +00:00
// Get the offset from the bounding client rectangle of the node.
2014-11-13 22:31:22 +00:00
if ( ! offset ) {
offset = node . getBoundingClientRect ();
}
}
2014-07-09 22:06:15 +00:00
2014-11-13 22:31:22 +00:00
return offset . height ? offset : false ;
}
2014-09-12 01:21:15 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Filters the special keys that should not be used for scrolling.
2017-08-24 17:48:45 +00:00
*
* @since 4.0.0
*
* @param {event} event The event to get the key code from.
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function mceKeyup ( event ) {
var key = event . keyCode ;
2017-08-24 17:48:45 +00:00
// Bail on special keys. Key code 47 is a /
2014-11-13 22:31:22 +00:00
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 ;
2017-08-24 17:48:45 +00:00
// OS keys, function keys, num lock, scroll lock. Key code 91-93 are OS keys. Key code 112-123 are F1 to F12. Key code 144 is num lock. Key code 145 is scroll lock.
2014-11-13 22:31:22 +00:00
} else if ( ( key >= 91 && key <= 93 ) || ( key >= 112 && key <= 123 ) || key === 144 || key === 145 ) {
return ;
}
2014-07-09 22:06:15 +00:00
2014-11-13 22:31:22 +00:00
mceScroll ( key );
}
2014-09-12 01:21:15 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Makes sure the cursor is always visible in the editor.
2017-08-24 17:48:45 +00:00
*
* Makes sure the cursor is kept between the toolbars of the editor and scrolls
* 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.
*
* @since 4.1.0
*
* @param {string} key The key code of the pressed key.
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function mceScroll ( key ) {
var offset = mceGetCursorOffset (),
buffer = 50 ,
cursorTop , cursorBottom , editorTop , editorBottom ;
2014-08-24 23:12:15 +00:00
2017-08-24 17:48:45 +00:00
// Don't scroll if there is no offset.
2014-11-13 22:31:22 +00:00
if ( ! offset ) {
return ;
2014-09-03 09:58:16 +00:00
}
2017-08-24 17:48:45 +00:00
// Determine the cursorTop based on the offset and the top of the editor iframe.
2014-11-13 22:31:22 +00:00
cursorTop = offset . top + editor . iframeElement . getBoundingClientRect (). top ;
2017-08-24 17:48:45 +00:00
// Determine the cursorBottom based on the cursorTop and offset height.
2014-11-13 22:31:22 +00:00
cursorBottom = cursorTop + offset . height ;
2017-08-24 17:48:45 +00:00
// Subtract the buffer from the cursorTop.
2014-11-13 22:31:22 +00:00
cursorTop = cursorTop - buffer ;
2017-08-24 17:48:45 +00:00
// Add the buffer to the cursorBottom.
2014-11-13 22:31:22 +00:00
cursorBottom = cursorBottom + buffer ;
editorTop = heights . adminBarHeight + heights . toolsHeight + heights . menuBarHeight + heights . visualTopHeight ;
2017-08-24 17:48:45 +00:00
/*
* Set the editorBottom based on the window Height, and add the bottomHeight and statusBarHeight if the
* advanced editor is enabled.
*/
2014-11-13 22:31:22 +00:00
editorBottom = heights . windowHeight - ( advanced ? heights . bottomHeight + heights . statusBarHeight : 0 );
2014-08-24 23:12:15 +00:00
2017-08-24 17:48:45 +00:00
// Don't scroll if the node is taller than the visible part of the editor.
2014-11-13 22:31:22 +00:00
if ( editorBottom - editorTop < offset . height ) {
return ;
}
2014-07-09 22:06:15 +00:00
2017-08-24 17:48:45 +00:00
/*
* If the cursorTop is smaller than the editorTop and the up, left
* or backspace key is pressed, scroll the editor to the position defined
* by the cursorTop, pageYOffset and editorTop.
*/
2014-11-13 22:31:22 +00:00
if ( cursorTop < editorTop && ( key === VK . UP || key === VK . LEFT || key === VK . BACKSPACE ) ) {
window . scrollTo ( window . pageXOffset , cursorTop + window . pageYOffset - editorTop );
2017-08-24 17:48:45 +00:00
/*
* If any other key is pressed or the cursorTop is bigger than the editorTop,
* scroll the editor to the position defined by the cursorBottom,
* pageYOffset and editorBottom.
*/
2014-11-13 22:31:22 +00:00
} else if ( cursorBottom > editorBottom ) {
window . scrollTo ( window . pageXOffset , cursorBottom + window . pageYOffset - editorBottom );
}
}
2014-09-12 01:21:15 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* If the editor is fullscreen, calls adjust.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @param {event} event The FullscreenStateChanged event.
*
* @returns {void}
*/
2014-11-26 02:50:24 +00:00
function mceFullscreenToggled ( event ) {
2017-08-24 17:48:45 +00:00
// event.state is true if the editor is fullscreen.
2014-11-26 02:50:24 +00:00
if ( ! event . state ) {
adjust ();
}
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Shows the editor when scrolled.
2017-08-24 17:48:45 +00:00
*
* Binds the hideFloatPanels function on the window scroll.mce-float-panels event.
* Executes the wpAutoResize on the active editor.
*
* @since 4.0.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function mceShow () {
$window . on ( 'scroll.mce-float-panels' , hideFloatPanels );
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
setTimeout ( function () {
editor . execCommand ( 'wpAutoResize' );
adjust ();
}, 300 );
}
2014-09-12 01:21:15 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Resizes the editor.
2017-08-24 17:48:45 +00:00
*
* Removes all functions from the window scroll.mce-float-panels event.
* Resizes the text editor and scrolls to a position based on the pageXOffset and adminBarHeight.
*
* @since 4.0.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function mceHide () {
$window . off ( 'scroll.mce-float-panels' );
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
setTimeout ( function () {
var top = $contentWrap . offset (). top ;
2014-07-09 22:06:15 +00:00
2014-11-13 22:31:22 +00:00
if ( window . pageYOffset > top ) {
window . scrollTo ( window . pageXOffset , top - heights . adminBarHeight );
}
2014-07-09 22:06:15 +00:00
2014-11-13 22:31:22 +00:00
textEditorResize ();
adjust ();
}, 100 );
2014-07-09 22:06:15 +00:00
2014-11-13 22:31:22 +00:00
adjust ();
}
2014-08-25 03:43:17 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Toggles advanced states.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function toggleAdvanced () {
advanced = ! advanced ;
}
2014-07-09 22:06:15 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Binds events of the editor and window.
2017-08-24 17:48:45 +00:00
*
* @since 4.0.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
mceBind = function () {
editor . on ( 'keyup' , mceKeyup );
editor . on ( 'show' , mceShow );
editor . on ( 'hide' , mceHide );
editor . on ( 'wp-toolbar-toggle' , toggleAdvanced );
2017-08-24 17:48:45 +00:00
2014-11-13 22:31:22 +00:00
// Adjust when the editor resizes.
editor . on ( 'setcontent wp-autoresize wp-toolbar-toggle' , adjust );
2017-08-24 17:48:45 +00:00
2014-11-26 02:50:24 +00:00
// Don't hide the caret after undo/redo.
2014-11-13 22:31:22 +00:00
editor . on ( 'undo redo' , mceScroll );
2017-08-24 17:48:45 +00:00
2014-11-26 02:50:24 +00:00
// Adjust when exiting TinyMCE's fullscreen mode.
editor . on ( 'FullscreenStateChanged' , mceFullscreenToggled );
2014-11-13 22:31:22 +00:00
$window . off ( 'scroll.mce-float-panels' ). on ( 'scroll.mce-float-panels' , hideFloatPanels );
};
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Unbinds the events of the editor and window.
2017-08-24 17:48:45 +00:00
*
* @since 4.0.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
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 );
2014-11-26 02:50:24 +00:00
editor . off ( 'FullscreenStateChanged' , mceFullscreenToggled );
2014-11-13 22:31:22 +00:00
$window . off ( 'scroll.mce-float-panels' );
};
if ( $wrap . hasClass ( 'wp-editor-expand' ) ) {
2017-08-24 17:48:45 +00:00
// Adjust "immediately".
2014-11-13 22:31:22 +00:00
mceBind ();
initialResize ( adjust );
}
} );
2014-07-09 22:06:15 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Adjusts the toolbars heights and positions.
2017-08-24 17:48:45 +00:00
*
2017-12-18 14:14:53 +00:00
* Adjusts the toolbars heights and positions based on the scroll position on
* the page, the active editor mode and the heights of the editor, admin bar and
* side bar.
2017-08-24 17:48:45 +00:00
*
* @since 4.0.0
*
* @param {event} event The event that calls this function.
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function adjust ( event ) {
2017-08-24 17:48:45 +00:00
// Makes sure we're not in fullscreen mode.
2014-11-13 22:31:22 +00:00
if ( fullscreen && fullscreen . settings . visible ) {
return ;
}
2014-08-18 00:35:18 +00:00
2014-11-13 22:31:22 +00:00
var windowPos = $window . scrollTop (),
2014-11-27 01:00:25 +00:00
type = event && event . type ,
2014-11-13 22:31:22 +00:00
resize = type !== 'scroll' ,
2015-02-06 22:25:23 +00:00
visual = mceEditor && ! mceEditor . isHidden (),
2014-11-13 22:31:22 +00:00
buffer = autoresizeMinHeight ,
postBodyTop = $postBody . offset (). top ,
borderWidth = 1 ,
contentWrapWidth = $contentWrap . width (),
$top , $editor , sidebarTop , footerTop , canPin ,
topPos , topHeight , editorPos , editorHeight ;
2017-08-24 17:48:45 +00:00
/*
* Refresh the heights if type isn't 'scroll'
* or heights.windowHeight isn't set.
*/
2014-11-13 22:31:22 +00:00
if ( resize || ! heights . windowHeight ) {
getHeights ();
}
2014-08-24 05:11:16 +00:00
2017-08-24 17:48:45 +00:00
// Resize on resize event when the editor is in text mode.
2014-11-13 22:31:22 +00:00
if ( ! visual && type === 'resize' ) {
textEditorResize ();
}
2014-08-24 05:11:16 +00:00
2014-11-13 22:31:22 +00:00
if ( visual ) {
$top = $visualTop ;
$editor = $visualEditor ;
topHeight = heights . visualTopHeight ;
} else {
$top = $textTop ;
$editor = $textEditor ;
topHeight = heights . textTopHeight ;
}
2014-07-09 22:43:14 +00:00
2019-04-07 05:39:50 +00:00
// Return if TinyMCE is still initializing.
2015-02-06 22:25:23 +00:00
if ( ! visual && ! $top . length ) {
return ;
}
2014-11-13 22:31:22 +00:00
topPos = $top . parent (). offset (). top ;
editorPos = $editor . offset (). top ;
editorHeight = $editor . outerHeight ();
2014-08-24 05:11:16 +00:00
2017-08-24 17:48:45 +00:00
/*
* If in visual mode, checks if the editorHeight is greater than the autoresizeMinHeight + topHeight.
* If not in visual mode, checks if the editorHeight is greater than the autoresizeMinHeight + 20.
*/
2014-11-13 22:31:22 +00:00
canPin = visual ? autoresizeMinHeight + topHeight : autoresizeMinHeight + 20 ; // 20px from textarea padding
canPin = editorHeight > ( canPin + 5 );
2014-08-18 00:35:18 +00:00
2014-11-13 22:31:22 +00:00
if ( ! canPin ) {
if ( resize ) {
2014-08-18 00:35:18 +00:00
$tools . css ( {
position : 'absolute' ,
top : 0 ,
width : contentWrapWidth
} );
2014-08-24 05:11:16 +00:00
if ( visual && $menuBar . length ) {
$menuBar . css ( {
position : 'absolute' ,
top : 0 ,
width : contentWrapWidth - ( borderWidth * 2 )
} );
}
2014-08-18 00:35:18 +00:00
$top . css ( {
position : 'absolute' ,
2014-08-24 05:11:16 +00:00
top : heights . menuBarHeight ,
2014-08-18 00:35:18 +00:00
width : contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top . outerWidth () - $top . width () ) )
} );
2014-11-13 22:31:22 +00:00
2015-01-10 01:32:26 +00:00
$statusBar . attr ( 'style' , advanced ? '' : 'visibility: hidden;' );
$bottom . attr ( 'style' , '' );
2014-11-13 22:31:22 +00:00
}
} else {
2017-08-24 17:48:45 +00:00
// Check if the top is not already in a fixed position.
2014-11-13 22:31:22 +00:00
if ( ( ! fixedTop || resize ) &&
( windowPos >= ( topPos - heights . toolsHeight - heights . adminBarHeight ) &&
windowPos <= ( topPos - heights . toolsHeight - heights . adminBarHeight + editorHeight - buffer ) ) ) {
fixedTop = true ;
2014-08-18 00:35:18 +00:00
$tools . css ( {
2014-11-13 22:31:22 +00:00
position : 'fixed' ,
top : heights . adminBarHeight ,
2014-08-18 00:35:18 +00:00
width : contentWrapWidth
} );
2014-08-24 05:11:16 +00:00
if ( visual && $menuBar . length ) {
$menuBar . css ( {
2014-11-13 22:31:22 +00:00
position : 'fixed' ,
top : heights . adminBarHeight + heights . toolsHeight ,
width : contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top . outerWidth () - $top . width () ) )
2014-08-24 05:11:16 +00:00
} );
}
$top . css ( {
2014-11-13 22:31:22 +00:00
position : 'fixed' ,
top : heights . adminBarHeight + heights . toolsHeight + heights . menuBarHeight ,
2014-08-24 05:11:16 +00:00
width : contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top . outerWidth () - $top . width () ) )
} );
2017-08-24 17:48:45 +00:00
// Check if the top is already in a fixed position.
2014-11-13 22:31:22 +00:00
} else if ( fixedTop || resize ) {
if ( windowPos <= ( topPos - heights . toolsHeight - heights . adminBarHeight ) ) {
fixedTop = false ;
$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 () ) )
} );
} else if ( windowPos >= ( topPos - heights . toolsHeight - heights . adminBarHeight + editorHeight - buffer ) ) {
fixedTop = false ;
$tools . css ( {
position : 'absolute' ,
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 () ) )
} );
}
2014-08-18 00:35:18 +00:00
}
2014-07-09 22:06:15 +00:00
2017-08-24 17:48:45 +00:00
// Check if the bottom is not already in a fixed position.
2014-11-13 22:31:22 +00:00
if ( ( ! fixedBottom || ( resize && advanced ) ) &&
2017-08-24 17:48:45 +00:00
// Add borderWidth for the border around the .wp-editor-container.
2014-11-13 22:31:22 +00:00
( windowPos + heights . windowHeight ) <= ( editorPos + editorHeight + heights . bottomHeight + heights . statusBarHeight + borderWidth ) ) {
2014-07-09 22:06:15 +00:00
2014-11-27 01:00:25 +00:00
if ( event && event . deltaHeight > 0 && event . deltaHeight < 100 ) {
2014-11-13 22:31:22 +00:00
window . scrollBy ( 0 , event . deltaHeight );
2016-05-30 20:32:30 +00:00
} else if ( visual && advanced ) {
2014-11-13 22:31:22 +00:00
fixedBottom = true ;
2014-08-24 05:11:16 +00:00
2014-11-13 22:31:22 +00:00
$statusBar . css ( {
position : 'fixed' ,
bottom : heights . bottomHeight ,
visibility : '' ,
width : contentWrapWidth - ( borderWidth * 2 )
} );
2014-08-18 00:35:18 +00:00
2014-11-13 22:31:22 +00:00
$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 ;
2014-07-24 01:33:15 +00:00
2015-01-10 01:32:26 +00:00
$statusBar . attr ( 'style' , advanced ? '' : 'visibility: hidden;' );
$bottom . attr ( 'style' , '' );
2014-11-13 22:31:22 +00:00
}
}
2014-08-15 03:17:15 +00:00
2017-08-24 17:48:45 +00:00
// The postbox container is positioned with @media from CSS. Ensure it is pinned on the side.
if ( $postboxContainer . width () < 300 && heights . windowWidth > 600 &&
// Check if the sidebar is not taller than the document height.
$document . height () > ( $sideSortables . height () + postBodyTop + 120 ) &&
// Check if the editor is taller than the viewport.
heights . windowHeight < editorHeight ) {
2014-11-13 22:31:22 +00:00
if ( ( heights . sideSortablesHeight + pinnedToolsTop + sidebarBottom ) > heights . windowHeight || fixedSideTop || fixedSideBottom ) {
2017-08-24 17:48:45 +00:00
// Reset the sideSortables style when scrolling to the top.
2014-11-13 22:31:22 +00:00
if ( windowPos + pinnedToolsTop <= postBodyTop ) {
$sideSortables . attr ( 'style' , '' );
fixedSideTop = fixedSideBottom = false ;
} else {
2017-08-24 17:48:45 +00:00
// When scrolling down.
2014-11-13 22:31:22 +00:00
if ( windowPos > lastScrollPosition ) {
if ( fixedSideTop ) {
2017-08-24 17:48:45 +00:00
// Let it scroll.
2014-11-13 22:31:22 +00:00
fixedSideTop = false ;
sidebarTop = $sideSortables . offset (). top - heights . adminBarHeight ;
footerTop = $footer . offset (). top ;
2017-08-24 17:48:45 +00:00
// Don't get over the footer.
2014-11-13 22:31:22 +00:00
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 ) {
2017-08-24 17:48:45 +00:00
// Pin the bottom.
2014-11-13 22:31:22 +00:00
fixedSideBottom = true ;
$sideSortables . css ({
position : 'fixed' ,
top : 'auto' ,
bottom : sidebarBottom
});
}
2017-08-24 17:48:45 +00:00
// When scrolling up.
2014-11-13 22:31:22 +00:00
} else if ( windowPos < lastScrollPosition ) {
if ( fixedSideBottom ) {
2017-08-24 17:48:45 +00:00
// Let it scroll.
2014-11-13 22:31:22 +00:00
fixedSideBottom = false ;
sidebarTop = $sideSortables . offset (). top - sidebarBottom ;
footerTop = $footer . offset (). top ;
2017-08-24 17:48:45 +00:00
// Don't get over the footer.
2014-11-13 22:31:22 +00:00
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 ) {
2017-08-24 17:48:45 +00:00
// Pin the top.
2014-11-13 22:31:22 +00:00
fixedSideTop = true ;
$sideSortables . css ({
position : 'fixed' ,
top : pinnedToolsTop ,
bottom : ''
});
2014-08-15 03:17:15 +00:00
}
}
}
2014-11-13 22:31:22 +00:00
} else {
2017-08-24 17:48:45 +00:00
// If the sidebar container is smaller than the viewport, then pin/unpin the top when scrolling.
2014-11-13 22:31:22 +00:00
if ( windowPos >= ( postBodyTop - pinnedToolsTop ) ) {
$sideSortables . css ( {
position : 'fixed' ,
top : pinnedToolsTop
} );
} else {
$sideSortables . attr ( 'style' , '' );
}
fixedSideTop = fixedSideBottom = false ;
2014-08-15 03:17:15 +00:00
}
2014-11-13 22:31:22 +00:00
lastScrollPosition = windowPos ;
2014-08-15 03:17:15 +00:00
} else {
2014-11-13 22:31:22 +00:00
$sideSortables . attr ( 'style' , '' );
fixedSideTop = fixedSideBottom = false ;
}
2014-09-01 18:49:15 +00:00
2014-11-13 22:31:22 +00:00
if ( resize ) {
$contentWrap . css ( {
paddingTop : heights . toolsHeight
} );
if ( visual ) {
$visualEditor . css ( {
paddingTop : heights . visualTopHeight + heights . menuBarHeight
2014-08-15 03:17:15 +00:00
} );
} else {
2014-11-13 22:31:22 +00:00
$textEditor . css ( {
marginTop : heights . textTopHeight
} );
2014-08-15 03:17:15 +00:00
}
2014-11-13 22:31:22 +00:00
}
}
2014-08-15 03:17:15 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Resizes the editor and adjusts the toolbars.
2017-08-24 17:48:45 +00:00
*
* @since 4.0.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function fullscreenHide () {
textEditorResize ();
adjust ();
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Runs the passed function with 500ms intervals.
2017-08-24 17:48:45 +00:00
*
* @since 4.0.0
*
* @param {function} callback The function to run in the timeout.
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function initialResize ( callback ) {
for ( var i = 1 ; i < 6 ; i ++ ) {
setTimeout ( callback , 500 * i );
2014-08-15 03:17:15 +00:00
}
2014-11-13 22:31:22 +00:00
}
2014-08-15 03:17:15 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Runs adjust after 100ms.
2017-08-24 17:48:45 +00:00
*
* @since 4.0.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function afterScroll () {
clearTimeout ( scrollTimer );
scrollTimer = setTimeout ( adjust , 100 );
2014-08-15 03:17:15 +00:00
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Binds editor expand events on elements.
2017-08-24 17:48:45 +00:00
*
* @since 4.0.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function on () {
2017-08-24 17:48:45 +00:00
/*
* Scroll to the top when triggering this from JS.
* Ensure the toolbars are pinned properly.
*/
2014-11-13 22:31:22 +00:00
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 ();
2014-07-24 01:33:15 +00:00
} );
2017-08-24 17:48:45 +00:00
/*
* Adjust when collapsing the menu, changing the columns
* or changing the body class.
*/
2014-11-13 22:31:22 +00:00
$document . on ( 'wp-collapse-menu.editor-expand postboxes-columnchange.editor-expand editor-classchange.editor-expand' , adjust )
2016-06-08 22:37:29 +00:00
. on ( 'postbox-toggled.editor-expand postbox-moved.editor-expand' , function () {
2014-11-13 22:31:22 +00:00
if ( ! fixedSideTop && ! fixedSideBottom && window . pageYOffset > pinnedToolsTop ) {
fixedSideBottom = true ;
window . scrollBy ( 0 , - 1 );
adjust ();
window . scrollBy ( 0 , 1 );
}
adjust ();
}). on ( 'wp-window-resized.editor-expand' , function () {
if ( mceEditor && ! mceEditor . isHidden () ) {
mceEditor . execCommand ( 'wpAutoResize' );
} else {
textEditorResize ();
}
});
$textEditor . on ( 'focus.editor-expand input.editor-expand propertychange.editor-expand' , textEditorResize );
mceBind ();
2017-08-24 17:48:45 +00:00
// Adjust when entering or exiting fullscreen mode.
2014-11-13 22:31:22 +00:00
fullscreen && fullscreen . pubsub . subscribe ( 'hidden' , fullscreenHide );
if ( mceEditor ) {
mceEditor . settings . wp_autoresize_on = true ;
mceEditor . execCommand ( 'wpAutoResizeOn' );
if ( ! mceEditor . isHidden () ) {
mceEditor . execCommand ( 'wpAutoResize' );
}
}
if ( ! mceEditor || mceEditor . isHidden () ) {
textEditorResize ();
}
adjust ();
$document . trigger ( 'editor-expand-on' );
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Unbinds editor expand events.
2017-08-24 17:48:45 +00:00
*
* @since 4.0.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function off () {
2014-12-20 19:33:23 +00:00
var height = parseInt ( window . getUserSetting ( 'ed_size' , 300 ), 10 );
if ( height < 50 ) {
height = 50 ;
} else if ( height > 5000 ) {
height = 5000 ;
}
2014-11-13 22:31:22 +00:00
2017-08-24 17:48:45 +00:00
/*
* Scroll to the top when triggering this from JS.
* Ensure the toolbars are reset properly.
*/
2014-11-13 22:31:22 +00:00
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 ();
2017-08-24 17:48:45 +00:00
// Adjust when entering or exiting fullscreen mode.
2014-11-13 22:31:22 +00:00
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 );
}
}
}
2017-08-24 17:48:45 +00:00
// If there is a height found in the user setting.
2014-11-13 22:31:22 +00:00
if ( height ) {
$textEditor . height ( height );
}
$document . trigger ( 'editor-expand-off' );
}
2017-08-24 17:48:45 +00:00
// Start on load.
2014-11-13 22:31:22 +00:00
if ( $wrap . hasClass ( 'wp-editor-expand' ) ) {
on ();
2017-08-24 17:48:45 +00:00
// Resize just after CSS has fully loaded and QuickTags is ready.
2014-11-13 22:31:22 +00:00
if ( $contentWrap . hasClass ( 'html-active' ) ) {
initialResize ( function () {
adjust ();
textEditorResize ();
2014-07-24 01:33:15 +00:00
} );
2014-11-13 22:31:22 +00:00
}
}
2017-08-24 17:48:45 +00:00
// Show the on/off checkbox.
2014-11-13 22:31:22 +00:00
$ ( '#adv-settings .editor-expand' ). show ();
$ ( '#editor-expand-toggle' ). on ( 'change.editor-expand' , function () {
if ( $ ( this ). prop ( 'checked' ) ) {
on ();
window . setUserSetting ( 'editor_expand' , 'on' );
2014-07-24 01:33:15 +00:00
} else {
2014-11-13 22:31:22 +00:00
off ();
window . setUserSetting ( 'editor_expand' , 'off' );
}
});
2017-08-24 17:48:45 +00:00
// Expose on() and off().
2014-11-13 22:31:22 +00:00
window . editorExpand = {
on : on ,
off : off
};
} );
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Handles the distraction free writing of TinyMCE.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
$ ( 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' ,
2014-11-26 02:50:24 +00:00
_isOn = _isActive ? window . getUserSetting ( 'post_dfw' ) === 'on' : false ,
2014-11-13 22:31:22 +00:00
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 ;
} );
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Recalculates the bottom and right position of the editor in the DOM.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-12-11 09:34:26 +00:00
function recalcEditorRect () {
editorRect = $editor . offset ();
editorRect . right = editorRect . left + $editor . outerWidth ();
editorRect . bottom = editorRect . top + $editor . outerHeight ();
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Activates the distraction free writing mode.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function activate () {
if ( ! _isActive ) {
_isActive = true ;
2014-08-18 01:13:16 +00:00
2014-11-13 22:31:22 +00:00
$document . trigger ( 'dfw-activate' );
2014-11-28 01:44:22 +00:00
$content . on ( 'keydown.focus-shortcut' , toggleViaKeyboard );
2014-07-24 01:33:15 +00:00
}
}
2014-07-09 22:06:15 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Deactivates the distraction free writing mode.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function deactivate () {
if ( _isActive ) {
off ();
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
_isActive = false ;
$document . trigger ( 'dfw-deactivate' );
2014-11-28 01:44:22 +00:00
$content . off ( 'keydown.focus-shortcut' );
2014-11-13 22:31:22 +00:00
}
2014-07-24 01:33:15 +00:00
}
2014-11-13 22:31:22 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Returns _isActive.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {boolean} Returns true is _isActive is true.
*/
2014-11-13 22:31:22 +00:00
function isActive () {
return _isActive ;
2014-08-01 02:43:17 +00:00
}
2014-07-09 22:06:15 +00:00
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Binds events on the editor for distraction free writing.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function on () {
if ( ! _isOn && _isActive ) {
_isOn = true ;
2014-07-09 22:06:15 +00:00
2014-11-13 22:31:22 +00:00
$content . on ( 'keydown.focus' , fadeOut );
2014-07-24 01:33:15 +00:00
2014-11-13 22:31:22 +00:00
$title . add ( $content ). on ( 'blur.focus' , maybeFadeIn );
2014-08-18 00:35:18 +00:00
2014-11-13 22:31:22 +00:00
fadeOut ();
2014-11-26 02:50:24 +00:00
window . setUserSetting ( 'post_dfw' , 'on' );
2014-11-13 22:31:22 +00:00
$document . trigger ( 'dfw-on' );
}
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Unbinds events on the editor for distraction free writing.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function off () {
if ( _isOn ) {
_isOn = false ;
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
$title . add ( $content ). off ( '.focus' );
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
fadeIn ();
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
$editor . off ( '.focus' );
2014-08-01 02:43:17 +00:00
2014-11-26 02:50:24 +00:00
window . setUserSetting ( 'post_dfw' , 'off' );
2014-11-13 22:31:22 +00:00
$document . trigger ( 'dfw-off' );
2014-08-01 02:43:17 +00:00
}
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Binds or unbinds the editor expand events.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function toggle () {
2014-11-28 01:44:22 +00:00
if ( _isOn ) {
off ();
} else {
on ();
}
2014-08-01 02:43:17 +00:00
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Returns the value of _isOn.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {boolean} Returns true if _isOn is true.
*/
2014-11-13 22:31:22 +00:00
function isOn () {
return _isOn ;
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Fades out all elements except for the editor.
2017-08-24 17:48:45 +00:00
*
* The fading is done based on key presses and mouse movements.
* Also calls the fadeIn on certain key presses
* or if the mouse leaves the editor.
*
* @since 4.1.0
*
* @param event The event that triggers this function.
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function fadeOut ( event ) {
2016-03-16 02:48:25 +00:00
var isMac ,
key = event && event . keyCode ;
2014-11-13 22:31:22 +00:00
2016-03-16 02:48:25 +00:00
if ( window . navigator . platform ) {
isMac = ( window . navigator . platform . indexOf ( 'Mac' ) > - 1 );
}
2017-08-24 17:48:45 +00:00
// Fade in and returns on Escape and keyboard shortcut Alt+Shift+W and Ctrl+Opt+W.
2016-03-16 02:48:25 +00:00
if ( key === 27 || ( key === 87 && event . altKey && ( ( ! isMac && event . shiftKey ) || ( isMac && event . ctrlKey ) ) ) ) {
2014-11-29 02:45:22 +00:00
fadeIn ( event );
2014-11-13 22:31:22 +00:00
return ;
}
2017-08-24 17:48:45 +00:00
// Return if any of the following keys or combinations of keys is pressed.
2014-12-01 22:53:24 +00:00
if ( event && ( event . metaKey || ( event . ctrlKey && ! event . altKey ) || ( event . altKey && event . shiftKey ) || ( key && (
2014-11-13 22:31:22 +00:00
// 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
2017-08-24 17:48:45 +00:00
// Always recalculate the editor area when entering the overlay with the mouse.
2014-11-13 22:31:22 +00:00
. on ( 'mouseenter.focus' , function () {
2014-12-11 09:34:26 +00:00
recalcEditorRect ();
2014-11-13 22:31:22 +00:00
$window . on ( 'scroll.focus' , function () {
var nScrollY = window . pageYOffset ;
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
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 ) {
2014-12-11 09:34:26 +00:00
var nx = event . clientX ,
ny = event . clientY ,
pageYOffset = window . pageYOffset ,
pageXOffset = window . pageXOffset ;
2014-11-13 22:31:22 +00:00
if ( x && y && ( nx !== x || ny !== y ) ) {
if (
2014-12-11 09:34:26 +00:00
( ny <= y && ny < editorRect . top - pageYOffset ) ||
( ny >= y && ny > editorRect . bottom - pageYOffset ) ||
( nx <= x && nx < editorRect . left - pageXOffset ) ||
( nx >= x && nx > editorRect . right - pageXOffset )
2014-11-13 22:31:22 +00:00
) {
traveledX += Math . abs ( x - nx );
traveledY += Math . abs ( y - ny );
if ( (
2014-12-11 09:34:26 +00:00
ny <= editorRect . top - buffer - pageYOffset ||
ny >= editorRect . bottom + buffer - pageYOffset ||
nx <= editorRect . left - buffer - pageXOffset ||
nx >= editorRect . right + buffer - pageXOffset
2014-11-13 22:31:22 +00:00
) && (
traveledX > 10 ||
traveledY > 10
) ) {
fadeIn ();
x = y = null ;
traveledX = traveledY = 0 ;
return ;
}
} else {
traveledX = traveledY = 0 ;
}
}
x = nx ;
y = ny ;
} )
2017-08-24 17:48:45 +00:00
// When the overlay is touched, fade in and cancel the event.
2014-11-13 22:31:22 +00:00
. 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' );
}
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
fadeOutAdminBar ();
fadeOutSlug ();
2014-08-01 02:43:17 +00:00
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Fades all elements back in.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @param event The event that triggers this function.
*
* @returns {void}
*/
2014-11-29 02:45:22 +00:00
function fadeIn ( event ) {
2014-11-13 22:31:22 +00:00
if ( faded ) {
faded = false ;
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
clearTimeout ( overlayTimer );
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
overlayTimer = setTimeout ( function () {
$overlay . hide ();
}, 200 );
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
$editor . css ( 'z-index' , '' );
$overlay . off ( 'mouseenter.focus mouseleave.focus mousemove.focus touchstart.focus' );
2014-11-29 02:45:22 +00:00
/*
* When fading in, temporarily watch for refocus and fade back out - helps
* with 'accidental' editor exits with the mouse. When fading in and the event
* is a key event (Escape or Alt+Shift+W) don't watch for refocus.
*/
if ( 'undefined' === typeof event ) {
$editor . on ( 'mouseenter.focus' , function () {
if ( $ . contains ( $editor . get ( 0 ), document . activeElement ) || editorHasFocus ) {
fadeOut ();
}
} );
}
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
focusLostTimer = setTimeout ( function () {
focusLostTimer = null ;
$editor . off ( 'mouseenter.focus' );
}, 1000 );
2014-08-15 03:17:15 +00:00
2014-11-13 22:31:22 +00:00
$body . addClass ( 'focus-off' ). removeClass ( 'focus-on' );
}
fadeInAdminBar ();
fadeInSlug ();
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Fades in if the focused element based on it position.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function maybeFadeIn () {
setTimeout ( function () {
var position = document . activeElement . compareDocumentPosition ( $editor . get ( 0 ) );
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
function hasFocus ( $el ) {
return $ . contains ( $el . get ( 0 ), document . activeElement );
}
2014-08-01 02:43:17 +00:00
2014-11-28 01:44:22 +00:00
// The focused node is before or behind the editor area, and not outside the wrap.
2014-11-13 22:31:22 +00:00
if ( ( position === 2 || position === 4 ) && ( hasFocus ( $menuWrap ) || hasFocus ( $wrap ) || hasFocus ( $footer ) ) ) {
fadeIn ();
2014-08-01 02:43:17 +00:00
}
2014-11-13 22:31:22 +00:00
}, 0 );
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Fades out the admin bar based on focus on the admin bar.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function fadeOutAdminBar () {
if ( ! fadedAdminBar && faded ) {
fadedAdminBar = true ;
$adminBar
. on ( 'mouseenter.focus' , function () {
$adminBar . addClass ( 'focus-off' );
} )
. on ( 'mouseleave.focus' , function () {
$adminBar . removeClass ( 'focus-off' );
} );
2014-08-01 02:43:17 +00:00
}
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Fades in the admin bar.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function fadeInAdminBar () {
if ( fadedAdminBar ) {
fadedAdminBar = false ;
$adminBar . off ( '.focus' );
}
2014-08-01 02:43:17 +00:00
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Fades out the edit slug box.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
function fadeOutSlug () {
if ( ! fadedSlug && faded && ! $slug . find ( ':focus' ). length ) {
fadedSlug = true ;
2014-08-01 02:43:17 +00:00
2014-11-13 22:31:22 +00:00
$slug . stop (). fadeTo ( 'fast' , 0.3 ). on ( 'mouseenter.focus' , fadeInSlug ). off ( 'mouseleave.focus' );
$slugFocusEl . on ( 'focus.focus' , fadeInSlug ). off ( 'blur.focus' );
}
2014-08-01 02:43:17 +00:00
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Fades in the edit slug box.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
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' );
}
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Triggers the toggle on Alt + Shift + W.
2017-08-24 17:48:45 +00:00
*
* Keycode 87 = w.
*
* @since 4.1.0
*
* @param {event} event The event to trigger the toggle.
*
* @returns {void}
*/
2014-11-28 01:44:22 +00:00
function toggleViaKeyboard ( event ) {
if ( event . altKey && event . shiftKey && 87 === event . keyCode ) {
toggle ();
}
}
if ( $ ( '#postdivrich' ). hasClass ( 'wp-editor-expand' ) ) {
$content . on ( 'keydown.focus-shortcut' , toggleViaKeyboard );
}
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Adds the distraction free writing button when setting up TinyMCE.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @param {event} event The TinyMCE editor setup event.
* @param {object} editor The editor to add the button to.
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
$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 );
} );
},
2014-12-16 10:07:23 +00:00
tooltip : 'Distraction-free writing mode' ,
2014-11-28 01:44:22 +00:00
shortcut : 'Alt+Shift+W'
2014-11-13 22:31:22 +00:00
} );
2014-11-28 01:44:22 +00:00
editor . addCommand ( 'wpToggleDFW' , toggle );
2016-03-12 17:44:26 +00:00
editor . addShortcut ( 'access+w' , '' , 'wpToggleDFW' );
2014-11-13 22:31:22 +00:00
} );
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Binds and unbinds events on the editor.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @param {event} event The TinyMCE editor init event.
* @param {object} editor The editor to bind events on.
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
$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 );
2014-12-11 09:34:26 +00:00
editor . on ( 'wp-autoresize' , recalcEditorRect );
2014-11-13 22:31:22 +00:00
};
mceUnbind = function () {
editor . off ( 'keydown' , fadeOut );
editor . off ( 'blur' , maybeFadeIn );
editor . off ( 'focus' , focus );
editor . off ( 'blur' , blur );
2014-12-11 09:34:26 +00:00
editor . off ( 'wp-autoresize' , recalcEditorRect );
2014-11-13 22:31:22 +00:00
};
if ( _isOn ) {
mceBind ();
}
2017-08-24 17:48:45 +00:00
// Bind and unbind based on the distraction free writing focus.
2014-11-13 22:31:22 +00:00
$document . on ( 'dfw-on.focus' , mceBind ). on ( 'dfw-off.focus' , mceUnbind );
2017-08-24 17:48:45 +00:00
// Focuse the editor when it is the target of the click event.
2015-11-12 12:04:27 +00:00
editor . on ( 'click' , function ( event ) {
2014-11-13 22:31:22 +00:00
if ( event . target === editor . getDoc (). documentElement ) {
editor . focus ();
}
} );
}
} );
2017-08-24 17:48:45 +00:00
/**
2017-12-18 14:14:53 +00:00
* Binds events on quicktags init.
2017-08-24 17:48:45 +00:00
*
* @since 4.1.0
*
* @param {event} event The quicktags init event.
* @param {object} editor The editor to bind events on.
*
* @returns {void}
*/
2014-11-13 22:31:22 +00:00
$document . on ( 'quicktags-init' , function ( event , editor ) {
var $button ;
2017-08-24 17:48:45 +00:00
// Bind the distraction free writing events if the distraction free writing button is available.
2014-11-13 22:31:22 +00:00
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 );
2014-08-01 02:43:17 +00:00
}
2014-11-13 22:31:22 +00:00
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 );