[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-admin/js/ -> editor-expand.js (source)

   1  /**
   2   * @output wp-admin/js/editor-expand.js
   3   */
   4  
   5  ( function( window, $, undefined ) {
   6      'use strict';
   7  
   8      var $window = $( window ),
   9          $document = $( document ),
  10          $adminBar = $( '#wpadminbar' ),
  11          $footer = $( '#wpfooter' );
  12  
  13      /**
  14       * Handles the resizing of the editor.
  15       *
  16       * @since 4.0.0
  17       *
  18       * @returns {void}
  19       */
  20      $( function() {
  21          var $wrap = $( '#postdivrich' ),
  22              $contentWrap = $( '#wp-content-wrap' ),
  23              $tools = $( '#wp-content-editor-tools' ),
  24              $visualTop = $(),
  25              $visualEditor = $(),
  26              $textTop = $( '#ed_toolbar' ),
  27              $textEditor = $( '#content' ),
  28              textEditor = $textEditor[0],
  29              oldTextLength = 0,
  30              $bottom = $( '#post-status-info' ),
  31              $menuBar = $(),
  32              $statusBar = $(),
  33              $sideSortables = $( '#side-sortables' ),
  34              $postboxContainer = $( '#postbox-container-1' ),
  35              $postBody = $('#post-body'),
  36              fullscreen = window.wp.editor && window.wp.editor.fullscreen,
  37              mceEditor,
  38              mceBind = function(){},
  39              mceUnbind = function(){},
  40              fixedTop = false,
  41              fixedBottom = false,
  42              fixedSideTop = false,
  43              fixedSideBottom = false,
  44              scrollTimer,
  45              lastScrollPosition = 0,
  46              pageYOffsetAtTop = 130,
  47              pinnedToolsTop = 56,
  48              sidebarBottom = 20,
  49              autoresizeMinHeight = 300,
  50              initialMode = $contentWrap.hasClass( 'tmce-active' ) ? 'tinymce' : 'html',
  51              advanced = !! parseInt( window.getUserSetting( 'hidetb' ), 10 ),
  52              // These are corrected when adjust() runs, except on scrolling if already set.
  53              heights = {
  54                  windowHeight: 0,
  55                  windowWidth: 0,
  56                  adminBarHeight: 0,
  57                  toolsHeight: 0,
  58                  menuBarHeight: 0,
  59                  visualTopHeight: 0,
  60                  textTopHeight: 0,
  61                  bottomHeight: 0,
  62                  statusBarHeight: 0,
  63                  sideSortablesHeight: 0
  64              };
  65  
  66          /**
  67           * Resizes textarea based on scroll height and width.
  68           *
  69           * Doesn't shrink the editor size below the 300px auto resize minimum height.
  70           *
  71           * @since 4.6.1
  72           *
  73           * @returns {void}
  74           */
  75          var shrinkTextarea = window._.throttle( function() {
  76              var x = window.scrollX || document.documentElement.scrollLeft;
  77              var y = window.scrollY || document.documentElement.scrollTop;
  78              var height = parseInt( textEditor.style.height, 10 );
  79  
  80              textEditor.style.height = autoresizeMinHeight + 'px';
  81  
  82              if ( textEditor.scrollHeight > autoresizeMinHeight ) {
  83                  textEditor.style.height = textEditor.scrollHeight + 'px';
  84              }
  85  
  86              if ( typeof x !== 'undefined' ) {
  87                  window.scrollTo( x, y );
  88              }
  89  
  90              if ( textEditor.scrollHeight < height ) {
  91                  adjust();
  92              }
  93          }, 300 );
  94  
  95          /**
  96           * Resizes the text editor depending on the old text length.
  97           *
  98           * If there is an mceEditor and it is hidden, it resizes the editor depending
  99           * on the old text length. If the current length of the text is smaller than
 100           * the old text length, it shrinks the text area. Otherwise it resizes the editor to
 101           * the scroll height.
 102           *
 103           * @since 4.6.1
 104           *
 105           * @returns {void}
 106           */
 107  		function textEditorResize() {
 108              var length = textEditor.value.length;
 109  
 110              if ( mceEditor && ! mceEditor.isHidden() ) {
 111                  return;
 112              }
 113  
 114              if ( ! mceEditor && initialMode === 'tinymce' ) {
 115                  return;
 116              }
 117  
 118              if ( length < oldTextLength ) {
 119                  shrinkTextarea();
 120              } else if ( parseInt( textEditor.style.height, 10 ) < textEditor.scrollHeight ) {
 121                  textEditor.style.height = Math.ceil( textEditor.scrollHeight ) + 'px';
 122                  adjust();
 123              }
 124  
 125              oldTextLength = length;
 126          }
 127  
 128          /**
 129           * Gets the height and widths of elements.
 130           *
 131           * Gets the heights of the window, the adminbar, the tools, the menu,
 132           * the visualTop, the textTop, the bottom, the statusbar and sideSortables
 133           * and stores these in the heights object. Defaults to 0.
 134           * Gets the width of the window and stores this in the heights object.
 135           *
 136           * @since 4.0.0
 137           *
 138           * @returns {void}
 139           */
 140  		function getHeights() {
 141              var windowWidth = $window.width();
 142  
 143              heights = {
 144                  windowHeight: $window.height(),
 145                  windowWidth: windowWidth,
 146                  adminBarHeight: ( windowWidth > 600 ? $adminBar.outerHeight() : 0 ),
 147                  toolsHeight: $tools.outerHeight() || 0,
 148                  menuBarHeight: $menuBar.outerHeight() || 0,
 149                  visualTopHeight: $visualTop.outerHeight() || 0,
 150                  textTopHeight: $textTop.outerHeight() || 0,
 151                  bottomHeight: $bottom.outerHeight() || 0,
 152                  statusBarHeight: $statusBar.outerHeight() || 0,
 153                  sideSortablesHeight: $sideSortables.height() || 0
 154              };
 155  
 156              // Adjust for hidden menubar.
 157              if ( heights.menuBarHeight < 3 ) {
 158                  heights.menuBarHeight = 0;
 159              }
 160          }
 161  
 162          // We need to wait for TinyMCE to initialize.
 163          /**
 164           * Binds all necessary functions for editor expand to the editor when the editor
 165           * is initialized.
 166           *
 167           * @since 4.0.0
 168           *
 169           * @param {event} event The TinyMCE editor init event.
 170           * @param {object} editor The editor to bind the vents on.
 171           *
 172           * @returns {void}
 173           */
 174          $document.on( 'tinymce-editor-init.editor-expand', function( event, editor ) {
 175              // VK contains the type of key pressed. VK = virtual keyboard.
 176              var VK = window.tinymce.util.VK,
 177                  /**
 178                   * Hides any float panel with a hover state. Additionally hides tooltips.
 179                   *
 180                   * @returns {void}
 181                   */
 182                  hideFloatPanels = _.debounce( function() {
 183                      ! $( '.mce-floatpanel:hover' ).length && window.tinymce.ui.FloatPanel.hideAll();
 184                      $( '.mce-tooltip' ).hide();
 185                  }, 1000, true );
 186  
 187              // Make sure it's the main editor.
 188              if ( editor.id !== 'content' ) {
 189                  return;
 190              }
 191  
 192              // Copy the editor instance.
 193              mceEditor = editor;
 194  
 195              // Set the minimum height to the initial viewport height.
 196              editor.settings.autoresize_min_height = autoresizeMinHeight;
 197  
 198              // Get the necessary UI elements.
 199              $visualTop = $contentWrap.find( '.mce-toolbar-grp' );
 200              $visualEditor = $contentWrap.find( '.mce-edit-area' );
 201              $statusBar = $contentWrap.find( '.mce-statusbar' );
 202              $menuBar = $contentWrap.find( '.mce-menubar' );
 203  
 204              /**
 205               * Gets the offset of the editor.
 206               *
 207               * @returns {Number|Boolean} Returns the offset of the editor
 208               * or false if there is no offset height.
 209               */
 210  			function mceGetCursorOffset() {
 211                  var node = editor.selection.getNode(),
 212                      range, view, offset;
 213  
 214                  /*
 215                   * If editor.wp.getView and the selection node from the editor selection
 216                   * are defined, use this as a view for the offset.
 217                   */
 218                  if ( editor.wp && editor.wp.getView && ( view = editor.wp.getView( node ) ) ) {
 219                      offset = view.getBoundingClientRect();
 220                  } else {
 221                      range = editor.selection.getRng();
 222  
 223                      // Try to get the offset from a range.
 224                      try {
 225                          offset = range.getClientRects()[0];
 226                      } catch( er ) {}
 227  
 228                      // Get the offset from the bounding client rectangle of the node.
 229                      if ( ! offset ) {
 230                          offset = node.getBoundingClientRect();
 231                      }
 232                  }
 233  
 234                  return offset.height ? offset : false;
 235              }
 236  
 237              /**
 238               * Filters the special keys that should not be used for scrolling.
 239               *
 240               * @since 4.0.0
 241               *
 242               * @param {event} event The event to get the key code from.
 243               *
 244               * @returns {void}
 245               */
 246  			function mceKeyup( event ) {
 247                  var key = event.keyCode;
 248  
 249                  // Bail on special keys. Key code 47 is a /
 250                  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 ) ) {
 251                      return;
 252                  // OS keys, function keys, num lock, scroll lock. Key code 91-93 are OS keys. Key code 112-123 are F1 to F12. Key code 144 is num lock. Key code 145 is scroll lock.
 253                  } else if ( ( key >= 91 && key <= 93 ) || ( key >= 112 && key <= 123 ) || key === 144 || key === 145 ) {
 254                      return;
 255                  }
 256  
 257                  mceScroll( key );
 258              }
 259  
 260              /**
 261               * Makes sure the cursor is always visible in the editor.
 262               *
 263               * Makes sure the cursor is kept between the toolbars of the editor and scrolls
 264               * the window when the cursor moves out of the viewport to a wpview.
 265               * Setting a buffer > 0 will prevent the browser default.
 266               * Some browsers will scroll to the middle,
 267               * others to the top/bottom of the *window* when moving the cursor out of the viewport.
 268               *
 269               * @since 4.1.0
 270               *
 271               * @param {string} key The key code of the pressed key.
 272               *
 273               * @returns {void}
 274               */
 275  			function mceScroll( key ) {
 276                  var offset = mceGetCursorOffset(),
 277                      buffer = 50,
 278                      cursorTop, cursorBottom, editorTop, editorBottom;
 279  
 280                  // Don't scroll if there is no offset.
 281                  if ( ! offset ) {
 282                      return;
 283                  }
 284  
 285                  // Determine the cursorTop based on the offset and the top of the editor iframe.
 286                  cursorTop = offset.top + editor.iframeElement.getBoundingClientRect().top;
 287  
 288                  // Determine the cursorBottom based on the cursorTop and offset height.
 289                  cursorBottom = cursorTop + offset.height;
 290  
 291                  // Subtract the buffer from the cursorTop.
 292                  cursorTop = cursorTop - buffer;
 293  
 294                  // Add the buffer to the cursorBottom.
 295                  cursorBottom = cursorBottom + buffer;
 296                  editorTop = heights.adminBarHeight + heights.toolsHeight + heights.menuBarHeight + heights.visualTopHeight;
 297  
 298                  /*
 299                   * Set the editorBottom based on the window Height, and add the bottomHeight and statusBarHeight if the
 300                   * advanced editor is enabled.
 301                   */
 302                  editorBottom = heights.windowHeight - ( advanced ? heights.bottomHeight + heights.statusBarHeight : 0 );
 303  
 304                  // Don't scroll if the node is taller than the visible part of the editor.
 305                  if ( editorBottom - editorTop < offset.height ) {
 306                      return;
 307                  }
 308  
 309                  /*
 310                   * If the cursorTop is smaller than the editorTop and the up, left
 311                   * or backspace key is pressed, scroll the editor to the position defined
 312                   * by the cursorTop, pageYOffset and editorTop.
 313                   */
 314                  if ( cursorTop < editorTop && ( key === VK.UP || key === VK.LEFT || key === VK.BACKSPACE ) ) {
 315                      window.scrollTo( window.pageXOffset, cursorTop + window.pageYOffset - editorTop );
 316  
 317                  /*
 318                   * If any other key is pressed or the cursorTop is bigger than the editorTop,
 319                   * scroll the editor to the position defined by the cursorBottom,
 320                   * pageYOffset and editorBottom.
 321                   */
 322                  } else if ( cursorBottom > editorBottom ) {
 323                      window.scrollTo( window.pageXOffset, cursorBottom + window.pageYOffset - editorBottom );
 324                  }
 325              }
 326  
 327              /**
 328               * If the editor is fullscreen, calls adjust.
 329               *
 330               * @since 4.1.0
 331               *
 332               * @param {event} event The FullscreenStateChanged event.
 333               *
 334               * @returns {void}
 335               */
 336  			function mceFullscreenToggled( event ) {
 337                  // event.state is true if the editor is fullscreen.
 338                  if ( ! event.state ) {
 339                      adjust();
 340                  }
 341              }
 342  
 343              /**
 344               * Shows the editor when scrolled.
 345               *
 346               * Binds the hideFloatPanels function on the window scroll.mce-float-panels event.
 347               * Executes the wpAutoResize on the active editor.
 348               *
 349               * @since 4.0.0
 350               *
 351               * @returns {void}
 352               */
 353  			function mceShow() {
 354                  $window.on( 'scroll.mce-float-panels', hideFloatPanels );
 355  
 356                  setTimeout( function() {
 357                      editor.execCommand( 'wpAutoResize' );
 358                      adjust();
 359                  }, 300 );
 360              }
 361  
 362              /**
 363               * Resizes the editor.
 364               *
 365               * Removes all functions from the window scroll.mce-float-panels event.
 366               * Resizes the text editor and scrolls to a position based on the pageXOffset and adminBarHeight.
 367               *
 368               * @since 4.0.0
 369               *
 370               * @returns {void}
 371               */
 372  			function mceHide() {
 373                  $window.off( 'scroll.mce-float-panels' );
 374  
 375                  setTimeout( function() {
 376                      var top = $contentWrap.offset().top;
 377  
 378                      if ( window.pageYOffset > top ) {
 379                          window.scrollTo( window.pageXOffset, top - heights.adminBarHeight );
 380                      }
 381  
 382                      textEditorResize();
 383                      adjust();
 384                  }, 100 );
 385  
 386                  adjust();
 387              }
 388  
 389              /**
 390               * Toggles advanced states.
 391               *
 392               * @since 4.1.0
 393               *
 394               * @returns {void}
 395               */
 396  			function toggleAdvanced() {
 397                  advanced = ! advanced;
 398              }
 399  
 400              /**
 401               * Binds events of the editor and window.
 402               *
 403               * @since 4.0.0
 404               *
 405               * @returns {void}
 406               */
 407              mceBind = function() {
 408                  editor.on( 'keyup', mceKeyup );
 409                  editor.on( 'show', mceShow );
 410                  editor.on( 'hide', mceHide );
 411                  editor.on( 'wp-toolbar-toggle', toggleAdvanced );
 412  
 413                  // Adjust when the editor resizes.
 414                  editor.on( 'setcontent wp-autoresize wp-toolbar-toggle', adjust );
 415  
 416                  // Don't hide the caret after undo/redo.
 417                  editor.on( 'undo redo', mceScroll );
 418  
 419                  // Adjust when exiting TinyMCE's fullscreen mode.
 420                  editor.on( 'FullscreenStateChanged', mceFullscreenToggled );
 421  
 422                  $window.off( 'scroll.mce-float-panels' ).on( 'scroll.mce-float-panels', hideFloatPanels );
 423              };
 424  
 425              /**
 426               * Unbinds the events of the editor and window.
 427               *
 428               * @since 4.0.0
 429               *
 430               * @returns {void}
 431               */
 432              mceUnbind = function() {
 433                  editor.off( 'keyup', mceKeyup );
 434                  editor.off( 'show', mceShow );
 435                  editor.off( 'hide', mceHide );
 436                  editor.off( 'wp-toolbar-toggle', toggleAdvanced );
 437                  editor.off( 'setcontent wp-autoresize wp-toolbar-toggle', adjust );
 438                  editor.off( 'undo redo', mceScroll );
 439                  editor.off( 'FullscreenStateChanged', mceFullscreenToggled );
 440  
 441                  $window.off( 'scroll.mce-float-panels' );
 442              };
 443  
 444              if ( $wrap.hasClass( 'wp-editor-expand' ) ) {
 445  
 446                  // Adjust "immediately".
 447                  mceBind();
 448                  initialResize( adjust );
 449              }
 450          } );
 451  
 452          /**
 453           * Adjusts the toolbars heights and positions.
 454           *
 455           * Adjusts the toolbars heights and positions based on the scroll position on
 456           * the page, the active editor mode and the heights of the editor, admin bar and
 457           * side bar.
 458           *
 459           * @since 4.0.0
 460           *
 461           * @param {event} event The event that calls this function.
 462           *
 463           * @returns {void}
 464           */
 465  		function adjust( event ) {
 466  
 467              // Makes sure we're not in fullscreen mode.
 468              if ( fullscreen && fullscreen.settings.visible ) {
 469                  return;
 470              }
 471  
 472              var windowPos = $window.scrollTop(),
 473                  type = event && event.type,
 474                  resize = type !== 'scroll',
 475                  visual = mceEditor && ! mceEditor.isHidden(),
 476                  buffer = autoresizeMinHeight,
 477                  postBodyTop = $postBody.offset().top,
 478                  borderWidth = 1,
 479                  contentWrapWidth = $contentWrap.width(),
 480                  $top, $editor, sidebarTop, footerTop, canPin,
 481                  topPos, topHeight, editorPos, editorHeight;
 482  
 483              /*
 484               * Refresh the heights if type isn't 'scroll'
 485               * or heights.windowHeight isn't set.
 486               */
 487              if ( resize || ! heights.windowHeight ) {
 488                  getHeights();
 489              }
 490  
 491              // Resize on resize event when the editor is in text mode.
 492              if ( ! visual && type === 'resize' ) {
 493                  textEditorResize();
 494              }
 495  
 496              if ( visual ) {
 497                  $top = $visualTop;
 498                  $editor = $visualEditor;
 499                  topHeight = heights.visualTopHeight;
 500              } else {
 501                  $top = $textTop;
 502                  $editor = $textEditor;
 503                  topHeight = heights.textTopHeight;
 504              }
 505  
 506              // Return if TinyMCE is still initializing.
 507              if ( ! visual && ! $top.length ) {
 508                  return;
 509              }
 510  
 511              topPos = $top.parent().offset().top;
 512              editorPos = $editor.offset().top;
 513              editorHeight = $editor.outerHeight();
 514  
 515              /*
 516               * If in visual mode, checks if the editorHeight is greater than the autoresizeMinHeight + topHeight.
 517               * If not in visual mode, checks if the editorHeight is greater than the autoresizeMinHeight + 20.
 518               */
 519              canPin = visual ? autoresizeMinHeight + topHeight : autoresizeMinHeight + 20; // 20px from textarea padding
 520              canPin = editorHeight > ( canPin + 5 );
 521  
 522              if ( ! canPin ) {
 523                  if ( resize ) {
 524                      $tools.css( {
 525                          position: 'absolute',
 526                          top: 0,
 527                          width: contentWrapWidth
 528                      } );
 529  
 530                      if ( visual && $menuBar.length ) {
 531                          $menuBar.css( {
 532                              position: 'absolute',
 533                              top: 0,
 534                              width: contentWrapWidth - ( borderWidth * 2 )
 535                          } );
 536                      }
 537  
 538                      $top.css( {
 539                          position: 'absolute',
 540                          top: heights.menuBarHeight,
 541                          width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
 542                      } );
 543  
 544                      $statusBar.attr( 'style', advanced ? '' : 'visibility: hidden;' );
 545                      $bottom.attr( 'style', '' );
 546                  }
 547              } else {
 548                  // Check if the top is not already in a fixed position.
 549                  if ( ( ! fixedTop || resize ) &&
 550                      ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight ) &&
 551                      windowPos <= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) ) {
 552                      fixedTop = true;
 553  
 554                      $tools.css( {
 555                          position: 'fixed',
 556                          top: heights.adminBarHeight,
 557                          width: contentWrapWidth
 558                      } );
 559  
 560                      if ( visual && $menuBar.length ) {
 561                          $menuBar.css( {
 562                              position: 'fixed',
 563                              top: heights.adminBarHeight + heights.toolsHeight,
 564                              width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
 565                          } );
 566                      }
 567  
 568                      $top.css( {
 569                          position: 'fixed',
 570                          top: heights.adminBarHeight + heights.toolsHeight + heights.menuBarHeight,
 571                          width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
 572                      } );
 573                      // Check if the top is already in a fixed position.
 574                  } else if ( fixedTop || resize ) {
 575                      if ( windowPos <= ( topPos - heights.toolsHeight - heights.adminBarHeight ) ) {
 576                          fixedTop = false;
 577  
 578                          $tools.css( {
 579                              position: 'absolute',
 580                              top: 0,
 581                              width: contentWrapWidth
 582                          } );
 583  
 584                          if ( visual && $menuBar.length ) {
 585                              $menuBar.css( {
 586                                  position: 'absolute',
 587                                  top: 0,
 588                                  width: contentWrapWidth - ( borderWidth * 2 )
 589                              } );
 590                          }
 591  
 592                          $top.css( {
 593                              position: 'absolute',
 594                              top: heights.menuBarHeight,
 595                              width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
 596                          } );
 597                      } else if ( windowPos >= ( topPos - heights.toolsHeight - heights.adminBarHeight + editorHeight - buffer ) ) {
 598                          fixedTop = false;
 599  
 600                          $tools.css( {
 601                              position: 'absolute',
 602                              top: editorHeight - buffer,
 603                              width: contentWrapWidth
 604                          } );
 605  
 606                          if ( visual && $menuBar.length ) {
 607                              $menuBar.css( {
 608                                  position: 'absolute',
 609                                  top: editorHeight - buffer,
 610                                  width: contentWrapWidth - ( borderWidth * 2 )
 611                              } );
 612                          }
 613  
 614                          $top.css( {
 615                              position: 'absolute',
 616                              top: editorHeight - buffer + heights.menuBarHeight,
 617                              width: contentWrapWidth - ( borderWidth * 2 ) - ( visual ? 0 : ( $top.outerWidth() - $top.width() ) )
 618                          } );
 619                      }
 620                  }
 621  
 622                  // Check if the bottom is not already in a fixed position.
 623                  if ( ( ! fixedBottom || ( resize && advanced ) ) &&
 624                          // Add borderWidth for the border around the .wp-editor-container.
 625                          ( windowPos + heights.windowHeight ) <= ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight + borderWidth ) ) {
 626  
 627                      if ( event && event.deltaHeight > 0 && event.deltaHeight < 100 ) {
 628                          window.scrollBy( 0, event.deltaHeight );
 629                      } else if ( visual && advanced ) {
 630                          fixedBottom = true;
 631  
 632                          $statusBar.css( {
 633                              position: 'fixed',
 634                              bottom: heights.bottomHeight,
 635                              visibility: '',
 636                              width: contentWrapWidth - ( borderWidth * 2 )
 637                          } );
 638  
 639                          $bottom.css( {
 640                              position: 'fixed',
 641                              bottom: 0,
 642                              width: contentWrapWidth
 643                          } );
 644                      }
 645                  } else if ( ( ! advanced && fixedBottom ) ||
 646                          ( ( fixedBottom || resize ) &&
 647                          ( windowPos + heights.windowHeight ) > ( editorPos + editorHeight + heights.bottomHeight + heights.statusBarHeight - borderWidth ) ) ) {
 648                      fixedBottom = false;
 649  
 650                      $statusBar.attr( 'style', advanced ? '' : 'visibility: hidden;' );
 651                      $bottom.attr( 'style', '' );
 652                  }
 653              }
 654  
 655              // The postbox container is positioned with @media from CSS. Ensure it is pinned on the side.
 656              if ( $postboxContainer.width() < 300 && heights.windowWidth > 600 &&
 657  
 658                  // Check if the sidebar is not taller than the document height.
 659                  $document.height() > ( $sideSortables.height() + postBodyTop + 120 ) &&
 660  
 661                  // Check if the editor is taller than the viewport.
 662                  heights.windowHeight < editorHeight ) {
 663  
 664                  if ( ( heights.sideSortablesHeight + pinnedToolsTop + sidebarBottom ) > heights.windowHeight || fixedSideTop || fixedSideBottom ) {
 665  
 666                      // Reset the sideSortables style when scrolling to the top.
 667                      if ( windowPos + pinnedToolsTop <= postBodyTop ) {
 668                          $sideSortables.attr( 'style', '' );
 669                          fixedSideTop = fixedSideBottom = false;
 670                      } else {
 671  
 672                          // When scrolling down.
 673                          if ( windowPos > lastScrollPosition ) {
 674                              if ( fixedSideTop ) {
 675  
 676                                  // Let it scroll.
 677                                  fixedSideTop = false;
 678                                  sidebarTop = $sideSortables.offset().top - heights.adminBarHeight;
 679                                  footerTop = $footer.offset().top;
 680  
 681                                  // Don't get over the footer.
 682                                  if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) {
 683                                      sidebarTop = footerTop - heights.sideSortablesHeight - 12;
 684                                  }
 685  
 686                                  $sideSortables.css({
 687                                      position: 'absolute',
 688                                      top: sidebarTop,
 689                                      bottom: ''
 690                                  });
 691                              } else if ( ! fixedSideBottom && heights.sideSortablesHeight + $sideSortables.offset().top + sidebarBottom < windowPos + heights.windowHeight ) {
 692                                  // Pin the bottom.
 693                                  fixedSideBottom = true;
 694  
 695                                  $sideSortables.css({
 696                                      position: 'fixed',
 697                                      top: 'auto',
 698                                      bottom: sidebarBottom
 699                                  });
 700                              }
 701  
 702                          // When scrolling up.
 703                          } else if ( windowPos < lastScrollPosition ) {
 704                              if ( fixedSideBottom ) {
 705                                  // Let it scroll.
 706                                  fixedSideBottom = false;
 707                                  sidebarTop = $sideSortables.offset().top - sidebarBottom;
 708                                  footerTop = $footer.offset().top;
 709  
 710                                  // Don't get over the footer.
 711                                  if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) {
 712                                      sidebarTop = footerTop - heights.sideSortablesHeight - 12;
 713                                  }
 714  
 715                                  $sideSortables.css({
 716                                      position: 'absolute',
 717                                      top: sidebarTop,
 718                                      bottom: ''
 719                                  });
 720                              } else if ( ! fixedSideTop && $sideSortables.offset().top >= windowPos + pinnedToolsTop ) {
 721                                  // Pin the top.
 722                                  fixedSideTop = true;
 723  
 724                                  $sideSortables.css({
 725                                      position: 'fixed',
 726                                      top: pinnedToolsTop,
 727                                      bottom: ''
 728                                  });
 729                              }
 730                          }
 731                      }
 732                  } else {
 733                      // If the sidebar container is smaller than the viewport, then pin/unpin the top when scrolling.
 734                      if ( windowPos >= ( postBodyTop - pinnedToolsTop ) ) {
 735  
 736                          $sideSortables.css( {
 737                              position: 'fixed',
 738                              top: pinnedToolsTop
 739                          } );
 740                      } else {
 741                          $sideSortables.attr( 'style', '' );
 742                      }
 743  
 744                      fixedSideTop = fixedSideBottom = false;
 745                  }
 746  
 747                  lastScrollPosition = windowPos;
 748              } else {
 749                  $sideSortables.attr( 'style', '' );
 750                  fixedSideTop = fixedSideBottom = false;
 751              }
 752  
 753              if ( resize ) {
 754                  $contentWrap.css( {
 755                      paddingTop: heights.toolsHeight
 756                  } );
 757  
 758                  if ( visual ) {
 759                      $visualEditor.css( {
 760                          paddingTop: heights.visualTopHeight + heights.menuBarHeight
 761                      } );
 762                  } else {
 763                      $textEditor.css( {
 764                          marginTop: heights.textTopHeight
 765                      } );
 766                  }
 767              }
 768          }
 769  
 770          /**
 771           * Resizes the editor and adjusts the toolbars.
 772           *
 773           * @since 4.0.0
 774           *
 775           * @returns {void}
 776           */
 777  		function fullscreenHide() {
 778              textEditorResize();
 779              adjust();
 780          }
 781  
 782          /**
 783           * Runs the passed function with 500ms intervals.
 784           *
 785           * @since 4.0.0
 786           *
 787           * @param {function} callback The function to run in the timeout.
 788           *
 789           * @returns {void}
 790           */
 791  		function initialResize( callback ) {
 792              for ( var i = 1; i < 6; i++ ) {
 793                  setTimeout( callback, 500 * i );
 794              }
 795          }
 796  
 797          /**
 798           * Runs adjust after 100ms.
 799           *
 800           * @since 4.0.0
 801           *
 802           * @returns {void}
 803           */
 804  		function afterScroll() {
 805              clearTimeout( scrollTimer );
 806              scrollTimer = setTimeout( adjust, 100 );
 807          }
 808  
 809          /**
 810           * Binds editor expand events on elements.
 811           *
 812           * @since 4.0.0
 813           *
 814           * @returns {void}
 815           */
 816          function on() {
 817              /*
 818               * Scroll to the top when triggering this from JS.
 819               * Ensure the toolbars are pinned properly.
 820               */
 821              if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) {
 822                  window.scrollTo( window.pageXOffset, 0 );
 823              }
 824  
 825              $wrap.addClass( 'wp-editor-expand' );
 826  
 827              // Adjust when the window is scrolled or resized.
 828              $window.on( 'scroll.editor-expand resize.editor-expand', function( event ) {
 829                  adjust( event.type );
 830                  afterScroll();
 831              } );
 832  
 833              /*
 834                * Adjust when collapsing the menu, changing the columns
 835                * or changing the body class.
 836               */
 837              $document.on( 'wp-collapse-menu.editor-expand postboxes-columnchange.editor-expand editor-classchange.editor-expand', adjust )
 838                  .on( 'postbox-toggled.editor-expand postbox-moved.editor-expand', function() {
 839                      if ( ! fixedSideTop && ! fixedSideBottom && window.pageYOffset > pinnedToolsTop ) {
 840                          fixedSideBottom = true;
 841                          window.scrollBy( 0, -1 );
 842                          adjust();
 843                          window.scrollBy( 0, 1 );
 844                      }
 845  
 846                      adjust();
 847                  }).on( 'wp-window-resized.editor-expand', function() {
 848                      if ( mceEditor && ! mceEditor.isHidden() ) {
 849                          mceEditor.execCommand( 'wpAutoResize' );
 850                      } else {
 851                          textEditorResize();
 852                      }
 853                  });
 854  
 855              $textEditor.on( 'focus.editor-expand input.editor-expand propertychange.editor-expand', textEditorResize );
 856              mceBind();
 857  
 858              // Adjust when entering or exiting fullscreen mode.
 859              fullscreen && fullscreen.pubsub.subscribe( 'hidden', fullscreenHide );
 860  
 861              if ( mceEditor ) {
 862                  mceEditor.settings.wp_autoresize_on = true;
 863                  mceEditor.execCommand( 'wpAutoResizeOn' );
 864  
 865                  if ( ! mceEditor.isHidden() ) {
 866                      mceEditor.execCommand( 'wpAutoResize' );
 867                  }
 868              }
 869  
 870              if ( ! mceEditor || mceEditor.isHidden() ) {
 871                  textEditorResize();
 872              }
 873  
 874              adjust();
 875  
 876              $document.trigger( 'editor-expand-on' );
 877          }
 878  
 879          /**
 880           * Unbinds editor expand events.
 881           *
 882           * @since 4.0.0
 883           *
 884           * @returns {void}
 885           */
 886  		function off() {
 887              var height = parseInt( window.getUserSetting( 'ed_size', 300 ), 10 );
 888  
 889              if ( height < 50 ) {
 890                  height = 50;
 891              } else if ( height > 5000 ) {
 892                  height = 5000;
 893              }
 894  
 895              /*
 896               * Scroll to the top when triggering this from JS.
 897               * Ensure the toolbars are reset properly.
 898               */
 899              if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) {
 900                  window.scrollTo( window.pageXOffset, 0 );
 901              }
 902  
 903              $wrap.removeClass( 'wp-editor-expand' );
 904  
 905              $window.off( '.editor-expand' );
 906              $document.off( '.editor-expand' );
 907              $textEditor.off( '.editor-expand' );
 908              mceUnbind();
 909  
 910              // Adjust when entering or exiting fullscreen mode.
 911              fullscreen && fullscreen.pubsub.unsubscribe( 'hidden', fullscreenHide );
 912  
 913              // Reset all css
 914              $.each( [ $visualTop, $textTop, $tools, $menuBar, $bottom, $statusBar, $contentWrap, $visualEditor, $textEditor, $sideSortables ], function( i, element ) {
 915                  element && element.attr( 'style', '' );
 916              });
 917  
 918              fixedTop = fixedBottom = fixedSideTop = fixedSideBottom = false;
 919  
 920              if ( mceEditor ) {
 921                  mceEditor.settings.wp_autoresize_on = false;
 922                  mceEditor.execCommand( 'wpAutoResizeOff' );
 923  
 924                  if ( ! mceEditor.isHidden() ) {
 925                      $textEditor.hide();
 926  
 927                      if ( height ) {
 928                          mceEditor.theme.resizeTo( null, height );
 929                      }
 930                  }
 931              }
 932  
 933              // If there is a height found in the user setting.
 934              if ( height ) {
 935                  $textEditor.height( height );
 936              }
 937  
 938              $document.trigger( 'editor-expand-off' );
 939          }
 940  
 941          // Start on load.
 942          if ( $wrap.hasClass( 'wp-editor-expand' ) ) {
 943              on();
 944  
 945              // Resize just after CSS has fully loaded and QuickTags is ready.
 946              if ( $contentWrap.hasClass( 'html-active' ) ) {
 947                  initialResize( function() {
 948                      adjust();
 949                      textEditorResize();
 950                  } );
 951              }
 952          }
 953  
 954          // Show the on/off checkbox.
 955          $( '#adv-settings .editor-expand' ).show();
 956          $( '#editor-expand-toggle' ).on( 'change.editor-expand', function() {
 957              if ( $(this).prop( 'checked' ) ) {
 958                  on();
 959                  window.setUserSetting( 'editor_expand', 'on' );
 960              } else {
 961                  off();
 962                  window.setUserSetting( 'editor_expand', 'off' );
 963              }
 964          });
 965  
 966          // Expose on() and off().
 967          window.editorExpand = {
 968              on: on,
 969              off: off
 970          };
 971      } );
 972  
 973      /**
 974       * Handles the distraction free writing of TinyMCE.
 975       *
 976       * @since 4.1.0
 977       *
 978       * @returns {void}
 979       */
 980      $( function() {
 981          var $body = $( document.body ),
 982              $wrap = $( '#wpcontent' ),
 983              $editor = $( '#post-body-content' ),
 984              $title = $( '#title' ),
 985              $content = $( '#content' ),
 986              $overlay = $( document.createElement( 'DIV' ) ),
 987              $slug = $( '#edit-slug-box' ),
 988              $slugFocusEl = $slug.find( 'a' )
 989                  .add( $slug.find( 'button' ) )
 990                  .add( $slug.find( 'input' ) ),
 991              $menuWrap = $( '#adminmenuwrap' ),
 992              $editorWindow = $(),
 993              $editorIframe = $(),
 994              _isActive = window.getUserSetting( 'editor_expand', 'on' ) === 'on',
 995              _isOn = _isActive ? window.getUserSetting( 'post_dfw' ) === 'on' : false,
 996              traveledX = 0,
 997              traveledY = 0,
 998              buffer = 20,
 999              faded, fadedAdminBar, fadedSlug,
1000              editorRect, x, y, mouseY, scrollY,
1001              focusLostTimer, overlayTimer, editorHasFocus;
1002  
1003          $body.append( $overlay );
1004  
1005          $overlay.css( {
1006              display: 'none',
1007              position: 'fixed',
1008              top: $adminBar.height(),
1009              right: 0,
1010              bottom: 0,
1011              left: 0,
1012              'z-index': 9997
1013          } );
1014  
1015          $editor.css( {
1016              position: 'relative'
1017          } );
1018  
1019          $window.on( 'mousemove.focus', function( event ) {
1020              mouseY = event.pageY;
1021          } );
1022  
1023          /**
1024           * Recalculates the bottom and right position of the editor in the DOM.
1025           *
1026           * @since 4.1.0
1027           *
1028           * @returns {void}
1029           */
1030  		function recalcEditorRect() {
1031              editorRect = $editor.offset();
1032              editorRect.right = editorRect.left + $editor.outerWidth();
1033              editorRect.bottom = editorRect.top + $editor.outerHeight();
1034          }
1035  
1036          /**
1037           * Activates the distraction free writing mode.
1038           *
1039           * @since 4.1.0
1040           *
1041           * @returns {void}
1042           */
1043  		function activate() {
1044              if ( ! _isActive ) {
1045                  _isActive = true;
1046  
1047                  $document.trigger( 'dfw-activate' );
1048                  $content.on( 'keydown.focus-shortcut', toggleViaKeyboard );
1049              }
1050          }
1051  
1052          /**
1053           * Deactivates the distraction free writing mode.
1054           *
1055           * @since 4.1.0
1056           *
1057           * @returns {void}
1058           */
1059  		function deactivate() {
1060              if ( _isActive ) {
1061                  off();
1062  
1063                  _isActive = false;
1064  
1065                  $document.trigger( 'dfw-deactivate' );
1066                  $content.off( 'keydown.focus-shortcut' );
1067              }
1068          }
1069  
1070          /**
1071           * Returns _isActive.
1072           *
1073           * @since 4.1.0
1074           *
1075           * @returns {boolean} Returns true is _isActive is true.
1076           */
1077  		function isActive() {
1078              return _isActive;
1079          }
1080  
1081          /**
1082           * Binds events on the editor for distraction free writing.
1083           *
1084           * @since 4.1.0
1085           *
1086           * @returns {void}
1087           */
1088          function on() {
1089              if ( ! _isOn && _isActive ) {
1090                  _isOn = true;
1091  
1092                  $content.on( 'keydown.focus', fadeOut );
1093  
1094                  $title.add( $content ).on( 'blur.focus', maybeFadeIn );
1095  
1096                  fadeOut();
1097  
1098                  window.setUserSetting( 'post_dfw', 'on' );
1099  
1100                  $document.trigger( 'dfw-on' );
1101              }
1102          }
1103  
1104          /**
1105           * Unbinds events on the editor for distraction free writing.
1106           *
1107           * @since 4.1.0
1108           *
1109           * @returns {void}
1110           */
1111  		function off() {
1112              if ( _isOn ) {
1113                  _isOn = false;
1114  
1115                  $title.add( $content ).off( '.focus' );
1116  
1117                  fadeIn();
1118  
1119                  $editor.off( '.focus' );
1120  
1121                  window.setUserSetting( 'post_dfw', 'off' );
1122  
1123                  $document.trigger( 'dfw-off' );
1124              }
1125          }
1126  
1127          /**
1128           * Binds or unbinds the editor expand events.
1129           *
1130           * @since 4.1.0
1131           *
1132           * @returns {void}
1133           */
1134  		function toggle() {
1135              if ( _isOn ) {
1136                  off();
1137              } else {
1138                  on();
1139              }
1140          }
1141  
1142          /**
1143           * Returns the value of _isOn.
1144           *
1145           * @since 4.1.0
1146           *
1147           * @returns {boolean} Returns true if _isOn is true.
1148           */
1149  		function isOn() {
1150              return _isOn;
1151          }
1152  
1153          /**
1154           * Fades out all elements except for the editor.
1155           *
1156           * The fading is done based on key presses and mouse movements.
1157           * Also calls the fadeIn on certain key presses
1158           * or if the mouse leaves the editor.
1159           *
1160           * @since 4.1.0
1161           *
1162           * @param event The event that triggers this function.
1163           *
1164           * @returns {void}
1165           */
1166  		function fadeOut( event ) {
1167              var isMac,
1168                  key = event && event.keyCode;
1169  
1170              if ( window.navigator.platform ) {
1171                  isMac = ( window.navigator.platform.indexOf( 'Mac' ) > -1 );
1172              }
1173  
1174              // Fade in and returns on Escape and keyboard shortcut Alt+Shift+W and Ctrl+Opt+W.
1175              if ( key === 27 || ( key === 87 && event.altKey && ( ( ! isMac && event.shiftKey ) || ( isMac && event.ctrlKey ) ) ) ) {
1176                  fadeIn( event );
1177                  return;
1178              }
1179  
1180              // Return if any of the following keys or combinations of keys is pressed.
1181              if ( event && ( event.metaKey || ( event.ctrlKey && ! event.altKey ) || ( event.altKey && event.shiftKey ) || ( key && (
1182                  // Special keys ( tab, ctrl, alt, esc, arrow keys... )
1183                  ( key <= 47 && key !== 8 && key !== 13 && key !== 32 && key !== 46 ) ||
1184                  // Windows keys
1185                  ( key >= 91 && key <= 93 ) ||
1186                  // F keys
1187                  ( key >= 112 && key <= 135 ) ||
1188                  // Num Lock, Scroll Lock, OEM
1189                  ( key >= 144 && key <= 150 ) ||
1190                  // OEM or non-printable
1191                  key >= 224
1192              ) ) ) ) {
1193                  return;
1194              }
1195  
1196              if ( ! faded ) {
1197                  faded = true;
1198  
1199                  clearTimeout( overlayTimer );
1200  
1201                  overlayTimer = setTimeout( function() {
1202                      $overlay.show();
1203                  }, 600 );
1204  
1205                  $editor.css( 'z-index', 9998 );
1206  
1207                  $overlay
1208                      // Always recalculate the editor area when entering the overlay with the mouse.
1209                      .on( 'mouseenter.focus', function() {
1210                          recalcEditorRect();
1211  
1212                          $window.on( 'scroll.focus', function() {
1213                              var nScrollY = window.pageYOffset;
1214  
1215                              if ( (
1216                                  scrollY && mouseY &&
1217                                  scrollY !== nScrollY
1218                              ) && (
1219                                  mouseY < editorRect.top - buffer ||
1220                                  mouseY > editorRect.bottom + buffer
1221                              ) ) {
1222                                  fadeIn();
1223                              }
1224  
1225                              scrollY = nScrollY;
1226                          } );
1227                      } )
1228                      .on( 'mouseleave.focus', function() {
1229                          x = y =  null;
1230                          traveledX = traveledY = 0;
1231  
1232                          $window.off( 'scroll.focus' );
1233                      } )
1234                      // Fade in when the mouse moves away form the editor area.
1235                      .on( 'mousemove.focus', function( event ) {
1236                          var nx = event.clientX,
1237                              ny = event.clientY,
1238                              pageYOffset = window.pageYOffset,
1239                              pageXOffset = window.pageXOffset;
1240  
1241                          if ( x && y && ( nx !== x || ny !== y ) ) {
1242                              if (
1243                                  ( ny <= y && ny < editorRect.top - pageYOffset ) ||
1244                                  ( ny >= y && ny > editorRect.bottom - pageYOffset ) ||
1245                                  ( nx <= x && nx < editorRect.left - pageXOffset ) ||
1246                                  ( nx >= x && nx > editorRect.right - pageXOffset )
1247                              ) {
1248                                  traveledX += Math.abs( x - nx );
1249                                  traveledY += Math.abs( y - ny );
1250  
1251                                  if ( (
1252                                      ny <= editorRect.top - buffer - pageYOffset ||
1253                                      ny >= editorRect.bottom + buffer - pageYOffset ||
1254                                      nx <= editorRect.left - buffer - pageXOffset ||
1255                                      nx >= editorRect.right + buffer - pageXOffset
1256                                  ) && (
1257                                      traveledX > 10 ||
1258                                      traveledY > 10
1259                                  ) ) {
1260                                      fadeIn();
1261  
1262                                      x = y =  null;
1263                                      traveledX = traveledY = 0;
1264  
1265                                      return;
1266                                  }
1267                              } else {
1268                                  traveledX = traveledY = 0;
1269                              }
1270                          }
1271  
1272                          x = nx;
1273                          y = ny;
1274                      } )
1275  
1276                      // When the overlay is touched, fade in and cancel the event.
1277                      .on( 'touchstart.focus', function( event ) {
1278                          event.preventDefault();
1279                          fadeIn();
1280                      } );
1281  
1282                  $editor.off( 'mouseenter.focus' );
1283  
1284                  if ( focusLostTimer ) {
1285                      clearTimeout( focusLostTimer );
1286                      focusLostTimer = null;
1287                  }
1288  
1289                  $body.addClass( 'focus-on' ).removeClass( 'focus-off' );
1290              }
1291  
1292              fadeOutAdminBar();
1293              fadeOutSlug();
1294          }
1295  
1296          /**
1297           * Fades all elements back in.
1298           *
1299           * @since 4.1.0
1300           *
1301           * @param event The event that triggers this function.
1302           *
1303           * @returns {void}
1304           */
1305  		function fadeIn( event ) {
1306              if ( faded ) {
1307                  faded = false;
1308  
1309                  clearTimeout( overlayTimer );
1310  
1311                  overlayTimer = setTimeout( function() {
1312                      $overlay.hide();
1313                  }, 200 );
1314  
1315                  $editor.css( 'z-index', '' );
1316  
1317                  $overlay.off( 'mouseenter.focus mouseleave.focus mousemove.focus touchstart.focus' );
1318  
1319                  /*
1320                   * When fading in, temporarily watch for refocus and fade back out - helps
1321                   * with 'accidental' editor exits with the mouse. When fading in and the event
1322                   * is a key event (Escape or Alt+Shift+W) don't watch for refocus.
1323                   */
1324                  if ( 'undefined' === typeof event ) {
1325                      $editor.on( 'mouseenter.focus', function() {
1326                          if ( $.contains( $editor.get( 0 ), document.activeElement ) || editorHasFocus ) {
1327                              fadeOut();
1328                          }
1329                      } );
1330                  }
1331  
1332                  focusLostTimer = setTimeout( function() {
1333                      focusLostTimer = null;
1334                      $editor.off( 'mouseenter.focus' );
1335                  }, 1000 );
1336  
1337                  $body.addClass( 'focus-off' ).removeClass( 'focus-on' );
1338              }
1339  
1340              fadeInAdminBar();
1341              fadeInSlug();
1342          }
1343  
1344          /**
1345           * Fades in if the focused element based on it position.
1346           *
1347           * @since 4.1.0
1348           *
1349           * @returns {void}
1350           */
1351  		function maybeFadeIn() {
1352              setTimeout( function() {
1353                  var position = document.activeElement.compareDocumentPosition( $editor.get( 0 ) );
1354  
1355  				function hasFocus( $el ) {
1356                      return $.contains( $el.get( 0 ), document.activeElement );
1357                  }
1358  
1359                  // The focused node is before or behind the editor area, and not outside the wrap.
1360                  if ( ( position === 2 || position === 4 ) && ( hasFocus( $menuWrap ) || hasFocus( $wrap ) || hasFocus( $footer ) ) ) {
1361                      fadeIn();
1362                  }
1363              }, 0 );
1364          }
1365  
1366          /**
1367           * Fades out the admin bar based on focus on the admin bar.
1368           *
1369           * @since 4.1.0
1370           *
1371           * @returns {void}
1372           */
1373  		function fadeOutAdminBar() {
1374              if ( ! fadedAdminBar && faded ) {
1375                  fadedAdminBar = true;
1376  
1377                  $adminBar
1378                      .on( 'mouseenter.focus', function() {
1379                          $adminBar.addClass( 'focus-off' );
1380                      } )
1381                      .on( 'mouseleave.focus', function() {
1382                          $adminBar.removeClass( 'focus-off' );
1383                      } );
1384              }
1385          }
1386  
1387          /**
1388           * Fades in the admin bar.
1389           *
1390           * @since 4.1.0
1391           *
1392           * @returns {void}
1393           */
1394  		function fadeInAdminBar() {
1395              if ( fadedAdminBar ) {
1396                  fadedAdminBar = false;
1397  
1398                  $adminBar.off( '.focus' );
1399              }
1400          }
1401  
1402          /**
1403           * Fades out the edit slug box.
1404           *
1405           * @since 4.1.0
1406           *
1407           * @returns {void}
1408           */
1409  		function fadeOutSlug() {
1410              if ( ! fadedSlug && faded && ! $slug.find( ':focus').length ) {
1411                  fadedSlug = true;
1412  
1413                  $slug.stop().fadeTo( 'fast', 0.3 ).on( 'mouseenter.focus', fadeInSlug ).off( 'mouseleave.focus' );
1414  
1415                  $slugFocusEl.on( 'focus.focus', fadeInSlug ).off( 'blur.focus' );
1416              }
1417          }
1418  
1419          /**
1420           * Fades in the edit slug box.
1421           *
1422           * @since 4.1.0
1423           *
1424           * @returns {void}
1425           */
1426  		function fadeInSlug() {
1427              if ( fadedSlug ) {
1428                  fadedSlug = false;
1429  
1430                  $slug.stop().fadeTo( 'fast', 1 ).on( 'mouseleave.focus', fadeOutSlug ).off( 'mouseenter.focus' );
1431  
1432                  $slugFocusEl.on( 'blur.focus', fadeOutSlug ).off( 'focus.focus' );
1433              }
1434          }
1435  
1436          /**
1437           * Triggers the toggle on Alt + Shift + W.
1438           *
1439           * Keycode 87 = w.
1440           *
1441           * @since 4.1.0
1442           *
1443           * @param {event} event The event to trigger the toggle.
1444           *
1445           * @returns {void}
1446           */
1447  		function toggleViaKeyboard( event ) {
1448              if ( event.altKey && event.shiftKey && 87 === event.keyCode ) {
1449                  toggle();
1450              }
1451          }
1452  
1453          if ( $( '#postdivrich' ).hasClass( 'wp-editor-expand' ) ) {
1454              $content.on( 'keydown.focus-shortcut', toggleViaKeyboard );
1455          }
1456  
1457          /**
1458           * Adds the distraction free writing button when setting up TinyMCE.
1459           *
1460           * @since 4.1.0
1461           *
1462           * @param {event} event The TinyMCE editor setup event.
1463           * @param {object} editor The editor to add the button to.
1464           *
1465           * @returns {void}
1466           */
1467          $document.on( 'tinymce-editor-setup.focus', function( event, editor ) {
1468              editor.addButton( 'dfw', {
1469                  active: _isOn,
1470                  classes: 'wp-dfw btn widget',
1471                  disabled: ! _isActive,
1472                  onclick: toggle,
1473                  onPostRender: function() {
1474                      var button = this;
1475  
1476                      editor.on( 'init', function() {
1477                          if ( button.disabled() ) {
1478                              button.hide();
1479                          }
1480                      } );
1481  
1482                      $document
1483                      .on( 'dfw-activate.focus', function() {
1484                          button.disabled( false );
1485                          button.show();
1486                      } )
1487                      .on( 'dfw-deactivate.focus', function() {
1488                          button.disabled( true );
1489                          button.hide();
1490                      } )
1491                      .on( 'dfw-on.focus', function() {
1492                          button.active( true );
1493                      } )
1494                      .on( 'dfw-off.focus', function() {
1495                          button.active( false );
1496                      } );
1497                  },
1498                  tooltip: 'Distraction-free writing mode',
1499                  shortcut: 'Alt+Shift+W'
1500              } );
1501  
1502              editor.addCommand( 'wpToggleDFW', toggle );
1503              editor.addShortcut( 'access+w', '', 'wpToggleDFW' );
1504          } );
1505  
1506          /**
1507           * Binds and unbinds events on the editor.
1508           *
1509           * @since 4.1.0
1510           *
1511           * @param {event} event The TinyMCE editor init event.
1512           * @param {object} editor The editor to bind events on.
1513           *
1514           * @returns {void}
1515           */
1516          $document.on( 'tinymce-editor-init.focus', function( event, editor ) {
1517              var mceBind, mceUnbind;
1518  
1519  			function focus() {
1520                  editorHasFocus = true;
1521              }
1522  
1523  			function blur() {
1524                  editorHasFocus = false;
1525              }
1526  
1527              if ( editor.id === 'content' ) {
1528                  $editorWindow = $( editor.getWin() );
1529                  $editorIframe = $( editor.getContentAreaContainer() ).find( 'iframe' );
1530  
1531                  mceBind = function() {
1532                      editor.on( 'keydown', fadeOut );
1533                      editor.on( 'blur', maybeFadeIn );
1534                      editor.on( 'focus', focus );
1535                      editor.on( 'blur', blur );
1536                      editor.on( 'wp-autoresize', recalcEditorRect );
1537                  };
1538  
1539                  mceUnbind = function() {
1540                      editor.off( 'keydown', fadeOut );
1541                      editor.off( 'blur', maybeFadeIn );
1542                      editor.off( 'focus', focus );
1543                      editor.off( 'blur', blur );
1544                      editor.off( 'wp-autoresize', recalcEditorRect );
1545                  };
1546  
1547                  if ( _isOn ) {
1548                      mceBind();
1549                  }
1550  
1551                  // Bind and unbind based on the distraction free writing focus.
1552                  $document.on( 'dfw-on.focus', mceBind ).on( 'dfw-off.focus', mceUnbind );
1553  
1554                  // Focuse the editor when it is the target of the click event.
1555                  editor.on( 'click', function( event ) {
1556                      if ( event.target === editor.getDoc().documentElement ) {
1557                          editor.focus();
1558                      }
1559                  } );
1560              }
1561          } );
1562  
1563          /**
1564           *  Binds events on quicktags init.
1565           *
1566           * @since 4.1.0
1567           *
1568           * @param {event} event The quicktags init event.
1569           * @param {object} editor The editor to bind events on.
1570           *
1571           * @returns {void}
1572           */
1573          $document.on( 'quicktags-init', function( event, editor ) {
1574              var $button;
1575  
1576              // Bind the distraction free writing events if the distraction free writing button is available.
1577              if ( editor.settings.buttons && ( ',' + editor.settings.buttons + ',' ).indexOf( ',dfw,' ) !== -1 ) {
1578                  $button = $( '#' + editor.name + '_dfw' );
1579  
1580                  $( document )
1581                  .on( 'dfw-activate', function() {
1582                      $button.prop( 'disabled', false );
1583                  } )
1584                  .on( 'dfw-deactivate', function() {
1585                      $button.prop( 'disabled', true );
1586                  } )
1587                  .on( 'dfw-on', function() {
1588                      $button.addClass( 'active' );
1589                  } )
1590                  .on( 'dfw-off', function() {
1591                      $button.removeClass( 'active' );
1592                  } );
1593              }
1594          } );
1595  
1596          $document.on( 'editor-expand-on.focus', activate ).on( 'editor-expand-off.focus', deactivate );
1597  
1598          if ( _isOn ) {
1599              $content.on( 'keydown.focus', fadeOut );
1600  
1601              $title.add( $content ).on( 'blur.focus', maybeFadeIn );
1602          }
1603  
1604          window.wp = window.wp || {};
1605          window.wp.editor = window.wp.editor || {};
1606          window.wp.editor.dfw = {
1607              activate: activate,
1608              deactivate: deactivate,
1609              isActive: isActive,
1610              on: on,
1611              off: off,
1612              toggle: toggle,
1613              isOn: isOn
1614          };
1615      } );
1616  } )( window, window.jQuery );


Generated: Tue Sep 17 01:00:03 2019 Cross-referenced by PHPXref 0.7.1