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