Make WordPress Core

Changeset 30338


Ignore:
Timestamp:
11/13/2014 10:30:55 PM (12 years ago)
Author:
markjaquith
Message:

Introduce Distraction-Free Writing v2, a re-think of DFW that uses the main editor instance

  • the "DFW" button is now an auto/off toggle
  • defaulting to auto during beta, decide later for release
  • "auto" means that DFW gets enabled as you start typing in editor
  • tabbing and mousing out will bring the full interface back
  • there is a slight grace period during which your mouse can quickly return

Feature plugin work happened here: https://github.com/avryl/focus

props avryl, azaozz, Michael Arestad
fixes #29806

Location:
trunk/src
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/edit-form-advanced.php

    r30028 r30338  
    513513
    514514<?php wp_editor( $post->post_content, 'content', array(
    515         'dfw' => true,
    516515        'drag_drop_upload' => true,
    517516        'tabfocus_elements' => 'content-html,save-post',
  • trunk/src/wp-admin/js/editor-expand.js

    r29929 r30338  
    1 /* global tinymce */
    2 
    3 window.wp = window.wp || {};
    4 
    5 jQuery( document ).ready( function( $ ) {
     1( function( window, $, undefined ) {
     2        'use strict';
     3
    64        var $window = $( window ),
    75                $document = $( document ),
    86                $adminBar = $( '#wpadminbar' ),
    9                 $footer = $( '#wpfooter' ),
    10                 $wrap = $( '#postdivrich' ),
    11                 $contentWrap = $( '#wp-content-wrap' ),
    12                 $tools = $( '#wp-content-editor-tools' ),
    13                 $visualTop = $(),
    14                 $visualEditor = $(),
    15                 $textTop = $( '#ed_toolbar' ),
    16                 $textEditor = $( '#content' ),
    17                 $textEditorClone = $( '<div id="content-textarea-clone"></div>' ),
    18                 $bottom = $( '#post-status-info' ),
    19                 $menuBar = $(),
    20                 $statusBar = $(),
    21                 $sideSortables = $( '#side-sortables' ),
    22                 $postboxContainer = $( '#postbox-container-1' ),
    23                 $postBody = $('#post-body'),
    24                 fullscreen = window.wp.editor && window.wp.editor.fullscreen,
    25                 mceEditor,
    26                 mceBind = function(){},
    27                 mceUnbind = function(){},
    28                 fixedTop = false,
    29                 fixedBottom = false,
    30                 fixedSideTop = false,
    31                 fixedSideBottom = false,
    32                 scrollTimer,
    33                 lastScrollPosition = 0,
    34                 pageYOffsetAtTop = 130,
    35                 pinnedToolsTop = 56,
    36                 sidebarBottom = 20,
    37                 autoresizeMinHeight = 300,
    38                 initialMode = window.getUserSetting( 'editor' ),
    39                 // These are corrected when adjust() runs, except on scrolling if already set.
    40                 heights = {
    41                         windowHeight: 0,
    42                         windowWidth: 0,
    43                         adminBarHeight: 0,
    44                         toolsHeight: 0,
    45                         menuBarHeight: 0,
    46                         visualTopHeight: 0,
    47                         textTopHeight: 0,
    48                         bottomHeight: 0,
    49                         statusBarHeight: 0,
    50                         sideSortablesHeight: 0
    51                 };
    52 
    53         $textEditorClone.insertAfter( $textEditor );
    54 
    55         $textEditorClone.css( {
    56                 'font-family': $textEditor.css( 'font-family' ),
    57                 'font-size': $textEditor.css( 'font-size' ),
    58                 'line-height': $textEditor.css( 'line-height' ),
    59                 'white-space': 'pre-wrap',
    60                 'word-wrap': 'break-word'
    61         } );
    62 
    63         function getHeights() {
    64                 var windowWidth = $window.width();
    65 
    66                 heights = {
    67                         windowHeight: $window.height(),
    68                         windowWidth: windowWidth,
    69                         adminBarHeight: ( windowWidth > 600 ? $adminBar.outerHeight() : 0 ),
    70                         toolsHeight: $tools.outerHeight() || 0,
    71                         menuBarHeight: $menuBar.outerHeight() || 0,
    72                         visualTopHeight: $visualTop.outerHeight() || 0,
    73                         textTopHeight: $textTop.outerHeight() || 0,
    74                         bottomHeight: $bottom.outerHeight() || 0,
    75                         statusBarHeight: $statusBar.outerHeight() || 0,
    76                         sideSortablesHeight: $sideSortables.height() || 0
    77                 };
    78 
    79                 // Adjust for hidden
    80                 if ( heights.menuBarHeight < 3 ) {
    81                         heights.menuBarHeight = 0;
    82                 }
    83         }
    84 
    85         function textEditorKeyup( event ) {
    86                 var VK = jQuery.ui.keyCode,
    87                         key = event.keyCode,
    88                         range = document.createRange(),
    89                         selStart = $textEditor[0].selectionStart,
    90                         selEnd = $textEditor[0].selectionEnd,
    91                         textNode = $textEditorClone[0].firstChild,
    92                         buffer = 10,
    93                         offset, cursorTop, cursorBottom, editorTop, editorBottom;
    94 
    95                 if ( selStart && selEnd && selStart !== selEnd ) {
    96                         return;
    97                 }
    98 
    99                 // These are not TinyMCE ranges.
    100                 try {
    101                         range.setStart( textNode, selStart );
    102                         range.setEnd( textNode, selEnd + 1 );
    103                 } catch ( ex ) {}
    104 
    105                 offset = range.getBoundingClientRect();
    106 
    107                 if ( ! offset.height ) {
    108                         return;
    109                 }
    110 
    111                 cursorTop = offset.top - buffer;
    112                 cursorBottom = cursorTop + offset.height + buffer;
    113                 editorTop = heights.adminBarHeight + heights.toolsHeight + heights.textTopHeight;
    114                 editorBottom = heights.windowHeight - heights.bottomHeight;
    115 
    116                 if ( cursorTop < editorTop && ( key === VK.UP || key === VK.LEFT || key === VK.BACKSPACE ) ) {
    117                         window.scrollTo( window.pageXOffset, cursorTop + window.pageYOffset - editorTop );
    118                 } else if ( cursorBottom > editorBottom ) {
    119                         window.scrollTo( window.pageXOffset, cursorBottom + window.pageYOffset - editorBottom );
    120                 }
    121         }
    122 
    123         function textEditorResize() {
    124                 if ( ( mceEditor && ! mceEditor.isHidden() ) || ( ! mceEditor && initialMode === 'tinymce' ) ) {
    125                         return;
    126                 }
    127 
    128                 var textEditorHeight = $textEditor.height(),
    129                         hiddenHeight;
    130 
    131                 $textEditorClone.width( $textEditor.width() - 22 );
    132                 $textEditorClone.text( $textEditor.val() + '&nbsp;' );
    133 
    134                 hiddenHeight = $textEditorClone.height();
    135 
    136                 if ( hiddenHeight < autoresizeMinHeight ) {
    137                         hiddenHeight = autoresizeMinHeight;
    138                 }
    139 
    140                 if ( hiddenHeight === textEditorHeight ) {
    141                         return;
    142                 }
    143 
    144                 $textEditor.height( hiddenHeight );
    145 
    146                 adjust();
    147         }
    148 
    149         // We need to wait for TinyMCE to initialize.
    150         $document.on( 'tinymce-editor-init.editor-expand', function( event, editor ) {
    151                 var hideFloatPanels = _.debounce( function() {
    152                         ! $( '.mce-floatpanel:hover' ).length && tinymce.ui.FloatPanel.hideAll();
    153                         $( '.mce-tooltip' ).hide();
    154                 }, 1000, true );
    155 
    156                 // Make sure it's the main editor.
    157                 if ( editor.id !== 'content' ) {
    158                         return;
    159                 }
    160 
    161                 // Copy the editor instance.
    162                 mceEditor = editor;
    163 
    164                 // Set the minimum height to the initial viewport height.
    165                 editor.settings.autoresize_min_height = autoresizeMinHeight;
    166 
    167                 // Get the necessary UI elements.
    168                 $visualTop = $contentWrap.find( '.mce-toolbar-grp' );
    169                 $visualEditor = $contentWrap.find( '.mce-edit-area' );
    170                 $statusBar = $contentWrap.find( '.mce-statusbar' );
    171                 $menuBar = $contentWrap.find( '.mce-menubar' );
    172 
    173                 function mceGetCursorOffset() {
    174                         var node = editor.selection.getNode(),
    175                                 range, view, offset;
    176 
    177                         if ( editor.plugins.wpview && ( view = editor.plugins.wpview.getView( node ) ) ) {
    178                                 offset = view.getBoundingClientRect();
    179                         } else {
    180                                 range = editor.selection.getRng();
    181 
    182                                 try {
    183                                         offset = range.getClientRects()[0];
    184                                 } catch( er ) {}
    185 
    186                                 if ( ! offset ) {
    187                                         offset = node.getBoundingClientRect();
    188                                 }
    189                         }
    190 
    191                         return offset.height ? offset : false;
    192                 }
    193 
    194                 // Make sure the cursor is always visible.
    195                 // This is not only necessary to keep the cursor between the toolbars,
    196                 // but also to scroll the window when the cursor moves out of the viewport to a wpview.
    197                 // Setting a buffer > 0 will prevent the browser default.
    198                 // Some browsers will scroll to the middle,
    199                 // others to the top/bottom of the *window* when moving the cursor out of the viewport.
    200                 function mceKeyup( event ) {
    201                         var VK = tinymce.util.VK,
    202                                 key = event.keyCode;
    203 
    204                         // Bail on special keys.
    205                         if ( key <= 47 && ! ( key === VK.SPACEBAR || key === VK.ENTER || key === VK.DELETE || key === VK.BACKSPACE ||
    206                                 key === VK.UP || key === VK.RIGHT || key === VK.DOWN || key === VK.LEFT ) ) {
    207 
     7                $footer = $( '#wpfooter' );
     8
     9        /* Autoresize editor. */
     10        $( function() {
     11                var $wrap = $( '#postdivrich' ),
     12                        $contentWrap = $( '#wp-content-wrap' ),
     13                        $tools = $( '#wp-content-editor-tools' ),
     14                        $visualTop = $(),
     15                        $visualEditor = $(),
     16                        $textTop = $( '#ed_toolbar' ),
     17                        $textEditor = $( '#content' ),
     18                        $textEditorClone = $( '<div id="content-textarea-clone"></div>' ),
     19                        $bottom = $( '#post-status-info' ),
     20                        $menuBar = $(),
     21                        $statusBar = $(),
     22                        $sideSortables = $( '#side-sortables' ),
     23                        $postboxContainer = $( '#postbox-container-1' ),
     24                        $postBody = $('#post-body'),
     25                        fullscreen = window.wp.editor && window.wp.editor.fullscreen,
     26                        mceEditor,
     27                        mceBind = function(){},
     28                        mceUnbind = function(){},
     29                        fixedTop = false,
     30                        fixedBottom = false,
     31                        fixedSideTop = false,
     32                        fixedSideBottom = false,
     33                        scrollTimer,
     34                        lastScrollPosition = 0,
     35                        pageYOffsetAtTop = 130,
     36                        pinnedToolsTop = 56,
     37                        sidebarBottom = 20,
     38                        autoresizeMinHeight = 300,
     39                        initialMode = window.getUserSetting( 'editor' ),
     40                        advanced = !! parseInt( window.getUserSetting( 'hidetb' ), 10 ),
     41                        // These are corrected when adjust() runs, except on scrolling if already set.
     42                        heights = {
     43                                windowHeight: 0,
     44                                windowWidth: 0,
     45                                adminBarHeight: 0,
     46                                toolsHeight: 0,
     47                                menuBarHeight: 0,
     48                                visualTopHeight: 0,
     49                                textTopHeight: 0,
     50                                bottomHeight: 0,
     51                                statusBarHeight: 0,
     52                                sideSortablesHeight: 0
     53                        };
     54
     55                $textEditorClone.insertAfter( $textEditor );
     56
     57                $textEditorClone.css( {
     58                        'font-family': $textEditor.css( 'font-family' ),
     59                        'font-size': $textEditor.css( 'font-size' ),
     60                        'line-height': $textEditor.css( 'line-height' ),
     61                        'white-space': 'pre-wrap',
     62                        'word-wrap': 'break-word'
     63                } );
     64
     65                function getHeights() {
     66                        var windowWidth = $window.width();
     67
     68                        heights = {
     69                                windowHeight: $window.height(),
     70                                windowWidth: windowWidth,
     71                                adminBarHeight: ( windowWidth > 600 ? $adminBar.outerHeight() : 0 ),
     72                                toolsHeight: $tools.outerHeight() || 0,
     73                                menuBarHeight: $menuBar.outerHeight() || 0,
     74                                visualTopHeight: $visualTop.outerHeight() || 0,
     75                                textTopHeight: $textTop.outerHeight() || 0,
     76                                bottomHeight: $bottom.outerHeight() || 0,
     77                                statusBarHeight: $statusBar.outerHeight() || 0,
     78                                sideSortablesHeight: $sideSortables.height() || 0
     79                        };
     80
     81                        // Adjust for hidden
     82                        if ( heights.menuBarHeight < 3 ) {
     83                                heights.menuBarHeight = 0;
     84                        }
     85                }
     86
     87                function textEditorKeyup( event ) {
     88                        var VK = jQuery.ui.keyCode,
     89                                key = event.keyCode,
     90                                range = document.createRange(),
     91                                selStart = $textEditor[0].selectionStart,
     92                                selEnd = $textEditor[0].selectionEnd,
     93                                textNode = $textEditorClone[0].firstChild,
     94                                buffer = 10,
     95                                offset, cursorTop, cursorBottom, editorTop, editorBottom;
     96
     97                        if ( selStart && selEnd && selStart !== selEnd ) {
    20898                                return;
    209                         // OS keys, function keys, num lock, scroll lock
    210                         } else if ( ( key >= 91 && key <= 93 ) || ( key >= 112 && key <= 123 ) || key === 144 || key === 145 ) {
     99                        }
     100
     101                        // These are not TinyMCE ranges.
     102                        try {
     103                                range.setStart( textNode, selStart );
     104                                range.setEnd( textNode, selEnd + 1 );
     105                        } catch ( ex ) {}
     106
     107                        offset = range.getBoundingClientRect();
     108
     109                        if ( ! offset.height ) {
    211110                                return;
    212111                        }
    213112
    214                         mceScroll( key );
    215                 }
    216 
    217                 function mceScroll( key ) {
    218                         var VK = tinymce.util.VK,
    219                                 offset = mceGetCursorOffset(),
    220                                 buffer = 10,
    221                                 cursorTop, cursorBottom, editorTop, editorBottom;
    222 
    223                         if ( ! offset ) {
    224                                 return;
    225                         }
    226 
    227                         cursorTop = offset.top + editor.iframeElement.getBoundingClientRect().top;
     113                        cursorTop = offset.top - buffer;
    228114                        cursorBottom = cursorTop + offset.height + buffer;
    229                         cursorTop -= buffer;
    230                         editorTop = heights.adminBarHeight + heights.toolsHeight + heights.menuBarHeight + heights.visualTopHeight;
    231                         editorBottom = heights.windowHeight - heights.bottomHeight - heights.statusBarHeight;
    232 
    233                         // Don't scroll if the node is taller than the visible part of the editor
    234                         if ( editorBottom - editorTop < offset.height ) {
    235                                 return;
    236                         }
    237 
    238                         // WebKit browsers scroll-into-view to the middle of the window but not for arrow keys/backspace.
    239                         // The others scroll to the top of the window, we need to account for the adminbar and editor toolbar(s).
    240                         if ( cursorTop < editorTop && ( ! tinymce.Env.webkit ||
    241                                 ( key === VK.UP || key === VK.RIGHT || key === VK.DOWN || key === VK.LEFT || key === VK.BACKSPACE ) ) ) {
    242 
     115                        editorTop = heights.adminBarHeight + heights.toolsHeight + heights.textTopHeight;
     116                        editorBottom = heights.windowHeight - heights.bottomHeight;
     117
     118                        if ( cursorTop < editorTop && ( key === VK.UP || key === VK.LEFT || key === VK.BACKSPACE ) ) {
    243119                                window.scrollTo( window.pageXOffset, cursorTop + window.pageYOffset - editorTop );
    244120                        } else if ( cursorBottom > editorBottom ) {
     
    247123                }
    248124
    249                 // Adjust when switching editor modes.
    250                 function mceShow() {
    251                         $window.on( 'scroll.mce-float-panels', hideFloatPanels );
    252 
    253                         setTimeout( function() {
    254                                 editor.execCommand( 'wpAutoResize' );
     125                function textEditorResize() {
     126                        if ( ( mceEditor && ! mceEditor.isHidden() ) || ( ! mceEditor && initialMode === 'tinymce' ) ) {
     127                                return;
     128                        }
     129
     130                        var textEditorHeight = $textEditor.height(),
     131                                hiddenHeight;
     132
     133                        $textEditorClone.width( $textEditor.width() - 22 );
     134                        $textEditorClone.text( $textEditor.val() + '&nbsp;' );
     135
     136                        hiddenHeight = $textEditorClone.height();
     137
     138                        if ( hiddenHeight < autoresizeMinHeight ) {
     139                                hiddenHeight = autoresizeMinHeight;
     140                        }
     141
     142                        if ( hiddenHeight === textEditorHeight ) {
     143                                return;
     144                        }
     145
     146                        $textEditor.height( hiddenHeight );
     147
     148                        adjust();
     149                }
     150
     151                // We need to wait for TinyMCE to initialize.
     152                $document.on( 'tinymce-editor-init.editor-expand', function( event, editor ) {
     153                        var VK = window.tinymce.util.VK,
     154                                hideFloatPanels = _.debounce( function() {
     155                                        ! $( '.mce-floatpanel:hover' ).length && window.tinymce.ui.FloatPanel.hideAll();
     156                                        $( '.mce-tooltip' ).hide();
     157                                }, 1000, true );
     158
     159                        // Make sure it's the main editor.
     160                        if ( editor.id !== 'content' ) {
     161                                return;
     162                        }
     163
     164                        // Copy the editor instance.
     165                        mceEditor = editor;
     166
     167                        // Set the minimum height to the initial viewport height.
     168                        editor.settings.autoresize_min_height = autoresizeMinHeight;
     169
     170                        // Get the necessary UI elements.
     171                        $visualTop = $contentWrap.find( '.mce-toolbar-grp' );
     172                        $visualEditor = $contentWrap.find( '.mce-edit-area' );
     173                        $statusBar = $contentWrap.find( '.mce-statusbar' );
     174                        $menuBar = $contentWrap.find( '.mce-menubar' );
     175
     176                        function mceGetCursorOffset() {
     177                                var node = editor.selection.getNode(),
     178                                        range, view, offset;
     179
     180                                if ( editor.plugins.wpview && ( view = editor.plugins.wpview.getView( node ) ) ) {
     181                                        offset = view.getBoundingClientRect();
     182                                } else {
     183                                        range = editor.selection.getRng();
     184
     185                                        try {
     186                                                offset = range.getClientRects()[0];
     187                                        } catch( er ) {}
     188
     189                                        if ( ! offset ) {
     190                                                offset = node.getBoundingClientRect();
     191                                        }
     192                                }
     193
     194                                return offset.height ? offset : false;
     195                        }
     196
     197                        // Make sure the cursor is always visible.
     198                        // This is not only necessary to keep the cursor between the toolbars,
     199                        // but also to scroll the window when the cursor moves out of the viewport to a wpview.
     200                        // Setting a buffer > 0 will prevent the browser default.
     201                        // Some browsers will scroll to the middle,
     202                        // others to the top/bottom of the *window* when moving the cursor out of the viewport.
     203                        function mceKeyup( event ) {
     204                                var key = event.keyCode;
     205
     206                                // Bail on special keys.
     207                                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 ) ) {
     208                                        return;
     209                                // OS keys, function keys, num lock, scroll lock
     210                                } else if ( ( key >= 91 && key <= 93 ) || ( key >= 112 && key <= 123 ) || key === 144 || key === 145 ) {
     211                                        return;
     212                                }
     213
     214                                mceScroll( key );
     215                        }
     216
     217                        function mceScroll( key ) {
     218                                var offset = mceGetCursorOffset(),
     219                                        buffer = 50,
     220                                        cursorTop, cursorBottom, editorTop, editorBottom;
     221
     222                                if ( ! offset ) {
     223                                        return;
     224                                }
     225
     226                                cursorTop = offset.top + editor.iframeElement.getBoundingClientRect().top;
     227                                cursorBottom = cursorTop + offset.height;
     228                                cursorTop = cursorTop - buffer;
     229                                cursorBottom = cursorBottom + buffer;
     230                                editorTop = heights.adminBarHeight + heights.toolsHeight + heights.menuBarHeight + heights.visualTopHeight;
     231                                editorBottom = heights.windowHeight - ( advanced ? heights.bottomHeight + heights.statusBarHeight : 0 );
     232
     233                                // Don't scroll if the node is taller than the visible part of the editor
     234                                if ( editorBottom - editorTop < offset.height ) {
     235                                        return;
     236                                }
     237
     238                                if ( cursorTop < editorTop && ( key === VK.UP || key === VK.LEFT || key === VK.BACKSPACE ) ) {
     239                                        window.scrollTo( window.pageXOffset, cursorTop + window.pageYOffset - editorTop );
     240                                } else if ( cursorBottom > editorBottom ) {
     241                                        window.scrollTo( window.pageXOffset, cursorBottom + window.pageYOffset - editorBottom );
     242                                }
     243                        }
     244
     245                        // Adjust when switching editor modes.
     246                        function mceShow() {
     247                                $window.on( 'scroll.mce-float-panels', hideFloatPanels );
     248
     249                                setTimeout( function() {
     250                                        editor.execCommand( 'wpAutoResize' );
     251                                        adjust();
     252                                }, 300 );
     253                        }
     254
     255                        function mceHide() {
     256                                $window.off( 'scroll.mce-float-panels' );
     257
     258                                setTimeout( function() {
     259                                        var top = $contentWrap.offset().top;
     260
     261                                        if ( window.pageYOffset > top ) {
     262                                                window.scrollTo( window.pageXOffset, top - heights.adminBarHeight );
     263                                        }
     264
     265                                        textEditorResize();
     266                                        adjust();
     267                                }, 100 );
     268
    255269                                adjust();
    256                         }, 300 );
    257                 }
    258 
    259                 function mceHide() {
    260                         $window.off( 'scroll.mce-float-panels' );
    261 
    262                         setTimeout( function() {
    263                                 var top = $contentWrap.offset().top;
    264 
    265                                 if ( window.pageYOffset > top ) {
    266                                         window.scrollTo( window.pageXOffset, top - heights.adminBarHeight );
    267                                 }
    268 
     270                        }
     271
     272                        function toggleAdvanced() {
     273                                advanced = ! advanced;
     274                        }
     275
     276                        mceBind = function() {
     277                                editor.on( 'keyup', mceKeyup );
     278                                editor.on( 'show', mceShow );
     279                                editor.on( 'hide', mceHide );
     280                                editor.on( 'wp-toolbar-toggle', toggleAdvanced );
     281                                // Adjust when the editor resizes.
     282                                editor.on( 'setcontent wp-autoresize wp-toolbar-toggle', adjust );
     283                                // Don't hide the caret after undo/redo
     284                                editor.on( 'undo redo', mceScroll );
     285
     286                                $window.off( 'scroll.mce-float-panels' ).on( 'scroll.mce-float-panels', hideFloatPanels );
     287                        };
     288
     289                        mceUnbind = function() {
     290                                editor.off( 'keyup', mceKeyup );
     291                                editor.off( 'show', mceShow );
     292                                editor.off( 'hide', mceHide );
     293                                editor.off( 'wp-toolbar-toggle', toggleAdvanced );
     294                                editor.off( 'setcontent wp-autoresize wp-toolbar-toggle', adjust );
     295                                editor.off( 'undo redo', mceScroll );
     296
     297                                $window.off( 'scroll.mce-float-panels' );
     298                        };
     299
     300                        if ( $wrap.hasClass( 'wp-editor-expand' ) ) {
     301                                // Adjust "immediately"
     302                                mceBind();
     303                                initialResize( adjust );
     304                        }
     305                } );
     306
     307                // Adjust the toolbars based on the active editor mode.
     308                function adjust( event ) {
     309                        var type = event && event.type;
     310
     311                        // Make sure we're not in fullscreen mode.
     312                        if ( fullscreen && fullscreen.settings.visible ) {
     313                                return;
     314                        }
     315
     316                        var windowPos = $window.scrollTop(),
     317                                resize = type !== 'scroll',
     318                                visual = ( mceEditor && ! mceEditor.isHidden() ),
     319                                buffer = autoresizeMinHeight,
     320                                postBodyTop = $postBody.offset().top,
     321                                borderWidth = 1,
     322                                contentWrapWidth = $contentWrap.width(),
     323                                $top, $editor, sidebarTop, footerTop, canPin,
     324                                topPos, topHeight, editorPos, editorHeight;
     325
     326                        // Refresh the heights
     327                        if ( resize || ! heights.windowHeight ) {
     328                                getHeights();
     329                        }
     330
     331                        if ( ! visual && type === 'resize' ) {
    269332                                textEditorResize();
    270                                 adjust();
    271                         }, 100 );
    272 
    273                         adjust();
    274                 }
    275 
    276                 mceBind = function() {
    277                         editor.on( 'keyup', mceKeyup );
    278                         editor.on( 'show', mceShow );
    279                         editor.on( 'hide', mceHide );
    280                         // Adjust when the editor resizes.
    281                         editor.on( 'setcontent wp-autoresize wp-toolbar-toggle', adjust );
    282                         // Scroll to the caret or selection after undo/redo
    283                         editor.on( 'undo redo', mceScroll );
    284 
    285                         $window.off( 'scroll.mce-float-panels' ).on( 'scroll.mce-float-panels', hideFloatPanels );
    286                 };
    287 
    288                 mceUnbind = function() {
    289                         editor.off( 'keyup', mceKeyup );
    290                         editor.off( 'show', mceShow );
    291                         editor.off( 'hide', mceHide );
    292                         editor.off( 'setcontent wp-autoresize wp-toolbar-toggle', adjust );
    293                         editor.off( 'undo redo', mceScroll );
    294 
    295                         $window.off( 'scroll.mce-float-panels' );
    296                 };
    297 
    298                 if ( $wrap.hasClass( 'wp-editor-expand' ) ) {
    299                         // Adjust "immediately"
    300                         mceBind();
    301                         initialResize( adjust );
    302                 }
    303         } );
    304 
    305         // Adjust the toolbars based on the active editor mode.
    306         function adjust( type ) {
    307                 // Make sure we're not in fullscreen mode.
    308                 if ( fullscreen && fullscreen.settings.visible ) {
    309                         return;
    310                 }
    311 
    312                 var windowPos = $window.scrollTop(),
    313                         resize = type !== 'scroll',
    314                         visual = ( mceEditor && ! mceEditor.isHidden() ),
    315                         buffer = autoresizeMinHeight,
    316                         postBodyTop = $postBody.offset().top,
    317                         borderWidth = 1,
    318                         contentWrapWidth = $contentWrap.width(),
    319                         $top, $editor, sidebarTop, footerTop, canPin,
    320                         topPos, topHeight, editorPos, editorHeight;
    321 
    322                 // Refresh the heights
    323                 if ( resize || ! heights.windowHeight ) {
    324                         getHeights();
    325                 }
    326 
    327                 if ( ! visual && type === 'resize' ) {
    328                         textEditorResize();
    329                 }
    330 
    331                 if ( visual ) {
    332                         $top = $visualTop;
    333                         $editor = $visualEditor;
    334                         topHeight = heights.visualTopHeight;
    335                 } else {
    336                         $top = $textTop;
    337                         $editor = $textEditor;
    338                         topHeight = heights.textTopHeight;
    339                 }
    340 
    341                 topPos = $top.parent().offset().top;
    342                 editorPos = $editor.offset().top;
    343                 editorHeight = $editor.outerHeight();
    344 
    345                 // Should we pin?
    346                 canPin = visual ? autoresizeMinHeight + topHeight : autoresizeMinHeight + 20; // 20px from textarea padding
    347                 canPin = editorHeight > ( canPin + 5 );
    348 
    349                 if ( ! canPin ) {
    350                         if ( resize ) {
    351                                 $tools.css( {
    352                                         position: 'absolute',
    353                                         top: 0,
    354                                         width: contentWrapWidth
    355                                 } );
    356 
    357                                 if ( visual && $menuBar.length ) {
    358                                         $menuBar.css( {
    359                                                 position: 'absolute',
    360                                                 top: 0,
    361                                                 width: contentWrapWidth - ( borderWidth * 2 )
    362                                         } );
    363                                 }
    364 
    365                                 $top.css( {
    366                                         position: 'absolute',
    367                                         top: heights.menuBarHeight,
    368                                         width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
    369                                 } );
    370 
    371                                 $statusBar.add( $bottom ).attr( 'style', '' );
    372                         }
    373                 } else {
    374                         // Maybe pin the top.
    375                         if ( ( ! fixedTop || resize ) &&
    376                                 // Handle scrolling down.
    377                                 ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight ) &&
    378                                 // Handle scrolling up.
    379                                 windowPos <= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) ) {
    380                                 fixedTop = true;
    381 
    382                                 $tools.css( {
    383                                         position: 'fixed',
    384                                         top: heights.adminBarHeight,
    385                                         width: contentWrapWidth
    386                                 } );
    387 
    388                                 if ( visual && $menuBar.length ) {
    389                                         $menuBar.css( {
    390                                                 position: 'fixed',
    391                                                 top: heights.adminBarHeight + heights.toolsHeight,
    392                                                 width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
    393                                         } );
    394                                 }
    395 
    396                                 $top.css( {
    397                                         position: 'fixed',
    398                                         top: heights.adminBarHeight + heights.toolsHeight + heights.menuBarHeight,
    399                                         width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
    400                                 } );
    401                         // Maybe unpin the top.
    402                         } else if ( fixedTop || resize ) {
    403                                 // Handle scrolling up.
    404                                 if ( windowPos <= ( topPos - heights.toolsHeight - heights.adminBarHeight ) ) {
    405                                         fixedTop = false;
    406 
     333                        }
     334
     335                        if ( visual ) {
     336                                $top = $visualTop;
     337                                $editor = $visualEditor;
     338                                topHeight = heights.visualTopHeight;
     339                        } else {
     340                                $top = $textTop;
     341                                $editor = $textEditor;
     342                                topHeight = heights.textTopHeight;
     343                        }
     344
     345                        topPos = $top.parent().offset().top;
     346                        editorPos = $editor.offset().top;
     347                        editorHeight = $editor.outerHeight();
     348
     349                        // Should we pin?
     350                        canPin = visual ? autoresizeMinHeight + topHeight : autoresizeMinHeight + 20; // 20px from textarea padding
     351                        canPin = editorHeight > ( canPin + 5 );
     352
     353                        if ( ! canPin ) {
     354                                if ( resize ) {
    407355                                        $tools.css( {
    408356                                                position: 'absolute',
     
    424372                                                width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
    425373                                        } );
    426                                 // Handle scrolling down.
    427                                 } else if ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) {
    428                                         fixedTop = false;
     374
     375                                        $statusBar.add( $bottom ).attr( 'style', '' );
     376                                }
     377                        } else {
     378                                // Maybe pin the top.
     379                                if ( ( ! fixedTop || resize ) &&
     380                                        // Handle scrolling down.
     381                                        ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight ) &&
     382                                        // Handle scrolling up.
     383                                        windowPos <= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) ) {
     384                                        fixedTop = true;
    429385
    430386                                        $tools.css( {
    431                                                 position: 'absolute',
    432                                                 top: editorHeight - buffer,
     387                                                position: 'fixed',
     388                                                top: heights.adminBarHeight,
    433389                                                width: contentWrapWidth
    434390                                        } );
     
    436392                                        if ( visual && $menuBar.length ) {
    437393                                                $menuBar.css( {
     394                                                        position: 'fixed',
     395                                                        top: heights.adminBarHeight + heights.toolsHeight,
     396                                                        width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
     397                                                } );
     398                                        }
     399
     400                                        $top.css( {
     401                                                position: 'fixed',
     402                                                top: heights.adminBarHeight + heights.toolsHeight + heights.menuBarHeight,
     403                                                width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
     404                                        } );
     405                                // Maybe unpin the top.
     406                                } else if ( fixedTop || resize ) {
     407                                        // Handle scrolling up.
     408                                        if ( windowPos <= ( topPos - heights.toolsHeight - heights.adminBarHeight ) ) {
     409                                                fixedTop = false;
     410
     411                                                $tools.css( {
     412                                                        position: 'absolute',
     413                                                        top: 0,
     414                                                        width: contentWrapWidth
     415                                                } );
     416
     417                                                if ( visual && $menuBar.length ) {
     418                                                        $menuBar.css( {
     419                                                                position: 'absolute',
     420                                                                top: 0,
     421                                                                width: contentWrapWidth - ( borderWidth * 2 )
     422                                                        } );
     423                                                }
     424
     425                                                $top.css( {
     426                                                        position: 'absolute',
     427                                                        top: heights.menuBarHeight,
     428                                                        width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
     429                                                } );
     430                                        // Handle scrolling down.
     431                                        } else if ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) {
     432                                                fixedTop = false;
     433
     434                                                $tools.css( {
    438435                                                        position: 'absolute',
    439436                                                        top: editorHeight - buffer,
     437                                                        width: contentWrapWidth
     438                                                } );
     439
     440                                                if ( visual && $menuBar.length ) {
     441                                                        $menuBar.css( {
     442                                                                position: 'absolute',
     443                                                                top: editorHeight - buffer,
     444                                                                width: contentWrapWidth - ( borderWidth * 2 )
     445                                                        } );
     446                                                }
     447
     448                                                $top.css( {
     449                                                        position: 'absolute',
     450                                                        top: editorHeight - buffer + heights.menuBarHeight,
     451                                                        width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
     452                                                } );
     453                                        }
     454                                }
     455
     456                                // Maybe adjust the bottom bar.
     457                                if ( ( ! fixedBottom || ( resize && advanced ) ) &&
     458                                                // +[n] for the border around the .wp-editor-container.
     459                                                ( windowPos + heights.windowHeight ) <= ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight + borderWidth ) ) {
     460
     461                                        if ( event && event.deltaHeight > 0 ) {
     462                                                window.scrollBy( 0, event.deltaHeight );
     463                                        } else if ( advanced ) {
     464                                                fixedBottom = true;
     465
     466                                                $statusBar.css( {
     467                                                        position: 'fixed',
     468                                                        bottom: heights.bottomHeight,
     469                                                        visibility: '',
    440470                                                        width: contentWrapWidth - ( borderWidth * 2 )
    441471                                                } );
    442                                         }
    443 
    444                                         $top.css( {
    445                                                 position: 'absolute',
    446                                                 top: editorHeight - buffer + heights.menuBarHeight,
    447                                                 width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
    448                                         } );
    449                                 }
    450                         }
    451 
    452                         // Maybe adjust the bottom bar.
    453                         if ( ( ! fixedBottom || resize ) &&
    454                                 // +[n] for the border around the .wp-editor-container.
    455                                 ( windowPos + heights.windowHeight ) <= ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight + borderWidth ) ) {
    456                                 fixedBottom = true;
    457 
    458                                 $statusBar.css( {
    459                                         position: 'fixed',
    460                                         bottom: heights.bottomHeight,
    461                                         width: contentWrapWidth - ( borderWidth * 2 )
     472
     473                                                $bottom.css( {
     474                                                        position: 'fixed',
     475                                                        bottom: 0,
     476                                                        width: contentWrapWidth
     477                                                } );
     478                                        }
     479                                } else if ( ( ! advanced && fixedBottom ) ||
     480                                                ( ( fixedBottom || resize ) &&
     481                                                ( windowPos + heights.windowHeight ) > ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight - borderWidth ) ) ) {
     482                                        fixedBottom = false;
     483
     484                                        $statusBar.add( $bottom ).attr( 'style', '' );
     485
     486                                        ! advanced && $statusBar.css( 'visibility', 'hidden' );
     487                                }
     488                        }
     489
     490                        // Sidebar pinning
     491                        if ( $postboxContainer.width() < 300 && heights.windowWidth > 600 && // sidebar position is changed with @media from CSS, make sure it is on the side
     492                                $document.height() > ( $sideSortables.height() + postBodyTop + 120 ) && // the sidebar is not the tallest element
     493                                heights.windowHeight < editorHeight ) { // the editor is taller than the viewport
     494
     495                                if ( ( heights.sideSortablesHeight + pinnedToolsTop + sidebarBottom ) > heights.windowHeight || fixedSideTop || fixedSideBottom ) {
     496                                        // Reset when scrolling to the top
     497                                        if ( windowPos + pinnedToolsTop <= postBodyTop ) {
     498                                                $sideSortables.attr( 'style', '' );
     499                                                fixedSideTop = fixedSideBottom = false;
     500                                        } else {
     501                                                if ( windowPos > lastScrollPosition ) {
     502                                                        // Scrolling down
     503                                                        if ( fixedSideTop ) {
     504                                                                // let it scroll
     505                                                                fixedSideTop = false;
     506                                                                sidebarTop = $sideSortables.offset().top - heights.adminBarHeight;
     507                                                                footerTop = $footer.offset().top;
     508
     509                                                                // don't get over the footer
     510                                                                if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) {
     511                                                                        sidebarTop = footerTop - heights.sideSortablesHeight - 12;
     512                                                                }
     513
     514                                                                $sideSortables.css({
     515                                                                        position: 'absolute',
     516                                                                        top: sidebarTop,
     517                                                                        bottom: ''
     518                                                                });
     519                                                        } else if ( ! fixedSideBottom && heights.sideSortablesHeight + $sideSortables.offset().top + sidebarBottom < windowPos + heights.windowHeight ) {
     520                                                                // pin the bottom
     521                                                                fixedSideBottom = true;
     522
     523                                                                $sideSortables.css({
     524                                                                        position: 'fixed',
     525                                                                        top: 'auto',
     526                                                                        bottom: sidebarBottom
     527                                                                });
     528                                                        }
     529                                                } else if ( windowPos < lastScrollPosition ) {
     530                                                        // Scrolling up
     531                                                        if ( fixedSideBottom ) {
     532                                                                // let it scroll
     533                                                                fixedSideBottom = false;
     534                                                                sidebarTop = $sideSortables.offset().top - sidebarBottom;
     535                                                                footerTop = $footer.offset().top;
     536
     537                                                                // don't get over the footer
     538                                                                if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) {
     539                                                                        sidebarTop = footerTop - heights.sideSortablesHeight - 12;
     540                                                                }
     541
     542                                                                $sideSortables.css({
     543                                                                        position: 'absolute',
     544                                                                        top: sidebarTop,
     545                                                                        bottom: ''
     546                                                                });
     547                                                        } else if ( ! fixedSideTop && $sideSortables.offset().top >= windowPos + pinnedToolsTop ) {
     548                                                                // pin the top
     549                                                                fixedSideTop = true;
     550
     551                                                                $sideSortables.css({
     552                                                                        position: 'fixed',
     553                                                                        top: pinnedToolsTop,
     554                                                                        bottom: ''
     555                                                                });
     556                                                        }
     557                                                }
     558                                        }
     559                                } else {
     560                                        // if the sidebar container is smaller than the viewport, then pin/unpin the top when scrolling
     561                                        if ( windowPos >= ( postBodyTop - pinnedToolsTop ) ) {
     562
     563                                                $sideSortables.css( {
     564                                                        position: 'fixed',
     565                                                        top: pinnedToolsTop
     566                                                } );
     567                                        } else {
     568                                                $sideSortables.attr( 'style', '' );
     569                                        }
     570
     571                                        fixedSideTop = fixedSideBottom = false;
     572                                }
     573
     574                                lastScrollPosition = windowPos;
     575                        } else {
     576                                $sideSortables.attr( 'style', '' );
     577                                fixedSideTop = fixedSideBottom = false;
     578                        }
     579
     580                        if ( resize ) {
     581                                $contentWrap.css( {
     582                                        paddingTop: heights.toolsHeight
    462583                                } );
    463584
    464                                 $bottom.css( {
    465                                         position: 'fixed',
    466                                         bottom: 0,
    467                                         width: contentWrapWidth
    468                                 } );
    469                         } else if ( ( fixedBottom || resize ) &&
    470                                         ( windowPos + heights.windowHeight ) > ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight - borderWidth ) ) {
    471                                 fixedBottom = false;
    472 
    473                                 $statusBar.add( $bottom ).attr( 'style', '' );
    474                         }
    475                 }
    476 
    477                 // Sidebar pinning
    478                 if ( $postboxContainer.width() < 300 && heights.windowWidth > 600 && // sidebar position is changed with @media from CSS, make sure it is on the side
    479                         $document.height() > ( $sideSortables.height() + postBodyTop + 120 ) && // the sidebar is not the tallest element
    480                         heights.windowHeight < editorHeight ) { // the editor is taller than the viewport
    481 
    482                         if ( ( heights.sideSortablesHeight + pinnedToolsTop + sidebarBottom ) > heights.windowHeight || fixedSideTop || fixedSideBottom ) {
    483                                 // Reset when scrolling to the top
    484                                 if ( windowPos + pinnedToolsTop <= postBodyTop ) {
    485                                         $sideSortables.attr( 'style', '' );
    486                                         fixedSideTop = fixedSideBottom = false;
    487                                 } else {
    488                                         if ( windowPos > lastScrollPosition ) {
    489                                                 // Scrolling down
    490                                                 if ( fixedSideTop ) {
    491                                                         // let it scroll
    492                                                         fixedSideTop = false;
    493                                                         sidebarTop = $sideSortables.offset().top - heights.adminBarHeight;
    494                                                         footerTop = $footer.offset().top;
    495 
    496                                                         // don't get over the footer
    497                                                         if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) {
    498                                                                 sidebarTop = footerTop - heights.sideSortablesHeight - 12;
    499                                                         }
    500 
    501                                                         $sideSortables.css({
    502                                                                 position: 'absolute',
    503                                                                 top: sidebarTop,
    504                                                                 bottom: ''
    505                                                         });
    506                                                 } else if ( ! fixedSideBottom && heights.sideSortablesHeight + $sideSortables.offset().top + sidebarBottom < windowPos + heights.windowHeight ) {
    507                                                         // pin the bottom
    508                                                         fixedSideBottom = true;
    509 
    510                                                         $sideSortables.css({
    511                                                                 position: 'fixed',
    512                                                                 top: 'auto',
    513                                                                 bottom: sidebarBottom
    514                                                         });
    515                                                 }
    516                                         } else if ( windowPos < lastScrollPosition ) {
    517                                                 // Scrolling up
    518                                                 if ( fixedSideBottom ) {
    519                                                         // let it scroll
    520                                                         fixedSideBottom = false;
    521                                                         sidebarTop = $sideSortables.offset().top - sidebarBottom;
    522                                                         footerTop = $footer.offset().top;
    523 
    524                                                         // don't get over the footer
    525                                                         if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) {
    526                                                                 sidebarTop = footerTop - heights.sideSortablesHeight - 12;
    527                                                         }
    528 
    529                                                         $sideSortables.css({
    530                                                                 position: 'absolute',
    531                                                                 top: sidebarTop,
    532                                                                 bottom: ''
    533                                                         });
    534                                                 } else if ( ! fixedSideTop && $sideSortables.offset().top >= windowPos + pinnedToolsTop ) {
    535                                                         // pin the top
    536                                                         fixedSideTop = true;
    537 
    538                                                         $sideSortables.css({
    539                                                                 position: 'fixed',
    540                                                                 top: pinnedToolsTop,
    541                                                                 bottom: ''
    542                                                         });
    543                                                 }
    544                                         }
    545                                 }
    546                         } else {
    547                                 // if the sidebar container is smaller than the viewport, then pin/unpin the top when scrolling
    548                                 if ( windowPos >= ( postBodyTop - pinnedToolsTop ) ) {
    549 
    550                                         $sideSortables.css( {
    551                                                 position: 'fixed',
    552                                                 top: pinnedToolsTop
     585                                if ( visual ) {
     586                                        $visualEditor.css( {
     587                                                paddingTop: heights.visualTopHeight + heights.menuBarHeight
    553588                                        } );
    554589                                } else {
    555                                         $sideSortables.attr( 'style', '' );
    556                                 }
    557 
    558                                 fixedSideTop = fixedSideBottom = false;
    559                         }
    560 
    561                         lastScrollPosition = windowPos;
    562                 } else {
    563                         $sideSortables.attr( 'style', '' );
    564                         fixedSideTop = fixedSideBottom = false;
    565                 }
    566 
    567                 if ( resize ) {
    568                         $contentWrap.css( {
    569                                 paddingTop: heights.toolsHeight
     590                                        $textEditor.css( {
     591                                                marginTop: heights.textTopHeight
     592                                        } );
     593
     594                                        $textEditorClone.width( contentWrapWidth - 20 - ( borderWidth * 2 ) );
     595                                }
     596                        }
     597                }
     598
     599                function fullscreenHide() {
     600                        textEditorResize();
     601                        adjust();
     602                }
     603
     604                function initialResize( callback ) {
     605                        for ( var i = 1; i < 6; i++ ) {
     606                                setTimeout( callback, 500 * i );
     607                        }
     608                }
     609
     610                function afterScroll() {
     611                        clearTimeout( scrollTimer );
     612                        scrollTimer = setTimeout( adjust, 100 );
     613                }
     614
     615                function on() {
     616                        // Scroll to the top when triggering this from JS.
     617                        // Ensures toolbars are pinned properly.
     618                        if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) {
     619                                window.scrollTo( window.pageXOffset, 0 );
     620                        }
     621
     622                        $wrap.addClass( 'wp-editor-expand' );
     623
     624                        // Adjust when the window is scrolled or resized.
     625                        $window.on( 'scroll.editor-expand resize.editor-expand', function( event ) {
     626                                adjust( event.type );
     627                                afterScroll();
    570628                        } );
    571629
    572                         if ( visual ) {
    573                                 $visualEditor.css( {
    574                                         paddingTop: heights.visualTopHeight + heights.menuBarHeight
     630                        // Adjust when collapsing the menu, changing the columns, changing the body class.
     631                        $document.on( 'wp-collapse-menu.editor-expand postboxes-columnchange.editor-expand editor-classchange.editor-expand', adjust )
     632                                .on( 'postbox-toggled.editor-expand', function() {
     633                                        if ( ! fixedSideTop && ! fixedSideBottom && window.pageYOffset > pinnedToolsTop ) {
     634                                                fixedSideBottom = true;
     635                                                window.scrollBy( 0, -1 );
     636                                                adjust();
     637                                                window.scrollBy( 0, 1 );
     638                                        }
     639
     640                                        adjust();
     641                                }).on( 'wp-window-resized.editor-expand', function() {
     642                                        if ( mceEditor && ! mceEditor.isHidden() ) {
     643                                                mceEditor.execCommand( 'wpAutoResize' );
     644                                        } else {
     645                                                textEditorResize();
     646                                        }
     647                                });
     648
     649                        $textEditor.on( 'focus.editor-expand input.editor-expand propertychange.editor-expand', textEditorResize );
     650                        $textEditor.on( 'keyup.editor-expand', textEditorKeyup );
     651                        mceBind();
     652
     653                        // Adjust when entering/exiting fullscreen mode.
     654                        fullscreen && fullscreen.pubsub.subscribe( 'hidden', fullscreenHide );
     655
     656                        if ( mceEditor ) {
     657                                mceEditor.settings.wp_autoresize_on = true;
     658                                mceEditor.execCommand( 'wpAutoResizeOn' );
     659
     660                                if ( ! mceEditor.isHidden() ) {
     661                                        mceEditor.execCommand( 'wpAutoResize' );
     662                                }
     663                        }
     664
     665                        if ( ! mceEditor || mceEditor.isHidden() ) {
     666                                textEditorResize();
     667                        }
     668
     669                        adjust();
     670
     671                        $document.trigger( 'editor-expand-on' );
     672                }
     673
     674                function off() {
     675                        var height = window.getUserSetting('ed_size');
     676
     677                        // Scroll to the top when triggering this from JS.
     678                        // Ensures toolbars are reset properly.
     679                        if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) {
     680                                window.scrollTo( window.pageXOffset, 0 );
     681                        }
     682
     683                        $wrap.removeClass( 'wp-editor-expand' );
     684
     685                        $window.off( '.editor-expand' );
     686                        $document.off( '.editor-expand' );
     687                        $textEditor.off( '.editor-expand' );
     688                        mceUnbind();
     689
     690                        // Adjust when entering/exiting fullscreen mode.
     691                        fullscreen && fullscreen.pubsub.unsubscribe( 'hidden', fullscreenHide );
     692
     693                        // Reset all css
     694                        $.each( [ $visualTop, $textTop, $tools, $menuBar, $bottom, $statusBar, $contentWrap, $visualEditor, $textEditor, $sideSortables ], function( i, element ) {
     695                                element && element.attr( 'style', '' );
     696                        });
     697
     698                        fixedTop = fixedBottom = fixedSideTop = fixedSideBottom = false;
     699
     700                        if ( mceEditor ) {
     701                                mceEditor.settings.wp_autoresize_on = false;
     702                                mceEditor.execCommand( 'wpAutoResizeOff' );
     703
     704                                if ( ! mceEditor.isHidden() ) {
     705                                        $textEditor.hide();
     706
     707                                        if ( height ) {
     708                                                mceEditor.theme.resizeTo( null, height );
     709                                        }
     710                                }
     711                        }
     712
     713                        if ( height ) {
     714                                $textEditor.height( height );
     715                        }
     716
     717                        $document.trigger( 'editor-expand-off' );
     718                }
     719
     720                // Start on load
     721                if ( $wrap.hasClass( 'wp-editor-expand' ) ) {
     722                        on();
     723
     724                        // Ideally we need to resize just after CSS has fully loaded and QuickTags is ready.
     725                        if ( $contentWrap.hasClass( 'html-active' ) ) {
     726                                initialResize( function() {
     727                                        adjust();
     728                                        textEditorResize();
    575729                                } );
     730                        }
     731                }
     732
     733                // Show the on/off checkbox
     734                $( '#adv-settings .editor-expand' ).show();
     735                $( '#editor-expand-toggle' ).on( 'change.editor-expand', function() {
     736                        if ( $(this).prop( 'checked' ) ) {
     737                                on();
     738                                window.setUserSetting( 'editor_expand', 'on' );
    576739                        } else {
    577                                 $textEditor.css( {
    578                                         marginTop: heights.textTopHeight
     740                                off();
     741                                window.setUserSetting( 'editor_expand', 'off' );
     742                        }
     743                });
     744
     745                // Expose on() and off()
     746                window.editorExpand = {
     747                        on: on,
     748                        off: off
     749                };
     750        } );
     751
     752        /* DFW. */
     753        $( function() {
     754                var $body = $( document.body ),
     755                        $wrap = $( '#wpcontent' ),
     756                        $editor = $( '#post-body-content' ),
     757                        $title = $( '#title' ),
     758                        $content = $( '#content' ),
     759                        $overlay = $( document.createElement( 'DIV' ) ),
     760                        $slug = $( '#edit-slug-box' ),
     761                        $slugFocusEl = $slug.find( 'a' )
     762                                .add( $slug.find( 'button' ) )
     763                                .add( $slug.find( 'input' ) ),
     764                        $menuWrap = $( '#adminmenuwrap' ),
     765                        $editorWindow = $(),
     766                        $editorIframe = $(),
     767                        _isActive = window.getUserSetting( 'editor_expand', 'on' ) === 'on',
     768                        _isOn = _isActive ? !! parseInt( window.getUserSetting( 'dfw', '1' ), 10 ) : false,
     769                        traveledX = 0,
     770                        traveledY = 0,
     771                        buffer = 20,
     772                        faded, fadedAdminBar, fadedSlug,
     773                        editorRect, x, y, mouseY, scrollY,
     774                        focusLostTimer, overlayTimer, editorHasFocus;
     775
     776                $body.append( $overlay );
     777
     778                $overlay.css( {
     779                        display: 'none',
     780                        position: 'fixed',
     781                        top: $adminBar.height(),
     782                        right: 0,
     783                        bottom: 0,
     784                        left: 0,
     785                        'z-index': 9997
     786                } );
     787
     788                $editor.css( {
     789                        position: 'relative'
     790                } );
     791
     792                $window.on( 'mousemove.focus', function( event ) {
     793                        mouseY = event.pageY;
     794                } );
     795
     796                function activate() {
     797                        if ( ! _isActive ) {
     798                                _isActive = true;
     799
     800                                $document.trigger( 'dfw-activate' );
     801                        }
     802                }
     803
     804                function deactivate() {
     805                        if ( _isActive ) {
     806                                off();
     807
     808                                _isActive = false;
     809
     810                                $document.trigger( 'dfw-deactivate' );
     811                        }
     812                }
     813
     814                function isActive() {
     815                        return _isActive;
     816                }
     817
     818                function on() {
     819                        if ( ! _isOn && _isActive ) {
     820                                _isOn = true;
     821
     822                                $content.on( 'keydown.focus', fadeOut );
     823
     824                                $title.add( $content ).on( 'blur.focus', maybeFadeIn );
     825
     826                                fadeOut();
     827
     828                                window.setUserSetting( 'dfw', '1' );
     829
     830                                $document.trigger( 'dfw-on' );
     831                        }
     832                }
     833
     834                function off() {
     835                        if ( _isOn ) {
     836                                _isOn = false;
     837
     838                                $title.add( $content ).off( '.focus' );
     839
     840                                fadeIn();
     841
     842                                $editor.off( '.focus' );
     843
     844                                window.setUserSetting( 'dfw', '0' );
     845
     846                                $document.trigger( 'dfw-off' );
     847                        }
     848                }
     849
     850                function toggle() {
     851                        ( _isOn ? off : on )();
     852                }
     853
     854                function isOn() {
     855                        return _isOn;
     856                }
     857
     858                function fadeOut( event ) {
     859                        var key = event && event.keyCode;
     860
     861                        if ( key === 27 ) {
     862                                fadeIn();
     863                                return;
     864                        }
     865
     866                        if ( event && ( event.metaKey || ( event.ctrlKey && ! event.altKey ) || ( key && (
     867                                // Special keys ( tab, ctrl, alt, esc, arrow keys... )
     868                                ( key <= 47 && key !== 8 && key !== 13 && key !== 32 && key !== 46 ) ||
     869                                // Windows keys
     870                                ( key >= 91 && key <= 93 ) ||
     871                                // F keys
     872                                ( key >= 112 && key <= 135 ) ||
     873                                // Num Lock, Scroll Lock, OEM
     874                                ( key >= 144 && key <= 150 ) ||
     875                                // OEM or non-printable
     876                                key >= 224
     877                        ) ) ) ) {
     878                                return;
     879                        }
     880
     881                        if ( ! faded ) {
     882                                faded = true;
     883
     884                                clearTimeout( overlayTimer );
     885
     886                                overlayTimer = setTimeout( function() {
     887                                        $overlay.show();
     888                                }, 600 );
     889
     890                                $editor.css( 'z-index', 9998 );
     891
     892                                $overlay
     893                                        // Always recalculate the editor area entering the overlay with the mouse.
     894                                        .on( 'mouseenter.focus', function() {
     895                                                editorRect = $editor.offset();
     896                                                editorRect.right = editorRect.left + $editor.outerWidth();
     897                                                editorRect.bottom = editorRect.top + $editor.outerHeight();
     898
     899                                                $window.on( 'scroll.focus', function() {
     900                                                        var nScrollY = window.pageYOffset;
     901
     902                                                        if ( (
     903                                                                scrollY && mouseY &&
     904                                                                scrollY !== nScrollY
     905                                                        ) && (
     906                                                                mouseY < editorRect.top - buffer ||
     907                                                                mouseY > editorRect.bottom + buffer
     908                                                        ) ) {
     909                                                                fadeIn();
     910                                                        }
     911
     912                                                        scrollY = nScrollY;
     913                                                } );
     914                                        } )
     915                                        .on( 'mouseleave.focus', function() {
     916                                                x = y =  null;
     917                                                traveledX = traveledY = 0;
     918
     919                                                $window.off( 'scroll.focus' );
     920                                        } )
     921                                        // Fade in when the mouse moves away form the editor area.
     922                                        .on( 'mousemove.focus', function( event ) {
     923                                                var nx = event.pageX,
     924                                                        ny = event.pageY;
     925
     926                                                if ( x && y && ( nx !== x || ny !== y ) ) {
     927                                                        if (
     928                                                                ( ny <= y && ny < editorRect.top ) ||
     929                                                                ( ny >= y && ny > editorRect.bottom ) ||
     930                                                                ( nx <= x && nx < editorRect.left ) ||
     931                                                                ( nx >= x && nx > editorRect.right )
     932                                                        ) {
     933                                                                traveledX += Math.abs( x - nx );
     934                                                                traveledY += Math.abs( y - ny );
     935
     936                                                                if ( (
     937                                                                        ny <= editorRect.top - buffer ||
     938                                                                        ny >= editorRect.bottom + buffer ||
     939                                                                        nx <= editorRect.left - buffer ||
     940                                                                        nx >= editorRect.right + buffer
     941                                                                ) && (
     942                                                                        traveledX > 10 ||
     943                                                                        traveledY > 10
     944                                                                ) ) {
     945                                                                        fadeIn();
     946
     947                                                                        x = y =  null;
     948                                                                        traveledX = traveledY = 0;
     949
     950                                                                        return;
     951                                                                }
     952                                                        } else {
     953                                                                traveledX = traveledY = 0;
     954                                                        }
     955                                                }
     956
     957                                                x = nx;
     958                                                y = ny;
     959                                        } )
     960                                        // When the overlay is touched, always fade in and cancel the event.
     961                                        .on( 'touchstart.focus', function( event ) {
     962                                                event.preventDefault();
     963                                                fadeIn();
     964                                        } );
     965
     966                                $editor.off( 'mouseenter.focus' );
     967
     968                                if ( focusLostTimer ) {
     969                                        clearTimeout( focusLostTimer );
     970                                        focusLostTimer = null;
     971                                }
     972
     973                                $body.addClass( 'focus-on' ).removeClass( 'focus-off' );
     974                        }
     975
     976                        fadeOutAdminBar();
     977                        fadeOutSlug();
     978                }
     979
     980                function fadeIn() {
     981                        if ( faded ) {
     982                                faded = false;
     983
     984                                clearTimeout( overlayTimer );
     985
     986                                overlayTimer = setTimeout( function() {
     987                                        $overlay.hide();
     988                                }, 200 );
     989
     990                                $editor.css( 'z-index', '' );
     991
     992                                $overlay.off( 'mouseenter.focus mouseleave.focus mousemove.focus touchstart.focus' );
     993
     994                                $editor.on( 'mouseenter.focus', function() {
     995                                        if ( $.contains( $editor.get( 0 ), document.activeElement ) || editorHasFocus ) {
     996                                                fadeOut();
     997                                        }
    579998                                } );
    580999
    581                                 $textEditorClone.width( contentWrapWidth - 20 - ( borderWidth * 2 ) );
    582                         }
    583                 }
    584         }
    585 
    586         function fullscreenHide() {
    587                 textEditorResize();
    588                 adjust();
    589         }
    590 
    591         function initialResize( callback ) {
    592                 for ( var i = 1; i < 6; i++ ) {
    593                         setTimeout( callback, 500 * i );
    594                 }
    595         }
    596 
    597         function afterScroll() {
    598                 clearTimeout( scrollTimer );
    599                 scrollTimer = setTimeout( adjust, 100 );
    600         }
    601 
    602         function on() {
    603                 // Scroll to the top when triggering this from JS.
    604                 // Ensures toolbars are pinned properly.
    605                 if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) {
    606                         window.scrollTo( window.pageXOffset, 0 );
    607                 }
    608 
    609                 $wrap.addClass( 'wp-editor-expand' );
    610 
    611                 // Adjust when the window is scrolled or resized.
    612                 $window.on( 'scroll.editor-expand resize.editor-expand', function( event ) {
    613                         adjust( event.type );
    614                         afterScroll();
     1000                                focusLostTimer = setTimeout( function() {
     1001                                        focusLostTimer = null;
     1002                                        $editor.off( 'mouseenter.focus' );
     1003                                }, 1000 );
     1004
     1005                                $body.addClass( 'focus-off' ).removeClass( 'focus-on' );
     1006                        }
     1007
     1008                        fadeInAdminBar();
     1009                        fadeInSlug();
     1010                }
     1011
     1012                function maybeFadeIn() {
     1013                        setTimeout( function() {
     1014                                var position = document.activeElement.compareDocumentPosition( $editor.get( 0 ) );
     1015
     1016                                function hasFocus( $el ) {
     1017                                        return $.contains( $el.get( 0 ), document.activeElement );
     1018                                }
     1019
     1020                                // The focussed node is before or behind the editor area, and not ouside the wrap.
     1021                                if ( ( position === 2 || position === 4 ) && ( hasFocus( $menuWrap ) || hasFocus( $wrap ) || hasFocus( $footer ) ) ) {
     1022                                        fadeIn();
     1023                                }
     1024                        }, 0 );
     1025                }
     1026
     1027                function fadeOutAdminBar() {
     1028                        if ( ! fadedAdminBar && faded ) {
     1029                                fadedAdminBar = true;
     1030
     1031                                $adminBar
     1032                                        .on( 'mouseenter.focus', function() {
     1033                                                $adminBar.addClass( 'focus-off' );
     1034                                        } )
     1035                                        .on( 'mouseleave.focus', function() {
     1036                                                $adminBar.removeClass( 'focus-off' );
     1037                                        } );
     1038                        }
     1039                }
     1040
     1041                function fadeInAdminBar() {
     1042                        if ( fadedAdminBar ) {
     1043                                fadedAdminBar = false;
     1044
     1045                                $adminBar.off( '.focus' );
     1046                        }
     1047                }
     1048
     1049                function fadeOutSlug() {
     1050                        if ( ! fadedSlug && faded && ! $slug.find( ':focus').length ) {
     1051                                fadedSlug = true;
     1052
     1053                                $slug.stop().fadeTo( 'fast', 0.3 ).on( 'mouseenter.focus', fadeInSlug ).off( 'mouseleave.focus' );
     1054
     1055                                $slugFocusEl.on( 'focus.focus', fadeInSlug ).off( 'blur.focus' );
     1056                        }
     1057                }
     1058
     1059                function fadeInSlug() {
     1060                        if ( fadedSlug ) {
     1061                                fadedSlug = false;
     1062
     1063                                $slug.stop().fadeTo( 'fast', 1 ).on( 'mouseleave.focus', fadeOutSlug ).off( 'mouseenter.focus' );
     1064
     1065                                $slugFocusEl.on( 'blur.focus', fadeOutSlug ).off( 'focus.focus' );
     1066                        }
     1067                }
     1068
     1069                $document.on( 'tinymce-editor-setup.focus', function( event, editor ) {
     1070                        editor.addButton( 'dfw', {
     1071                                active: _isOn,
     1072                                classes: 'wp-dfw btn widget',
     1073                                disabled: ! _isActive,
     1074                                onclick: toggle,
     1075                                onPostRender: function() {
     1076                                        var button = this;
     1077
     1078                                        $document
     1079                                        .on( 'dfw-activate.focus', function() {
     1080                                                button.disabled( false );
     1081                                        } )
     1082                                        .on( 'dfw-deactivate.focus', function() {
     1083                                                button.disabled( true );
     1084                                        } )
     1085                                        .on( 'dfw-on.focus', function() {
     1086                                                button.active( true );
     1087                                        } )
     1088                                        .on( 'dfw-off.focus', function() {
     1089                                                button.active( false );
     1090                                        } );
     1091                                },
     1092                                tooltip: 'Distraction Free Writing'
     1093                        } );
    6151094                } );
    6161095
    617                 // Adjust when collapsing the menu, changing the columns, changing the body class.
    618                 $document.on( 'wp-collapse-menu.editor-expand postboxes-columnchange.editor-expand editor-classchange.editor-expand', adjust )
    619                         .on( 'postbox-toggled.editor-expand', function() {
    620                                 if ( ! fixedSideTop && ! fixedSideBottom && window.pageYOffset > pinnedToolsTop ) {
    621                                         fixedSideBottom = true;
    622                                         window.scrollBy( 0, -1 );
    623                                         adjust();
    624                                         window.scrollBy( 0, 1 );
    625                                 }
    626 
    627                                 adjust();
    628                         }).on( 'wp-window-resized.editor-expand', function() {
    629                                 if ( mceEditor && ! mceEditor.isHidden() ) {
    630                                         mceEditor.execCommand( 'wpAutoResize' );
    631                                 } else {
    632                                         textEditorResize();
    633                                 }
    634                         });
    635 
    636                 $textEditor.on( 'focus.editor-expand input.editor-expand propertychange.editor-expand', textEditorResize );
    637                 $textEditor.on( 'keyup.editor-expand', textEditorKeyup );
    638                 mceBind();
    639 
    640                 // Adjust when entering/exiting fullscreen mode.
    641                 fullscreen && fullscreen.pubsub.subscribe( 'hidden', fullscreenHide );
    642 
    643                 if ( mceEditor ) {
    644                         mceEditor.settings.wp_autoresize_on = true;
    645                         mceEditor.execCommand( 'wpAutoResizeOn' );
    646 
    647                         if ( ! mceEditor.isHidden() ) {
    648                                 mceEditor.execCommand( 'wpAutoResize' );
    649                         }
    650                 }
    651 
    652                 if ( ! mceEditor || mceEditor.isHidden() ) {
    653                         textEditorResize();
    654                 }
    655 
    656                 adjust();
    657         }
    658 
    659         function off() {
    660                 var height = window.getUserSetting('ed_size');
    661 
    662                 // Scroll to the top when triggering this from JS.
    663                 // Ensures toolbars are reset properly.
    664                 if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) {
    665                         window.scrollTo( window.pageXOffset, 0 );
    666                 }
    667 
    668                 $wrap.removeClass( 'wp-editor-expand' );
    669 
    670                 $window.off( '.editor-expand' );
    671                 $document.off( '.editor-expand' );
    672                 $textEditor.off( '.editor-expand' );
    673                 mceUnbind();
    674 
    675                 // Adjust when entering/exiting fullscreen mode.
    676                 fullscreen && fullscreen.pubsub.unsubscribe( 'hidden', fullscreenHide );
    677 
    678                 // Reset all css
    679                 $.each( [ $visualTop, $textTop, $tools, $menuBar, $bottom, $statusBar, $contentWrap, $visualEditor, $textEditor, $sideSortables ], function( i, element ) {
    680                         element && element.attr( 'style', '' );
    681                 });
    682 
    683                 fixedTop = fixedBottom = fixedSideTop = fixedSideBottom = false;
    684 
    685                 if ( mceEditor ) {
    686                         mceEditor.settings.wp_autoresize_on = false;
    687                         mceEditor.execCommand( 'wpAutoResizeOff' );
    688 
    689                         if ( ! mceEditor.isHidden() ) {
    690                                 $textEditor.hide();
    691 
    692                                 if ( height ) {
    693                                         mceEditor.theme.resizeTo( null, height );
    694                                 }
    695                         }
    696                 }
    697 
    698                 if ( height ) {
    699                         $textEditor.height( height );
    700                 }
    701         }
    702 
    703         // Start on load
    704         if ( $wrap.hasClass( 'wp-editor-expand' ) ) {
    705                 on();
    706 
    707                 // Ideally we need to resize just after CSS has fully loaded and QuickTags is ready.
    708                 if ( $contentWrap.hasClass( 'html-active' ) ) {
    709                         initialResize( function() {
    710                                 adjust();
    711                                 textEditorResize();
    712                         } );
    713                 }
    714         }
    715 
    716         // Show the on/off checkbox
    717         $( '#adv-settings .editor-expand' ).show();
    718         $( '#editor-expand-toggle' ).on( 'change.editor-expand', function() {
    719                 if ( $(this).prop( 'checked' ) ) {
    720                         on();
    721                         window.setUserSetting( 'editor_expand', 'on' );
    722                 } else {
    723                         off();
    724                         window.setUserSetting( 'editor_expand', 'off' );
    725                 }
    726         });
    727 
    728         // Expose on() and off()
    729         window.editorExpand = {
    730                 on: on,
    731                 off: off
    732         };
    733 });
     1096                $document.on( 'tinymce-editor-init.focus', function( event, editor ) {
     1097                        var mceBind, mceUnbind;
     1098
     1099                        function focus() {
     1100                                editorHasFocus = true;
     1101                        }
     1102
     1103                        function blur() {
     1104                                editorHasFocus = false;
     1105                        }
     1106
     1107                        if ( editor.id === 'content' ) {
     1108                                $editorWindow = $( editor.getWin() );
     1109                                $editorIframe = $( editor.getContentAreaContainer() ).find( 'iframe' );
     1110
     1111                                mceBind = function() {
     1112                                        editor.on( 'keydown', fadeOut );
     1113                                        editor.on( 'blur', maybeFadeIn );
     1114                                        editor.on( 'focus', focus );
     1115                                        editor.on( 'blur', blur );
     1116                                };
     1117
     1118                                mceUnbind = function() {
     1119                                        editor.off( 'keydown', fadeOut );
     1120                                        editor.off( 'blur', maybeFadeIn );
     1121                                        editor.off( 'focus', focus );
     1122                                        editor.off( 'blur', blur );
     1123                                };
     1124
     1125                                if ( _isOn ) {
     1126                                        mceBind();
     1127                                }
     1128
     1129                                $document.on( 'dfw-on.focus', mceBind ).on( 'dfw-off.focus', mceUnbind );
     1130
     1131                                // Make sure the body focusses when clicking outside it.
     1132                                editor.on( 'click', function( event ) {
     1133                                        if ( event.target === editor.getDoc().documentElement ) {
     1134                                                editor.focus();
     1135                                        }
     1136                                } );
     1137                        }
     1138                } );
     1139
     1140                $document.on( 'quicktags-init', function( event, editor ) {
     1141                        var $button;
     1142
     1143                        if ( editor.settings.buttons && ( ',' + editor.settings.buttons + ',' ).indexOf( ',dfw,' ) !== -1 ) {
     1144                                $button = $( '#' + editor.name + '_dfw' );
     1145
     1146                                $( document )
     1147                                .on( 'dfw-activate', function() {
     1148                                        $button.prop( 'disabled', false );
     1149                                } )
     1150                                .on( 'dfw-deactivate', function() {
     1151                                        $button.prop( 'disabled', true );
     1152                                } )
     1153                                .on( 'dfw-on', function() {
     1154                                        $button.addClass( 'active' );
     1155                                } )
     1156                                .on( 'dfw-off', function() {
     1157                                        $button.removeClass( 'active' );
     1158                                } );
     1159                        }
     1160                } );
     1161
     1162                $document.on( 'editor-expand-on.focus', activate ).on( 'editor-expand-off.focus', deactivate );
     1163
     1164                if ( _isOn ) {
     1165                        $content.on( 'keydown.focus', fadeOut );
     1166
     1167                        $title.add( $content ).on( 'blur.focus', maybeFadeIn );
     1168                }
     1169
     1170                window.wp = window.wp || {};
     1171                window.wp.editor = window.wp.editor || {};
     1172                window.wp.editor.dfw = {
     1173                        activate: activate,
     1174                        deactivate: deactivate,
     1175                        isActive: isActive,
     1176                        on: on,
     1177                        off: off,
     1178                        toggle: toggle,
     1179                        isOn: isOn
     1180                };
     1181        } );
     1182} )( window, window.jQuery );
  • trunk/src/wp-includes/class-wp-editor.php

    r30319 r30338  
    279279                                $qtInit['buttons'] .= ',fullscreen';
    280280
     281                        if ( $editor_id === 'content' && ! wp_is_mobile() )
     282                                $qtInit['buttons'] .= ',dfw';
     283
    281284                        /**
    282285                         * Filter the Quicktags settings.
     
    547550                                $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = array();
    548551                        } else {
     552                                $mce_buttons = array( 'bold', 'italic', 'strikethrough', 'bullist', 'numlist', 'blockquote', 'hr', 'alignleft', 'aligncenter', 'alignright', 'link', 'unlink', 'wp_more', 'spellchecker', 'wp_adv' );
     553
     554                                if ( $editor_id ) {
     555                                        $mce_buttons[] = 'dfw';
     556                                } else {
     557                                        $mce_buttons[] = 'fullscreen';
     558                                }
    549559
    550560                                /**
     
    556566                                 * @param string $editor_id Unique editor identifier, e.g. 'content'.
    557567                                 */
    558                                 $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 );
     568                                $mce_buttons = apply_filters( 'mce_buttons', $mce_buttons, $editor_id );
    559569
    560570                                /**
  • trunk/src/wp-includes/css/editor.css

    r30318 r30338  
    284284
    285285.mce-toolbar .mce-btn,
    286 .qt-fullscreen {
     286.qt-dfw {
    287287        border-color: transparent;
    288288        background: transparent;
     
    295295#wp-fullscreen-buttons .mce-btn,
    296296.mce-toolbar .mce-btn-group .mce-btn,
    297 .qt-fullscreen {
     297.qt-dfw {
    298298        border: 1px solid transparent;
    299299        margin: 2px;
     
    309309#wp-fullscreen-buttons .mce-btn:focus,
    310310.mce-toolbar .mce-btn-group .mce-btn:focus,
    311 .qt-fullscreen:hover,
    312 .qt-fullscreen:focus {
     311.qt-dfw:hover,
     312.qt-dfw:focus {
    313313        background: #fafafa;
    314314        border-color: #999;
     
    316316        -webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba( 0, 0, 0, 0.08 );
    317317        box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba( 0, 0, 0, 0.08 );
     318        outline: none;
    318319}
    319320
     
    321322#wp-fullscreen-buttons .mce-btn.mce-active,
    322323.mce-toolbar .mce-btn-group .mce-btn:active,
    323 #wp-fullscreen-buttons .mce-btn:active {
     324#wp-fullscreen-buttons .mce-btn:active,
     325.qt-dfw.active {
    324326        background: #ebebeb;
    325327        border-color: #999;
     
    354356
    355357.mce-toolbar .mce-btn button,
    356 .qt-fullscreen {
     358.qt-dfw {
    357359        padding: 2px 3px;
    358360        line-height: normal;
     
    669671}
    670672
    671 .qt-fullscreen {
     673.qt-dfw {
    672674        color: #777;
    673675        line-height: 20px;
     
    703705i.mce-i-fullscreen,
    704706i.mce-i-wp_fullscreen,
     707i.mce-i-dfw,
    705708i.mce-i-wp_adv,
    706709i.mce-i-underline,
     
    734737}
    735738
    736 .qt-fullscreen {
     739.qt-dfw {
    737740        font: normal 20px/1 'dashicons';
    738741        vertical-align: top;
     
    796799i.mce-i-fullscreen:before,
    797800i.mce-i-wp_fullscreen:before,
    798 .qt-fullscreen:before {
     801i.mce-i-dfw:before,
     802.qt-dfw:before {
    799803        content: '\f211';
    800804}
     
    10721076}
    10731077
    1074 .mce-toolbar .mce-btn-group .mce-btn.mce-wp-fullscreen,
    1075 .qt-fullscreen {
     1078.mce-toolbar .mce-btn-group .mce-btn.mce-wp-dfw,
     1079.qt-dfw {
    10761080        position: absolute;
    10771081        top: 0;
     
    10821086@media screen and ( max-width: 782px ) {
    10831087        .mce-toolbar .mce-btn button,
    1084         .qt-fullscreen {
     1088        .qt-dfw {
    10851089                padding: 6px 7px;
    10861090        }
     
    10911095        }
    10921096
    1093         .qt-fullscreen {
     1097        .qt-dfw {
    10941098                width: 36px;
    10951099                height: 34px;
    10961100        }
    10971101
    1098         .mce-toolbar .mce-btn-group .mce-btn.mce-wp-fullscreen {
     1102        .mce-toolbar .mce-btn-group .mce-btn.mce-wp-dfw {
    10991103                margin: 4px 4px 0 0;
    11001104        }
     
    21102114
    21112115/* TODO: DFW responsive */
     2116
     2117/* DFW 2
     2118-------------------------------------------------------------- */
     2119
     2120.focus-on .wrap > h2,
     2121.focus-on #wpfooter,
     2122.focus-on .postbox-container,
     2123.focus-on div.updated,
     2124.focus-on div.error,
     2125.focus-on #wp-toolbar {
     2126        opacity: 0;
     2127        -webkit-transition-duration: 0.6s;
     2128        transition-duration: 0.6s;
     2129        -webkit-transition-property: opacity;
     2130        transition-property: opacity;
     2131        -webkit-transition-timing-function: ease-in-out;
     2132        transition-timing-function: ease-in-out;
     2133}
     2134
     2135.focus-on #wp-toolbar {
     2136        opacity: 0.3;
     2137}
     2138
     2139.focus-off .wrap > h2,
     2140.focus-off #wpfooter,
     2141.focus-off .postbox-container,
     2142.focus-off div.updated,
     2143.focus-off div.error,
     2144.focus-off #wp-toolbar {
     2145        opacity: 1;
     2146        -webkit-transition-duration: 0.2s;
     2147        transition-duration: 0.2s;
     2148        -webkit-transition-property: opacity;
     2149        transition-property: opacity;
     2150        -webkit-transition-timing-function: ease-in-out;
     2151        transition-timing-function: ease-in-out;
     2152}
     2153
     2154.focus-on #adminmenuback,
     2155.focus-on #adminmenuwrap,
     2156.focus-on .screen-meta-toggle {
     2157        -webkit-transition-duration: 0.6s;
     2158        transition-duration: 0.6s;
     2159        -webkit-transition-property: -webkit-transform;
     2160        transition-property: transform;
     2161        -webkit-transition-timing-function: ease-in-out;
     2162        transition-timing-function: ease-in-out;
     2163}
     2164
     2165.focus-on #adminmenuback,
     2166.focus-on #adminmenuwrap {
     2167        -webkit-transform: translateX( -100% );
     2168        -ms-transform: translateX( -100% );
     2169        transform: translateX( -100% );
     2170}
     2171
     2172.focus-on .screen-meta-toggle {
     2173        -webkit-transform: translateY( -100% );
     2174        -ms-transform: translateY( -100% );
     2175        transform: translateY( -100% );
     2176}
     2177
     2178.focus-off #adminmenuback,
     2179.focus-off #adminmenuwrap,
     2180.focus-off .screen-meta-toggle {
     2181        -webkit-transform: translateX( 0 );
     2182        -ms-transform: translateX( 0 );
     2183        transform: translateX( 0 );
     2184        -webkit-transition-duration: 0.2s;
     2185        transition-duration: 0.2s;
     2186        -webkit-transition-property: -webkit-transform;
     2187        transition-property: transform;
     2188        -webkit-transition-timing-function: ease-in-out;
     2189        transition-timing-function: ease-in-out;
     2190}
  • trunk/src/wp-includes/js/quicktags.js

    r29889 r30338  
    289289                        }
    290290
     291                        if ( use && use.indexOf(',dfw,') !== -1 ) {
     292                                theButtons.dfw = new qt.DFWButton();
     293                                html += theButtons.dfw.html( name + '_' );
     294                        }
    291295
    292296                        if ( 'rtl' === document.getElementsByTagName('html')[0].dir ) {
     
    297301                        ed.toolbar.innerHTML = html;
    298302                        ed.theButtons = theButtons;
     303
     304                        window.jQuery && window.jQuery( document ).trigger( 'quicktags-init', [ ed ] );
    299305                }
    300306                t.buttonsInitDone = true;
     
    406412        };
    407413        qt.Button.prototype.html = function(idPrefix) {
    408                 var title = this.title ? ' title="' + this.title + '"' : '';
     414                var title = this.title ? ' title="' + this.title + '"' : '',
     415                        active, on, wp,
     416                        dfw = ( wp = window.wp ) && wp.editor && wp.editor.dfw;
    409417
    410418                if ( this.id === 'fullscreen' ) {
    411                         return '<button type="button" id="' + idPrefix + this.id + '" class="ed_button qt-fullscreen"' + title + '></button>';
    412                 }
     419                        return '<button type="button" id="' + idPrefix + this.id + '" class="ed_button qt-dfw"' + title + '></button>';
     420                } else if ( this.id === 'dfw' ) {
     421                        active = dfw && dfw.isActive() ? '' : ' disabled="disabled"';
     422                        on = dfw && dfw.isOn() ? ' active' : '';
     423
     424                        return '<button type="button" id="' + idPrefix + this.id + '" class="ed_button qt-dfw' + on + '"' + title + active + '></button>';
     425                }
     426
    413427                return '<input type="button" id="' + idPrefix + this.id + '" class="ed_button button button-small"' + title + ' value="' + this.display + '" />';
    414428        };
     
    620634        };
    621635
     636        qt.DFWButton = function() {
     637                qt.Button.call( this, 'dfw', '', 'f', quicktagsL10n.dfw );
     638        };
     639        qt.DFWButton.prototype = new qt.Button();
     640        qt.DFWButton.prototype.callback = function() {
     641                var wp;
     642
     643                if ( ! ( wp = window.wp ) || ! wp.editor || ! wp.editor.dfw ) {
     644                        return;
     645                }
     646
     647                window.wp.editor.dfw.toggle();
     648        };
     649
    622650        qt.TextDirectionButton = function() {
    623651                qt.Button.call(this, 'textdirection', quicktagsL10n.textdirection, '', quicktagsL10n.toggleTextdirection);
  • trunk/src/wp-includes/js/tinymce/plugins/wordpress/plugin.js

    r29317 r30338  
    77        var DOM = tinymce.DOM, wpAdvButton, modKey, style,
    88                last = 0;
     9
     10        if ( typeof window.jQuery !== 'undefined' ) {
     11                window.jQuery( document ).triggerHandler( 'tinymce-editor-setup', [ editor ] );
     12        }
    913
    1014        function toggleToolbars( state ) {
  • trunk/src/wp-includes/js/tinymce/plugins/wpautoresize/plugin.js

    r29628 r30338  
    118118                        }
    119119
    120                         editor.fire( 'wp-autoresize', { height: resizeHeight } );
     120                        editor.fire( 'wp-autoresize', { height: resizeHeight, deltaHeight: e.type === 'nodechange' ? deltaSize : null } );
    121121                }
    122122        }
  • trunk/src/wp-includes/js/tinymce/plugins/wpfullscreen/plugin.js

    r29049 r30338  
    6666                shortcut: 'Alt+Shift+W',
    6767                onclick: toggleFullscreen,
    68                 classes: 'wp-fullscreen btn widget' // This overwrites all classes on the container!
     68                classes: 'wp-dfw btn widget' // This overwrites all classes on the container!
    6969        });
    7070
  • trunk/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css

    r29986 r30338  
    1717        margin: 9px 10px;
    1818        max-width: 100%;
     19        -webkit-font-smoothing: antialiased !important;
    1920}
    2021
  • trunk/src/wp-includes/script-loader.php

    r29989 r30338  
    9595                'toggleFullscreen'      => esc_attr__( 'Toggle fullscreen mode' ),
    9696                'textdirection'         => esc_attr__( 'text direction' ),
    97                 'toggleTextdirection'   => esc_attr__( 'Toggle Editor Text Direction' )
     97                'toggleTextdirection'   => esc_attr__( 'Toggle Editor Text Direction' ),
     98                'dfw'                   => esc_attr__( 'Distraction Free Writing' )
    9899        ) );
    99100
  • trunk/src/wp-includes/version.php

    r30134 r30338  
    1919 * @global string $tinymce_version
    2020 */
    21 $tinymce_version = '4106-20141022';
     21$tinymce_version = '4106-20141113';
    2222
    2323/**
Note: See TracChangeset for help on using the changeset viewer.