Make WordPress Core

Changeset 41783


Ignore:
Timestamp:
10/06/2017 05:43:11 PM (9 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.