Make WordPress Core

Changeset 41783


Ignore:
Timestamp:
10/06/2017 05:43:11 PM (7 years ago)
Author:
azaozz
Message:

Editor:

  • Fix keeping text selection and scroll position when there are embeds from URL.
  • Add editor setting to disable keeping selection and scroll position.
  • Remove dependency on Underscore.js.
  • Fix error in the Text widget editor.

Props biskobe.
Fixes #42059, see #40854.

Location:
trunk/src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/edit-form-advanced.php

    r40578 r41783  
    629629        'wp_autoresize_on' => $_wp_editor_expand,
    630630        'add_unload_trigger' => false,
     631        'wp_keep_scroll_position' => true,
    631632    ),
    632633) ); ?>
  • trunk/src/wp-admin/js/editor.js

    r41656 r41783  
    100100                editorHeight = parseInt( textarea.style.height, 10 ) || 0;
    101101
    102                 // Save the selection
    103                 addHTMLBookmarkInTextAreaContent( $textarea, $ );
     102                var keepSelection = false;
     103                if ( editor ) {
     104                    keepSelection = editor.getParam( 'wp_keep_scroll_position' )
     105                } else {
     106                    keepSelection = window.tinyMCEPreInit.mceInit[ id ] &&
     107                                    window.tinyMCEPreInit.mceInit[ id ]['wp_keep_scroll_position']
     108                }
     109
     110                if ( keepSelection ) {
     111                    // Save the selection
     112                    addHTMLBookmarkInTextAreaContent( $textarea );
     113                }
    104114
    105115                if ( editor ) {
     
    117127                    }
    118128
    119                     // Restore the selection
    120                     focusHTMLBookmarkInVisualEditor( editor );
     129                    if ( editor.getParam( 'wp_keep_scroll_position' ) ) {
     130                        // Restore the selection
     131                        focusHTMLBookmarkInVisualEditor( editor );
     132                    }
    121133                } else {
    122134                    tinymce.init( window.tinyMCEPreInit.mceInit[ id ] );
     
    133145                }
    134146
    135                 var selectionRange = null;
    136147                if ( editor ) {
    137148                    // Don't resize the textarea in iOS. The iframe is forced to 100% height there, we shouldn't match it.
     
    151162                    }
    152163
    153                     selectionRange = findBookmarkedPosition( editor );
     164                    var selectionRange = null;
     165
     166                    if ( editor.getParam( 'wp_keep_scroll_position' ) ) {
     167                        selectionRange = findBookmarkedPosition( editor );
     168                    }
    154169
    155170                    editor.hide();
     
    235250            var contentShortcodes = getShortCodePositionsInText( content );
    236251
    237             return _.find( contentShortcodes, function( element ) {
    238                 return cursorPosition >= element.startIndex && cursorPosition <= element.endIndex;
    239             } );
     252            for ( var i = 0; i < contentShortcodes.length; i++ ) {
     253                var element = contentShortcodes[ i ];
     254
     255                if ( cursorPosition >= element.startIndex && cursorPosition <= element.endIndex ) {
     256                    return element;
     257                }
     258            }
    240259        }
    241260
     
    246265         */
    247266        function getShortcodesInText( content ) {
    248             var shortcodes = content.match( /\[+([\w_-])+/g );
    249 
    250             return _.uniq(
    251                 _.map( shortcodes, function( element ) {
    252                     return element.replace( /^\[+/g, '' );
    253                 } )
    254             );
     267            var shortcodes = content.match( /\[+([\w_-])+/g ),
     268                result = [];
     269
     270            if ( shortcodes ) {
     271                for ( var i = 0; i < shortcodes.length; i++ ) {
     272                    var shortcode = shortcodes[ i ].replace( /^\[+/g, '' );
     273   
     274                    if ( result.indexOf( shortcode ) === -1 ) {
     275                        result.push( shortcode );
     276                    }
     277                }
     278            }
     279
     280            return result;
    255281        }
    256282
     
    336362            }
    337363
     364            /**
     365             * Get all URL matches, and treat them as embeds.
     366             *
     367             * Since there isn't a good way to detect if a URL by itself on a line is a previewable
     368             * object, it's best to treat all of them as such.
     369             *
     370             * This means that the selection will capture the whole URL, in a similar way shrotcodes
     371             * are treated.
     372             */
     373            var urlRegexp = new RegExp(
     374                '(^|[\\n\\r][\\n\\r]|<p>)(https?:\\/\\/[^\s"]+?)(<\\/p>\s*|[\\n\\r][\\n\\r]|$)', 'gi'
     375            );
     376
     377            while ( shortcodeMatch = urlRegexp.exec( content ) ) {
     378                shortcodeInfo = {
     379                    shortcodeName: 'url',
     380                    showAsPlainText: false,
     381                    startIndex: shortcodeMatch.index,
     382                    endIndex: shortcodeMatch.index + shortcodeMatch[ 0 ].length,
     383                    length: shortcodeMatch[ 0 ].length,
     384                    isPreviewable: true,
     385                    urlAtStartOfContent: shortcodeMatch[ 1 ] === '',
     386                    urlAtEndOfContent: shortcodeMatch[ 3 ] === ''
     387                };
     388
     389                shortcodesDetails.push( shortcodeInfo );
     390            }
     391
    338392            return shortcodesDetails;
    339393        }
     
    400454                if ( voidElements.indexOf( isCursorStartInTag.tagType ) !== -1 ) {
    401455                    cursorStart = isCursorStartInTag.ltPos;
    402                 }
    403                 else {
     456                } else {
    404457                    cursorStart = isCursorStartInTag.gtPos;
    405458                }
     
    413466            var isCursorStartInShortcode = getShortcodeWrapperInfo( content, cursorStart );
    414467            if ( isCursorStartInShortcode && isCursorStartInShortcode.isPreviewable ) {
    415                 cursorStart = isCursorStartInShortcode.startIndex;
     468                /**
     469                 * If a URL is at the start or the end of the content,
     470                 * the selection doesn't work, because it inserts a marker in the text,
     471                 * which breaks the embedURL detection.
     472                 *
     473                 * The best way to avoid that and not modify the user content is to
     474                 * adjust the cursor to either after or before URL.
     475                 */
     476                if ( isCursorStartInShortcode.urlAtStartOfContent ) {
     477                    cursorStart = isCursorStartInShortcode.endIndex;
     478                } else {
     479                    cursorStart = isCursorStartInShortcode.startIndex;
     480                }
    416481            }
    417482
    418483            var isCursorEndInShortcode = getShortcodeWrapperInfo( content, cursorEnd );
    419484            if ( isCursorEndInShortcode && isCursorEndInShortcode.isPreviewable ) {
    420                 cursorEnd = isCursorEndInShortcode.endIndex;
     485                if ( isCursorEndInShortcode.urlAtEndOfContent ) {
     486                    cursorEnd = isCursorEndInShortcode.startIndex;
     487                } else {
     488                    cursorEnd = isCursorEndInShortcode.endIndex;
     489                }
    421490            }
    422491
     
    456525
    457526                selectedText = null,
    458                 cursorMarkerSkeleton = getCursorMarkerSpan( $$, '&#65279;' );
     527                cursorMarkerSkeleton = getCursorMarkerSpan( $$, '&#65279;' ).attr( 'data-mce-type','bookmark' );
    459528
    460529            if ( mode === 'range' ) {
     
    471540                textArea.value.slice( 0, htmlModeCursorStartPosition ), // text until the cursor/selection position
    472541                cursorMarkerSkeleton.clone()                            // cursor/selection start marker
    473                     .addClass( 'mce_SELRES_start')[0].outerHTML,
     542                    .addClass( 'mce_SELRES_start' )[0].outerHTML,
    474543                selectedText,                                           // selected text with end cursor/position marker
    475544                textArea.value.slice( htmlModeCursorEndPosition )       // text from last cursor/selection position to end
     
    488557         */
    489558        function focusHTMLBookmarkInVisualEditor( editor ) {
    490             var startNode = editor.$( '.mce_SELRES_start' ),
    491                 endNode = editor.$( '.mce_SELRES_end' );
     559            var startNode = editor.$( '.mce_SELRES_start' ).attr( 'data-mce-bogus', 1 ),
     560                endNode = editor.$( '.mce_SELRES_end' ).attr( 'data-mce-bogus', 1 );
    492561
    493562            if ( startNode.length ) {
     
    506575            }
    507576
    508             scrollVisualModeToStartElement( editor, startNode );
    509 
     577            if ( editor.getParam( 'wp_keep_scroll_position' ) ) {
     578                scrollVisualModeToStartElement( editor, startNode );
     579            }
    510580
    511581            removeSelectionMarker( startNode );
     
    549619                TinyMCEContentAreaTop = editor.$( editor.getContentAreaContainer() ).offset().top,
    550620
     621                toolbarHeight = getToolbarHeight( editor ),
     622
    551623                edTools = $( '#wp-content-editor-tools' ),
    552                 edToolsHeight = edTools.height(),
    553                 edToolsOffsetTop = edTools.offset().top,
    554 
    555                 toolbarHeight = getToolbarHeight( editor ),
    556 
    557                 windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,
     624                edToolsHeight = 0,
     625                edToolsOffsetTop = 0;
     626
     627            if ( edTools.length ) {
     628                edToolsHeight = edTools.height();
     629                edToolsOffsetTop = edTools.offset().top;
     630            }
     631
     632            var windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,
    558633
    559634                selectionPosition = TinyMCEContentAreaTop + elementTop,
     
    676751                 * whitespace inserted around the selected object by the Editor.
    677752                 */
    678                 startElement.attr('data-mce-object-selection', 'true');
    679                 endElement.attr('data-mce-object-selection', 'true');
     753                startElement.attr( 'data-mce-object-selection', 'true' );
     754                endElement.attr( 'data-mce-object-selection', 'true' );
    680755
    681756                editor.$( startNode ).before( startElement[0] );
  • trunk/src/wp-includes/class-wp-editor.php

    r41346 r41783  
    982982            'wpeditimage_html5_captions' => true,
    983983            'wp_lang_attr' => get_bloginfo( 'language' ),
     984            'wp_keep_scroll_position' => false,
    984985            'wp_shortcut_labels' => wp_json_encode( $shortcut_labels ),
    985986        );
Note: See TracChangeset for help on using the changeset viewer.