[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sat Nov 23 20:47:33 2019 | Cross-referenced by PHPXref 0.7 |