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