Index: src/wp-admin/css/edit.css =================================================================== --- src/wp-admin/css/edit.css (revision 29047) +++ src/wp-admin/css/edit.css (working copy) @@ -37,7 +37,6 @@ #titlediv { position: relative; - margin-bottom: 10px; } #titlediv label { @@ -337,7 +336,7 @@ background-color: #f7f7f7; -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.04); box-shadow: 0 1px 1px rgba(0,0,0,0.04); - cursor: row-resize; + z-index: 999; } #post-status-info td { @@ -345,7 +344,7 @@ } .autosave-info { - padding: 2px; + padding: 2px 10px; text-align: right; } @@ -367,6 +366,18 @@ padding: 2px 10px; } +#wp-content-editor-container { + position: relative; +} + +#content-textarea-clone { + z-index: -1; + position: absolute; + top: 0; + visibility: hidden; + overflow: hidden; +} + #timestampdiv select { height: 21px; line-height: 14px; @@ -1348,12 +1359,6 @@ padding: 10px 20px; } - #wp-content-editor-tools { - overflow: hidden; - padding: 20px 15px 1px 0; - top: 1px; - } - a.wp-switch-editor { font-size: 16px; line-height: 1em; Index: src/wp-admin/edit-form-advanced.php =================================================================== --- src/wp-admin/edit-form-advanced.php (revision 29047) +++ src/wp-admin/edit-form-advanced.php (working copy) @@ -11,6 +11,7 @@ die('-1'); wp_enqueue_script('post'); +wp_enqueue_script('editor-expand'); if ( wp_is_mobile() ) wp_enqueue_script( 'jquery-touch-punch' ); @@ -492,6 +493,7 @@ 'editor_height' => 360, 'tinymce' => array( 'resize' => false, + 'wp_autoresize_on' => true, 'add_unload_trigger' => false, ), ) ); ?> Index: src/wp-admin/js/common.js =================================================================== --- src/wp-admin/js/common.js (revision 29047) +++ src/wp-admin/js/common.js (working copy) @@ -179,7 +179,7 @@ }); $('#collapse-menu').on('click.collapse-menu', function() { - var body = $( document.body ), respWidth; + var body = $( document.body ), respWidth, state; // reset any compensation for submenus near the bottom of the screen $('#adminmenu div.wp-submenu').css('margin-top', ''); @@ -197,19 +197,25 @@ body.removeClass('auto-fold').removeClass('folded'); setUserSetting('unfold', 1); setUserSetting('mfold', 'o'); + state = 'open'; } else { body.addClass('auto-fold'); setUserSetting('unfold', 0); + state = 'folded'; } } else { if ( body.hasClass('folded') ) { body.removeClass('folded'); setUserSetting('mfold', 'o'); + state = 'open'; } else { body.addClass('folded'); setUserSetting('mfold', 'f'); + state = 'folded'; } } + + $( document ).trigger( 'wp-collapse-menu', { state: state } ); }); if ( 'ontouchstart' in window || /IEMobile\/[1-9]/.test(navigator.userAgent) ) { // touch screen device @@ -721,7 +727,7 @@ window.wpResponsive.init(); }); -// make Windows 8 devices playing along nicely +// Make Windows 8 devices play along nicely. (function(){ if ( '-ms-user-select' in document.documentElement.style && navigator.userAgent.match(/IEMobile\/10\.0/) ) { var msViewportStyle = document.createElement( 'style' ); Index: src/wp-admin/js/editor-expand.js =================================================================== --- src/wp-admin/js/editor-expand.js (revision 0) +++ src/wp-admin/js/editor-expand.js (working copy) @@ -0,0 +1,378 @@ + +window.wp = window.wp || {}; + +jQuery( document ).ready( function($) { + var $window = $( window ), + $document = $( document ), + $adminBar = $( '#wpadminbar' ), + $contentWrap = $( '#wp-content-wrap' ), + $tools = $( '#wp-content-editor-tools' ), + $visualTop, + $visualEditor, + $textTop = $( '#ed_toolbar' ), + $textEditor = $( '#content' ), + $textEditorClone = $( '
' ), + $bottom = $( '#post-status-info' ), + $statusBar, + buffer = 200, + adjust, + fullscreen = window.wp.editor && window.wp.editor.fullscreen, + editorInstance, + fixedTop = false, + fixedBottom = false; + + $textEditorClone.insertAfter( $textEditor ); + + // use to enable/disable + $contentWrap.addClass( 'wp-editor-expand' ); + $( '#content-resize-handle' ).hide(); + + $textEditorClone.css( { + 'font-family': $textEditor.css( 'font-family' ), + 'font-size': $textEditor.css( 'font-size' ), + 'line-height': $textEditor.css( 'line-height' ), + 'padding': $textEditor.css( 'padding' ), + 'padding-top': 37, + 'white-space': 'pre-wrap', + 'word-wrap': 'break-word' + } ); + + $textEditor.on( 'focus input propertychange', function() { + textEditorResize(); + } ); + + $textEditor.on( 'keyup', function() { + var range = document.createRange(), + start = $textEditor[0].selectionStart, + end = $textEditor[0].selectionEnd, + textNode = $textEditorClone[0].firstChild, + windowHeight = $window.height(), + offset, cursorTop, cursorBottom, editorTop, editorBottom; + + if ( start && end && start !== end ) { + return; + } + + range.setStart( textNode, start ); + range.setEnd( textNode, end + 1 ); + + offset = range.getBoundingClientRect(); + + if ( ! offset.height ) { + return; + } + + cursorTop = offset.top; + cursorBottom = cursorTop + offset.height; + editorTop = $adminBar.outerHeight() + $textTop.outerHeight(); + editorBottom = windowHeight - $bottom.outerHeight(); + + if ( cursorTop < editorTop || cursorBottom > editorBottom ) { + window.scrollTo( window.pageXOffset, cursorTop + window.pageYOffset - windowHeight / 2 ); + } + } ); + + function textEditorResize() { + if ( editorInstance && ! editorInstance.isHidden() ) { + return; + } + + var hiddenHeight = $textEditorClone.width( $textEditor.width() ).text( $textEditor.val() + ' ' ).height(), + textEditorHeight = $textEditor.height(); + + if ( hiddenHeight < 300 ) { + hiddenHeight = 300; + } + + if ( hiddenHeight === textEditorHeight ) { + return; + } + + $textEditor.height( hiddenHeight ); + + adjust( 'resize' ); + } + + // We need to wait for TinyMCE to initialize. + $document.on( 'tinymce-editor-init.editor-expand', function( event, editor ) { + // Make sure it's the main editor. + if ( editor.id !== 'content' ) { + return; + } + + // Copy the editor instance. + editorInstance = editor; + + // Resizing will be handled by the autoresize plugin. + editor.theme.resizeTo = function() {}; + + // Set the minimum height to the initial viewport height. + editor.settings.autoresize_min_height = 300; + + // Get the necessary UI elements. + $visualTop = $contentWrap.find( '.mce-toolbar-grp' ); + $visualEditor = $contentWrap.find( '.mce-edit-area' ); + $statusBar = $contentWrap.find( '.mce-statusbar' ).filter( ':visible' ); + + // Adjust when switching editor modes. + editor.on( 'show', function() { + setTimeout( function() { + editor.execCommand( 'mceAutoResize' ); + adjust( 'resize' ); + }, 200 ); + } ); + + editor.on( 'keyup', function() { + var offset = getCursorOffset(), + windowHeight = $window.height(), + cursorTop, cursorBottom, editorTop, editorBottom; + + if ( ! offset ) { + return; + } + + cursorTop = offset.top + editor.getContentAreaContainer().getElementsByTagName( 'iframe' )[0].getBoundingClientRect().top; + cursorBottom = cursorTop + offset.height; + editorTop = $adminBar.outerHeight() + $tools.outerHeight() + $visualTop.outerHeight(); + editorBottom = $window.height() - $bottom.outerHeight(); + + if ( cursorTop < editorTop || cursorBottom > editorBottom ) { + window.scrollTo( window.pageXOffset, cursorTop + window.pageYOffset - windowHeight / 2 ); + } + } ); + + function getCursorOffset() { + var selection = editor.selection, + node = selection.getNode(), + range = selection.getRng(), + view, clone, right, offset; + + if ( tinymce.Env.ie && tinymce.Env.ie < 9 ) { + return; + } + + if ( editor.plugins.wpview && ( view = editor.plugins.wpview.getView( node ) ) ) { + offset = view.getBoundingClientRect(); + } else if ( selection.isCollapsed() ) { + clone = range.cloneRange(); + + if ( clone.startContainer.length > 1 ) { + if ( clone.startContainer.length > clone.endOffset ) { + clone.setEnd( clone.startContainer, clone.endOffset + 1 ); + right = true; + } else { + clone.setStart( clone.startContainer, clone.endOffset - 1 ); + } + + selection.setRng( clone ); + offset = selection.getRng().getBoundingClientRect(); + selection.setRng( range ); + } else { + offset = node.getBoundingClientRect(); + } + } else { + offset = range.getBoundingClientRect(); + } + + if ( ! offset.height ) { + return false; + } + + return offset; + } + + editor.on( 'hide', function() { + textEditorResize(); + adjust( 'resize' ); + } ); + + // Adjust when the editor resizes. + editor.on( 'nodechange setcontent keyup FullscreenStateChanged', function() { + adjust( 'resize' ); + } ); + + editor.on( 'wp-toolbar-toggle', function() { + $visualEditor.css( { + paddingTop: $visualTop.outerHeight() + } ); + } ); + + // And adjust "immediately". + // Allow some time to load CSS etc. + setTimeout( function() { + $visualEditor.css( { + paddingTop: $visualTop.outerHeight() + } ); + + adjust( 'resize' ); + }, 500 ); + } ); + + // Adjust when the window is scrolled or resized. + $window.on( 'scroll resize', function( event ) { + adjust( event.type ); + } ); + + // Adjust when exiting fullscreen mode. + fullscreen && fullscreen.pubsub.subscribe( 'hidden', function() { + adjust( 'resize' ); + } ); + + // Adjust when collapsing the menu. + $document.on( 'wp-collapse-menu.editor-expand', function() { + adjust( 'resize' ); + } ) + + // Adjust when changing the columns. + .on( 'postboxes-columnchange.editor-expand', function() { + adjust( 'resize' ); + } ) + + // Adjust when changing the body class. + .on( 'editor-classchange.editor-expand', function() { + adjust( 'resize' ); + } ); + + // Adjust the toolbars based on the active editor mode. + function adjust( eventType ) { + // Make sure we're not in fullscreen mode. + if ( fullscreen && fullscreen.settings.visible ) { + return; + } + + var bottomHeight = $bottom.outerHeight(), + windowPos = $window.scrollTop(), + windowHeight = $window.height(), + windowWidth = $window.width(), + adminBarHeight = windowWidth > 600 ? $adminBar.height() : 0, + $top, $editor, visual, + toolsHeight, topPos, topHeight, editorPos, editorHeight, editorWidth, statusBarHeight; + + // Visual editor. + if ( editorInstance && ! editorInstance.isHidden() ) { + $top = $visualTop; + $editor = $visualEditor; + visual = true; + + // Doesn't hide the panel of 'styleselect'. :( + tinymce.each( editorInstance.controlManager.buttons, function( button ) { + if ( button._active && ( button.type === 'colorbutton' || button.type === 'panelbutton' || button.type === 'menubutton' ) ) { + button.hidePanel(); + } + } ); + // Text editor. + } else { + $top = $textTop; + $editor = $textEditor; + } + + toolsHeight = $tools.outerHeight(); + topPos = $top.parent().offset().top; + topHeight = $top.outerHeight(); + editorPos = $editor.offset().top; + editorHeight = $editor.outerHeight(); + editorWidth = $editor.outerWidth(); + statusBarHeight = visual ? $statusBar.outerHeight() : 0; + + // Maybe pin the top. + if ( ( ! fixedTop || eventType === 'resize' ) && + // Handle scrolling down. + ( windowPos >= ( topPos - toolsHeight - adminBarHeight ) && + // Handle scrolling up. + windowPos <= ( topPos - toolsHeight - adminBarHeight + editorHeight - buffer ) ) ) { + fixedTop = true; + + $top.css( { + position: 'fixed', + top: adminBarHeight + toolsHeight, + width: editorWidth - ( visual ? 0 : 38 ), + borderTop: '1px solid #e5e5e5' + } ); + + $tools.css( { + position: 'fixed', + top: adminBarHeight, + width: editorWidth + 2 + } ); + // Maybe unpin the top. + } else if ( fixedTop || eventType === 'resize' ) { + // Handle scrolling up. + if ( windowPos <= ( topPos - toolsHeight - adminBarHeight ) ) { + fixedTop = false; + + $top.css( { + position: 'absolute', + top: 0, + borderTop: 'none', + width: $editor.parent().width() - ( $top.outerWidth() - $top.width() ) + } ); + + $tools.css( { + position: 'absolute', + top: 0, + borderTop: 'none', + width: $contentWrap.width() + } ); + // Handle scrolling down. + } else if ( windowPos >= ( topPos - toolsHeight - adminBarHeight + editorHeight - buffer ) ) { + fixedTop = false; + + $top.css( { + position: 'absolute', + top: window.pageYOffset - $editor.offset().top + adminBarHeight + $tools.outerHeight(), + borderTop: 'none' + } ); + + $tools.css( { + position: 'absolute', + top: window.pageYOffset - $contentWrap.offset().top + adminBarHeight, + borderTop: 'none', + width: $contentWrap.width() + } ); + } + } + + // Maybe adjust the bottom bar. + if ( ( ! fixedBottom || eventType === 'resize' ) && + // + 1 for the border around the .wp-editor-container. + ( windowPos + windowHeight ) <= ( editorPos + editorHeight + bottomHeight + statusBarHeight + 1 ) ) { + fixedBottom = true; + + $bottom.css( { + position: 'fixed', + bottom: 0, + width: editorWidth + 2, + borderTop: '1px solid #dedede' + } ); + } else if ( fixedBottom && + ( windowPos + windowHeight ) > ( editorPos + editorHeight + bottomHeight + statusBarHeight - 1 ) ) { + fixedBottom = false; + + $bottom.css( { + position: 'relative', + bottom: 'auto', + width: '100%', + borderTop: 'none' + } ); + } + } + + textEditorResize(); + + $tools.css( { + position: 'absolute', + top: 0, + width: $contentWrap.width() + } ); + + $contentWrap.css( { + paddingTop: $tools.outerHeight() + } ); + + // This needs to execute after quicktags is ready or a button is added... + setTimeout( function() { + $textEditor.css( { + paddingTop: $textTop.outerHeight() + parseInt( $textEditor.css( 'padding-top' ), 10 ) + } ); + }, 500 ); +}); Index: src/wp-admin/js/post.js =================================================================== --- src/wp-admin/js/post.js (revision 29047) +++ src/wp-admin/js/post.js (working copy) @@ -1004,7 +1004,8 @@ ( function() { var editor, offset, mce, $textarea = $('textarea#content'), - $handle = $('#post-status-info'); + $handle = $('#post-status-info'), + $contentWrap = $('#wp-content-wrap'); // No point for touch devices if ( ! $textarea.length || 'ontouchstart' in window ) { @@ -1012,6 +1013,10 @@ } function dragging( event ) { + if ( $contentWrap.hasClass( 'wp-editor-expand' ) ) { + return; + } + if ( mce ) { editor.theme.resizeTo( null, offset + event.pageY ); } else { @@ -1024,6 +1029,10 @@ function endDrag() { var height, toolbarHeight; + if ( $contentWrap.hasClass( 'wp-editor-expand' ) ) { + return; + } + if ( mce ) { editor.focus(); toolbarHeight = parseInt( $( '#wp-content-editor-container .mce-toolbar-grp' ).height(), 10 ); @@ -1074,14 +1083,11 @@ $( '#post-formats-select input.post-format' ).on( 'change.set-editor-class', function() { var editor, body, format = this.id; - if ( format && $( this ).prop('checked') ) { - editor = tinymce.get( 'content' ); - - if ( editor ) { - body = editor.getBody(); - body.className = body.className.replace( /\bpost-format-[^ ]+/, '' ); - editor.dom.addClass( body, format == 'post-format-0' ? 'post-format-standard' : format ); - } + if ( format && $( this ).prop( 'checked' ) && ( editor = tinymce.get( 'content' ) ) ) { + body = editor.getBody(); + body.className = body.className.replace( /\bpost-format-[^ ]+/, '' ); + editor.dom.addClass( body, format == 'post-format-0' ? 'post-format-standard' : format ); + $( document ).trigger( 'editor-classchange' ); } }); } Index: src/wp-admin/js/postbox.js =================================================================== --- src/wp-admin/js/postbox.js (revision 29047) +++ src/wp-admin/js/postbox.js (working copy) @@ -159,6 +159,8 @@ if ( el ) { el.className = el.className.replace(/columns-\d+/, 'columns-' + n); } + + $( document ).trigger( 'postboxes-columnchange' ); }, _pb_change : function() { Index: src/wp-includes/class-wp-editor.php =================================================================== --- src/wp-includes/class-wp-editor.php (revision 29047) +++ src/wp-includes/class-wp-editor.php (working copy) @@ -347,6 +347,7 @@ 'textcolor', 'fullscreen', 'wordpress', + 'wpautoresize', 'wpeditimage', 'wpgallery', 'wplink', Index: src/wp-includes/css/editor.css =================================================================== --- src/wp-includes/css/editor.css (revision 29047) +++ src/wp-includes/css/editor.css (working copy) @@ -148,8 +148,13 @@ div.mce-toolbar-grp { border-bottom: 1px solid #dedede; background: #f5f5f5; - padding: 3px; + padding: 0; position: relative; + z-index: 999; +} + +div.mce-toolbar-grp > div { + padding: 3px; } .has-dfw div.mce-toolbar-grp .mce-toolbar.mce-first { @@ -161,14 +166,26 @@ } div.mce-statusbar { - border-top: 1px solid #eee; + border-top: 1px solid #e5e5e5; } div.mce-path { - padding: 0 8px 2px; + padding: 2px 10px; margin: 0; } +.mce-path, +.mce-path-item, +.mce-path .mce-divider { + font-size: 12px; + line-height: 18px; +} + +.mce-path-item:focus { + background: none; + color: inherit; +} + .mce-toolbar .mce-btn, .qt-fullscreen { border-color: transparent; @@ -731,7 +748,7 @@ } .mce-i-wp_code:before { - content: '\e017'; + content: '\f475'; } /* Editors */ @@ -740,8 +757,16 @@ } .wp-editor-tools { + background-color: #f1f1f1; + padding-top: 20px; position: relative; - z-index: 1; + z-index: 1000; +} + +.wp-editor-tools:after { + clear: both; + content: ''; + display: table; } .wp-editor-container { @@ -763,10 +788,6 @@ box-sizing: border-box; } -.wp-editor-tools { - padding: 0; -} - .wp-editor-container textarea.wp-editor-area { width: 100%; margin: 0; Index: src/wp-includes/js/tinymce/plugins/wordpress/plugin.js =================================================================== --- src/wp-includes/js/tinymce/plugins/wordpress/plugin.js (revision 29047) +++ src/wp-includes/js/tinymce/plugins/wordpress/plugin.js (working copy) @@ -52,6 +52,8 @@ wpAdvButton && wpAdvButton.active( true ); } } + + editor.fire( 'wp-toolbar-toggle' ); } // Add the kitchen sink button :) Index: src/wp-includes/js/tinymce/plugins/wpautoresize/plugin.js =================================================================== --- src/wp-includes/js/tinymce/plugins/wpautoresize/plugin.js (revision 0) +++ src/wp-includes/js/tinymce/plugins/wpautoresize/plugin.js (working copy) @@ -0,0 +1,326 @@ +/** + * plugin.js + * + * Copyright, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://www.tinymce.com/license + * Contributing: http://www.tinymce.com/contributing + */ + +// Forked for WordPress so it can be turned on/off after loading. + +/*global tinymce:true */ +/*eslint no-nested-ternary:0 */ + +/** + * Auto Resize + * + * This plugin automatically resizes the content area to fit its content height. + * It will retain a minimum height, which is the height of the content area when + * it's initialized. + */ +tinymce.PluginManager.add('wpautoresize', function(editor) { + var settings = editor.settings, oldSize = 0; + + function isFullscreen() { + return editor.plugins.fullscreen && editor.plugins.fullscreen.isFullscreen(); + } + + if (editor.settings.inline) { + return; + } + + /** + * This method gets executed each time the editor needs to resize. + */ + function resize(e) { + var deltaSize, doc, body, docElm, DOM = tinymce.DOM, resizeHeight, myHeight, marginTop, marginBottom; + + doc = editor.getDoc(); + if (!doc) { + return; + } + + body = doc.body; + docElm = doc.documentElement; + resizeHeight = settings.autoresize_min_height; + + if (!body || (e && e.type === "setcontent" && e.initial) || isFullscreen()) { + if (body && docElm) { + body.style.overflowY = "auto"; + docElm.style.overflowY = "auto"; // Old IE + } + + return; + } + + // Calculate outer height of the body element using CSS styles + marginTop = editor.dom.getStyle(body, 'margin-top', true); + marginBottom = editor.dom.getStyle(body, 'margin-bottom', true); + myHeight = body.offsetHeight + parseInt(marginTop, 10) + parseInt(marginBottom, 10); + + // Make sure we have a valid height + if (isNaN(myHeight) || myHeight <= 0) { + // Get height differently depending on the browser used + myHeight = tinymce.Env.ie ? body.scrollHeight : (tinymce.Env.webkit && body.clientHeight === 0 ? 0 : body.offsetHeight); + } + + // Don't make it smaller than the minimum height + if (myHeight > settings.autoresize_min_height) { + resizeHeight = myHeight; + } + + // If a maximum height has been defined don't exceed this height + if (settings.autoresize_max_height && myHeight > settings.autoresize_max_height) { + resizeHeight = settings.autoresize_max_height; + body.style.overflowY = "auto"; + docElm.style.overflowY = "auto"; // Old IE + } else { + body.style.overflowY = "hidden"; + docElm.style.overflowY = "hidden"; // Old IE + body.scrollTop = 0; + } + + // Resize content element + if (resizeHeight !== oldSize) { + deltaSize = resizeHeight - oldSize; + DOM.setStyle(DOM.get(editor.id + '_ifr'), 'height', resizeHeight + 'px'); + oldSize = resizeHeight; + + // WebKit doesn't decrease the size of the body element until the iframe gets resized + // So we need to continue to resize the iframe down until the size gets fixed + if (tinymce.isWebKit && deltaSize < 0) { + resize(e); + } + } + } + + /** + * Calls the resize x times in 100ms intervals. We can't wait for load events since + * the CSS files might load async. + */ + function wait( times, interval, callback ) { + setTimeout( function() { + resize({}); + + if ( times-- ) { + wait( times, interval, callback ); + } else if ( callback ) { + callback(); + } + }, interval ); + } + + // Define minimum height + settings.autoresize_min_height = parseInt(editor.getParam('autoresize_min_height', editor.getElement().offsetHeight), 10); + + // Define maximum height + settings.autoresize_max_height = parseInt(editor.getParam('autoresize_max_height', 0), 10); + + function on() { + if ( ! editor.dom.hasClass( editor.getBody(), 'wp-autoresize' ) ) { + editor.dom.addClass( editor.getBody(), 'wp-autoresize' ); + // Add appropriate listeners for resizing the content area + editor.on( 'nodechange setcontent keyup FullscreenStateChanged', resize ); + } + } + + function off() { + // Don't turn off if the setting is 'on' + if ( ! settings.wp_autoresize_on ) { + editor.dom.removeClass( editor.getBody(), 'wp-autoresize' ); + editor.off( 'nodechange setcontent keyup FullscreenStateChanged', resize ); + oldSize = 0; + } + } + + if ( settings.wp_autoresize_on ) { + // Turn resizing on when the editor loads + editor.on( 'init', function() { + editor.dom.addClass( editor.getBody(), 'wp-autoresize' ); + }); + + editor.on( 'nodechange setcontent keyup FullscreenStateChanged', resize ); + + if ( editor.getParam( 'autoresize_on_init', true ) ) { + editor.on( 'init', function() { + // Hit it 20 times in 100 ms intervals + wait( 10, 200, function() { + // Hit it 5 times in 1 sec intervals + wait( 5, 1000 ); + }); + }); + } + } + + // Register the command + editor.addCommand( 'wpAutoResize', resize ); + + // On/off + editor.addCommand( 'wpAutoResizeOn', on ); + editor.addCommand( 'wpAutoResizeOff', off ); +}); +/** + * plugin.js + * + * Copyright, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://www.tinymce.com/license + * Contributing: http://www.tinymce.com/contributing + */ + +// Forked for WordPress so it can be turned on/off after loading. + +/*global tinymce:true */ +/*eslint no-nested-ternary:0 */ + +/** + * Auto Resize + * + * This plugin automatically resizes the content area to fit its content height. + * It will retain a minimum height, which is the height of the content area when + * it's initialized. + */ +tinymce.PluginManager.add('wpautoresize', function(editor) { + var settings = editor.settings, oldSize = 0; + + function isFullscreen() { + return editor.plugins.fullscreen && editor.plugins.fullscreen.isFullscreen(); + } + + if (editor.settings.inline) { + return; + } + + /** + * This method gets executed each time the editor needs to resize. + */ + function resize(e) { + var deltaSize, doc, body, docElm, DOM = tinymce.DOM, resizeHeight, myHeight, marginTop, marginBottom; + + doc = editor.getDoc(); + if (!doc) { + return; + } + + body = doc.body; + docElm = doc.documentElement; + resizeHeight = settings.autoresize_min_height; + + if (!body || (e && e.type === "setcontent" && e.initial) || isFullscreen()) { + if (body && docElm) { + body.style.overflowY = "auto"; + docElm.style.overflowY = "auto"; // Old IE + } + + return; + } + + // Calculate outer height of the body element using CSS styles + marginTop = editor.dom.getStyle(body, 'margin-top', true); + marginBottom = editor.dom.getStyle(body, 'margin-bottom', true); + myHeight = body.offsetHeight + parseInt(marginTop, 10) + parseInt(marginBottom, 10); + + // Make sure we have a valid height + if (isNaN(myHeight) || myHeight <= 0) { + // Get height differently depending on the browser used + myHeight = tinymce.Env.ie ? body.scrollHeight : (tinymce.Env.webkit && body.clientHeight === 0 ? 0 : body.offsetHeight); + } + + // Don't make it smaller than the minimum height + if (myHeight > settings.autoresize_min_height) { + resizeHeight = myHeight; + } + + // If a maximum height has been defined don't exceed this height + if (settings.autoresize_max_height && myHeight > settings.autoresize_max_height) { + resizeHeight = settings.autoresize_max_height; + body.style.overflowY = "auto"; + docElm.style.overflowY = "auto"; // Old IE + } else { + body.style.overflowY = "hidden"; + docElm.style.overflowY = "hidden"; // Old IE + body.scrollTop = 0; + } + + // Resize content element + if (resizeHeight !== oldSize) { + deltaSize = resizeHeight - oldSize; + DOM.setStyle(DOM.get(editor.id + '_ifr'), 'height', resizeHeight + 'px'); + oldSize = resizeHeight; + + // WebKit doesn't decrease the size of the body element until the iframe gets resized + // So we need to continue to resize the iframe down until the size gets fixed + if (tinymce.isWebKit && deltaSize < 0) { + resize(e); + } + } + } + + /** + * Calls the resize x times in 100ms intervals. We can't wait for load events since + * the CSS files might load async. + */ + function wait( times, interval, callback ) { + setTimeout( function() { + resize({}); + + if ( times-- ) { + wait( times, interval, callback ); + } else if ( callback ) { + callback(); + } + }, interval ); + } + + // Define minimum height + settings.autoresize_min_height = parseInt(editor.getParam('autoresize_min_height', editor.getElement().offsetHeight), 10); + + // Define maximum height + settings.autoresize_max_height = parseInt(editor.getParam('autoresize_max_height', 0), 10); + + function on() { + if ( ! editor.dom.hasClass( editor.getBody(), 'wp-autoresize' ) ) { + editor.dom.addClass( editor.getBody(), 'wp-autoresize' ); + // Add appropriate listeners for resizing the content area + editor.on( 'nodechange setcontent keyup FullscreenStateChanged', resize ); + } + } + + function off() { + // Don't turn off if the setting is 'on' + if ( ! settings.wp_autoresize_on ) { + editor.dom.removeClass( editor.getBody(), 'wp-autoresize' ); + editor.off( 'nodechange setcontent keyup FullscreenStateChanged', resize ); + oldSize = 0; + } + } + + if ( settings.wp_autoresize_on ) { + // Turn resizing on when the editor loads + editor.on( 'init', function() { + editor.dom.addClass( editor.getBody(), 'wp-autoresize' ); + }); + + editor.on( 'nodechange setcontent keyup FullscreenStateChanged', resize ); + + if ( editor.getParam( 'autoresize_on_init', true ) ) { + editor.on( 'init', function() { + // Hit it 20 times in 100 ms intervals + wait( 10, 200, function() { + // Hit it 5 times in 1 sec intervals + wait( 5, 1000 ); + }); + }); + } + } + + // Register the command + editor.addCommand( 'wpAutoResize', resize ); + + // On/off + editor.addCommand( 'wpAutoResizeOn', on ); + editor.addCommand( 'wpAutoResizeOff', off ); +}); Index: src/wp-includes/js/tinymce/plugins/wpfullscreen/plugin.js =================================================================== --- src/wp-includes/js/tinymce/plugins/wpfullscreen/plugin.js (revision 29047) +++ src/wp-includes/js/tinymce/plugins/wpfullscreen/plugin.js (working copy) @@ -3,60 +3,20 @@ * WP Fullscreen (Distraction Free Writing) TinyMCE plugin */ tinymce.PluginManager.add( 'wpfullscreen', function( editor ) { - var settings = editor.settings, - oldSize = 0; - - function resize( e ) { - var deltaSize, myHeight, - d = editor.getDoc(), - body = d.body, - DOM = tinymce.DOM, - resizeHeight = 250; - - if ( ( e && e.type === 'setcontent' && e.initial ) || editor.settings.inline ) { - return; - } - - // Get height differently depending on the browser used - myHeight = tinymce.Env.ie ? body.scrollHeight : ( tinymce.Env.webkit && body.clientHeight === 0 ? 0 : body.offsetHeight ); - - // Don't make it smaller than 250px - if ( myHeight > 250 ) { - resizeHeight = myHeight; - } - - body.scrollTop = 0; - - // Resize content element - if ( resizeHeight !== oldSize ) { - deltaSize = resizeHeight - oldSize; - DOM.setStyle( DOM.get( editor.id + '_ifr' ), 'height', resizeHeight + 'px' ); - oldSize = resizeHeight; - - // WebKit doesn't decrease the size of the body element until the iframe gets resized - // So we need to continue to resize the iframe down until the size gets fixed - if ( tinymce.isWebKit && deltaSize < 0 ) { - resize( e ); - } - } - } - - // Register the command - editor.addCommand( 'wpAutoResize', resize ); + var settings = editor.settings; function fullscreenOn() { settings.wp_fullscreen = true; editor.dom.addClass( editor.getDoc().documentElement, 'wp-fullscreen' ); - // Add listeners for auto-resizing - editor.on( 'change setcontent paste keyup', resize ); + // Start auto-resizing + editor.execCommand( 'wpAutoResizeOn' ); } function fullscreenOff() { settings.wp_fullscreen = false; editor.dom.removeClass( editor.getDoc().documentElement, 'wp-fullscreen' ); - // Remove listeners for auto-resizing - editor.off( 'change setcontent paste keyup', resize ); - oldSize = 0; + // Stop auto-resizing + editor.execCommand( 'wpAutoResizeOff' ); } // For use from outside the editor. Index: src/wp-includes/js/tinymce/plugins/wpview/plugin.js =================================================================== --- src/wp-includes/js/tinymce/plugins/wpview/plugin.js (revision 29047) +++ src/wp-includes/js/tinymce/plugins/wpview/plugin.js (working copy) @@ -646,6 +646,7 @@ return { getViewText: getViewText, - setViewText: setViewText + setViewText: setViewText, + getView: getView }; }); Index: src/wp-includes/js/tinymce/skins/wordpress/wp-content.css =================================================================== --- src/wp-includes/js/tinymce/skins/wordpress/wp-content.css (revision 29047) +++ src/wp-includes/js/tinymce/skins/wordpress/wp-content.css (working copy) @@ -14,7 +14,17 @@ font-size: 13px; line-height: 19px; color: #333; - margin: 10px; + margin: 9px 10px; +} + +body.wp-autoresize { + max-width: 100%; + overflow: visible !important; + /* The padding ensures margins of the children are contained in the body. */ + padding-top: 1px !important; + padding-bottom: 1px !important; + padding-left: 0 !important; + padding-right: 0 !important; } /* When font-weight is different than the default browser style, Index: src/wp-includes/script-loader.php =================================================================== --- src/wp-includes/script-loader.php (revision 29047) +++ src/wp-includes/script-loader.php (working copy) @@ -459,6 +459,8 @@ 'savingText' => __('Saving Draft…'), ) ); + $scripts->add( 'editor-expand', "/wp-admin/js/editor-expand$suffix.js", array( 'jquery' ), false, 1 ); + $scripts->add( 'link', "/wp-admin/js/link$suffix.js", array( 'wp-lists', 'postbox' ), false, 1 ); $scripts->add( 'comment', "/wp-admin/js/comment$suffix.js", array( 'jquery', 'postbox' ) );