Changeset 41645
- Timestamp:
- 09/29/2017 05:49:43 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/js/editor.js
r41630 r41645 134 134 var tinyMCEConfig = $.extend( 135 135 {}, 136 window.tinyMCEPreInit.mceInit[ id],136 window.tinyMCEPreInit.mceInit[ id ], 137 137 { 138 setup: function( editor) {139 editor.on( 'init', function(event) {138 setup: function( editor ) { 139 editor.on( 'init', function( event ) { 140 140 focusHTMLBookmarkInVisualEditor( event.target ); 141 141 }); … … 211 211 */ 212 212 function getContainingTagInfo( content, cursorPosition ) { 213 var lastLtPos = content.lastIndexOf( '<', cursorPosition ),213 var lastLtPos = content.lastIndexOf( '<', cursorPosition - 1 ), 214 214 lastGtPos = content.lastIndexOf( '>', cursorPosition ); 215 215 216 216 if ( lastLtPos > lastGtPos || content.substr( cursorPosition, 1 ) === '>' ) { 217 217 // find what the tag is 218 var tagContent = content.substr( lastLtPos ); 219 var tagMatch = tagContent.match( /<\s*(\/)?(\w+)/ ); 218 var tagContent = content.substr( lastLtPos ), 219 tagMatch = tagContent.match( /<\s*(\/)?(\w+)/ ); 220 220 221 if ( ! tagMatch ) { 221 222 return null; 222 223 } 223 224 224 var tagType = tagMatch[ 2 ]; 225 var closingGt = tagContent.indexOf( '>' ); 226 var isClosingTag = ! ! tagMatch[ 1 ]; 227 var shortcodeWrapperInfo = getShortcodeWrapperInfo( content, lastLtPos ); 225 var tagType = tagMatch[2], 226 closingGt = tagContent.indexOf( '>' ); 228 227 229 228 return { … … 231 230 gtPos: lastLtPos + closingGt + 1, // offset by one to get the position _after_ the character, 232 231 tagType: tagType, 233 isClosingTag: isClosingTag, 234 shortcodeTagInfo: shortcodeWrapperInfo 232 isClosingTag: !! tagMatch[1] 235 233 }; 236 234 } … … 239 237 240 238 /** 241 * @summary Check if a given HTML tag is enclosed in a shortcode tag239 * @summary Check if the cursor is inside a shortcode 242 240 * 243 241 * If the cursor is inside a shortcode wrapping tag, e.g. `[caption]` it's better to 244 * move the selection marker to before the short tag.242 * move the selection marker to before or after the shortcode. 245 243 * 246 244 * For example `[caption]` rewrites/removes anything that's between the `[caption]` tag and the 247 245 * `<img/>` tag inside. 248 246 * 249 * `[caption]<span>ThisIsGone</span><img .../>[caption]` 250 * 251 * Moving the selection to before the short code is better, since it allows to select 252 * something, instead of just losing focus and going to the start of the content. 253 * 254 * @param {string} content The text content to check against 255 * @param {number} cursorPosition The cursor position to check from. Usually this is the opening symbol of 256 * an HTML tag. 257 * 258 * @return {(null|Object)} Null if the oject is not wrapped in a shortcode tag. 259 * Information about the wrapping shortcode tag if it's wrapped in one. 247 * `[caption]<span>ThisIsGone</span><img .../>[caption]` 248 * 249 * Moving the selection to before or after the short code is better, since it allows to select 250 * something, instead of just losing focus and going to the start of the content. 251 * 252 * @param {string} content The text content to check against. 253 * @param {number} cursorPosition The cursor position to check. 254 * 255 * @return {(undefined|Object)} Undefined if the cursor is not wrapped in a shortcode tag. 256 * Information about the wrapping shortcode tag if it's wrapped in one. 260 257 */ 261 258 function getShortcodeWrapperInfo( content, cursorPosition ) { 262 if ( content.substr( cursorPosition - 1, 1 ) === ']' ) { 263 var shortTagStart = content.lastIndexOf( '[', cursorPosition ); 264 var shortTagContent = content.substr(shortTagStart, cursorPosition - shortTagStart); 265 var shortTag = content.match( /\[\s*(\/)?(\w+)/ ); 266 var tagType = shortTag[ 2 ]; 267 var closingGt = shortTagContent.indexOf( '>' ); 268 var isClosingTag = ! ! shortTag[ 1 ]; 269 270 return { 271 openingBracket: shortTagStart, 272 shortcode: tagType, 273 closingBracket: closingGt, 274 isClosingTag: isClosingTag 275 }; 276 } 277 278 return null; 259 var contentShortcodes = getShortCodePositionsInText( content ); 260 261 return _.find( contentShortcodes, function( element ) { 262 return cursorPosition >= element.startIndex && cursorPosition <= element.endIndex; 263 } ); 264 } 265 266 /** 267 * Gets a list of unique shortcodes or shortcode-look-alikes in the content. 268 * 269 * @param {string} content The content we want to scan for shortcodes. 270 */ 271 function getShortcodesInText( content ) { 272 var shortcodes = content.match( /\[+([\w_-])+/g ); 273 274 return _.uniq( 275 _.map( shortcodes, function( element ) { 276 return element.replace( /^\[+/g, '' ); 277 } ) 278 ); 279 } 280 281 /** 282 * @summary Check if a shortcode has Live Preview enabled for it. 283 * 284 * Previewable shortcodes here refers to shortcodes that have Live Preview enabled. 285 * 286 * These shortcodes get rewritten when the editor is in Visual mode, which means that 287 * we don't want to change anything inside them, i.e. inserting a selection marker 288 * inside the shortcode will break it :( 289 * 290 * @link wp-includes/js/mce-view.js 291 * 292 * @param {string} shortcode The shortcode to check. 293 * @return {boolean} If a shortcode has Live Preview or not 294 */ 295 function isShortcodePreviewable( shortcode ) { 296 var defaultPreviewableShortcodes = [ 'caption' ]; 297 298 return ( 299 defaultPreviewableShortcodes.indexOf( shortcode ) !== -1 || 300 wp.mce.views.get( shortcode ) !== undefined 301 ); 302 303 } 304 305 /** 306 * @summary Get all shortcodes and their positions in the content 307 * 308 * This function returns all the shortcodes that could be found in the textarea content 309 * along with their character positions and boundaries. 310 * 311 * This is used to check if the selection cursor is inside the boundaries of a shortcode 312 * and move it accordingly, to avoid breakage. 313 * 314 * @link adjustTextAreaSelectionCursors 315 * 316 * The information can also be used in other cases when we need to lookup shortcode data, 317 * as it's already structured! 318 * 319 * @param {string} content The content we want to scan for shortcodes 320 */ 321 function getShortCodePositionsInText( content ) { 322 var allShortcodes = getShortcodesInText( content ); 323 324 if ( allShortcodes.length === 0 ) { 325 return []; 326 } 327 328 var shortcodeDetailsRegexp = wp.shortcode.regexp( allShortcodes.join( '|' ) ), 329 shortcodeMatch, // Define local scope for the variable to be used in the loop below. 330 shortcodesDetails = []; 331 332 while ( shortcodeMatch = shortcodeDetailsRegexp.exec( content ) ) { 333 /** 334 * Check if the shortcode should be shown as plain text. 335 * 336 * This corresponds to the [[shortcode]] syntax, which doesn't parse the shortcode 337 * and just shows it as text. 338 */ 339 var showAsPlainText = shortcodeMatch[1] === '['; 340 341 /** 342 * For more context check the docs for: 343 * 344 * @link isShortcodePreviewable 345 * 346 * In addition, if the shortcode will get rendered as plain text ( see above ), 347 * we can treat it as text and use the selection markers in it. 348 */ 349 var isPreviewable = ! showAsPlainText && isShortcodePreviewable( shortcodeMatch[2] ), 350 shortcodeInfo = { 351 shortcodeName: shortcodeMatch[2], 352 showAsPlainText: showAsPlainText, 353 startIndex: shortcodeMatch.index, 354 endIndex: shortcodeMatch.index + shortcodeMatch[0].length, 355 length: shortcodeMatch[0].length, 356 isPreviewable: isPreviewable 357 }; 358 359 shortcodesDetails.push( shortcodeInfo ); 360 } 361 362 return shortcodesDetails; 279 363 } 280 364 … … 300 384 301 385 /** 302 * @summary Adds text selection markers in the editor textarea.303 * 304 * Adds selection markers in the content of the editor `textarea`.305 * The method directly manipulates the `textarea` content, to allow TinyMCE plugins306 * to run after the markers are added.307 * 308 * @ param {object} $textarea TinyMCE's textarea wrapped as a DomQuery object309 * @param {object} jQuery A jQuery instance310 * /311 function addHTMLBookmarkInTextAreaContent( $textarea, jQuery ) {312 var textArea = $textarea[ 0 ], // TODO add error checking313 htmlModeCursorStartPosition = textArea.selectionStart,314 htmlModeCursorEndPosition = textArea.selectionEnd;315 386 * @summary Get adjusted selection cursor positions according to HTML tags/shortcodes 387 * 388 * Shortcodes and HTML codes are a bit of a special case when selecting, since they may render 389 * content in Visual mode. If we insert selection markers somewhere inside them, it's really possible 390 * to break the syntax and render the HTML tag or shortcode broken. 391 * 392 * @link getShortcodeWrapperInfo 393 * 394 * @param {string} content Textarea content that the cursors are in 395 * @param {{cursorStart: number, cursorEnd: number}} cursorPositions Cursor start and end positions 396 * 397 * @return {{cursorStart: number, cursorEnd: number}} 398 */ 399 function adjustTextAreaSelectionCursors( content, cursorPositions ) { 316 400 var voidElements = [ 317 401 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', … … 319 403 ]; 320 404 321 // check if the cursor is in a tag and if so, adjust it 322 var isCursorStartInTag = getContainingTagInfo( textArea.value, htmlModeCursorStartPosition ); 405 var cursorStart = cursorPositions.cursorStart, 406 cursorEnd = cursorPositions.cursorEnd, 407 // check if the cursor is in a tag and if so, adjust it 408 isCursorStartInTag = getContainingTagInfo( content, cursorStart ); 409 323 410 if ( isCursorStartInTag ) { 324 411 /** … … 335 422 * so it's either between the opening and closing tag elements or after the closing tag. 336 423 */ 337 if ( voidElements.indexOf( isCursorStartInTag.tagType ) !== - 338 htmlModeCursorStartPosition= isCursorStartInTag.ltPos;424 if ( voidElements.indexOf( isCursorStartInTag.tagType ) !== -1 ) { 425 cursorStart = isCursorStartInTag.ltPos; 339 426 } 340 427 else { 341 htmlModeCursorStartPosition= isCursorStartInTag.gtPos;342 } 343 } 344 345 var isCursorEndInTag = getContainingTagInfo( textArea.value, htmlModeCursorEndPosition);428 cursorStart = isCursorStartInTag.gtPos; 429 } 430 } 431 432 var isCursorEndInTag = getContainingTagInfo( content, cursorEnd ); 346 433 if ( isCursorEndInTag ) { 347 htmlModeCursorEndPosition = isCursorEndInTag.gtPos; 348 } 349 350 var mode = htmlModeCursorStartPosition !== htmlModeCursorEndPosition ? 'range' : 'single'; 351 352 var selectedText = null; 353 var cursorMarkerSkeleton = getCursorMarkerSpan( { $: jQuery }, '' ); 434 cursorEnd = isCursorEndInTag.gtPos; 435 } 436 437 var isCursorStartInShortcode = getShortcodeWrapperInfo( content, cursorStart ); 438 if ( isCursorStartInShortcode && isCursorStartInShortcode.isPreviewable ) { 439 cursorStart = isCursorStartInShortcode.startIndex; 440 } 441 442 var isCursorEndInShortcode = getShortcodeWrapperInfo( content, cursorEnd ); 443 if ( isCursorEndInShortcode && isCursorEndInShortcode.isPreviewable ) { 444 cursorEnd = isCursorEndInShortcode.endIndex; 445 } 446 447 return { 448 cursorStart: cursorStart, 449 cursorEnd: cursorEnd 450 }; 451 } 452 453 /** 454 * @summary Adds text selection markers in the editor textarea. 455 * 456 * Adds selection markers in the content of the editor `textarea`. 457 * The method directly manipulates the `textarea` content, to allow TinyMCE plugins 458 * to run after the markers are added. 459 * 460 * @param {object} $textarea TinyMCE's textarea wrapped as a DomQuery object 461 * @param {object} jQuery A jQuery instance 462 */ 463 function addHTMLBookmarkInTextAreaContent( $textarea, jQuery ) { 464 if ( ! $textarea || ! $textarea.length ) { 465 // If no valid $textarea object is provided, there's nothing we can do. 466 return; 467 } 468 469 var textArea = $textarea[0], 470 textAreaContent = textArea.value, 471 472 adjustedCursorPositions = adjustTextAreaSelectionCursors( textAreaContent, { 473 cursorStart: textArea.selectionStart, 474 cursorEnd: textArea.selectionEnd 475 } ), 476 477 htmlModeCursorStartPosition = adjustedCursorPositions.cursorStart, 478 htmlModeCursorEndPosition = adjustedCursorPositions.cursorEnd, 479 480 mode = htmlModeCursorStartPosition !== htmlModeCursorEndPosition ? 'range' : 'single', 481 482 selectedText = null, 483 cursorMarkerSkeleton = getCursorMarkerSpan( { $: jQuery }, '' ); 354 484 355 485 if ( mode === 'range' ) { 356 var markedText = textArea.value.slice( htmlModeCursorStartPosition, htmlModeCursorEndPosition ); 357 358 /** 359 * Since the shortcodes convert the tags in them a bit, we need to mark the tag itself, 360 * and not rely on the cursor marker. 361 * 362 * @see getShortcodeWrapperInfo 363 */ 364 if ( isCursorStartInTag && isCursorStartInTag.shortcodeTagInfo ) { 365 // Get the tag on the cursor start 366 var tagEndPosition = isCursorStartInTag.gtPos - isCursorStartInTag.ltPos; 367 var tagContent = markedText.slice( 0, tagEndPosition ); 368 369 // Check if the tag already has a `class` attribute. 370 var classMatch = /class=(['"])([^$1]*?)\1/; 371 372 /** 373 * Add a marker class to the selected tag, to be used later. 374 * 375 * @see focusHTMLBookmarkInVisualEditor 376 */ 377 if ( tagContent.match( classMatch ) ) { 378 tagContent = tagContent.replace( classMatch, 'class=$1$2 mce_SELRES_start_target$1' ); 379 } 380 else { 381 tagContent = tagContent.replace( /(<\w+)/, '$1 class="mce_SELRES_start_target" ' ); 382 } 383 384 // Update the selected text content with the marked tag above 385 markedText = [ 386 tagContent, 387 markedText.substr( tagEndPosition ) 388 ].join( '' ); 389 } 390 391 var bookMarkEnd = cursorMarkerSkeleton.clone() 392 .addClass( 'mce_SELRES_end' )[ 0 ].outerHTML; 393 394 /** 395 * A small workaround when selecting just a single HTML tag inside a shortcode. 396 * 397 * This removes the end selection marker, to make sure the HTML tag is the only selected 398 * thing. This prevents the selection to appear like it contains multiple items in it (i.e. 399 * all highlighted blue) 400 */ 401 if ( isCursorStartInTag && isCursorStartInTag.shortcodeTagInfo && isCursorEndInTag && 402 isCursorStartInTag.ltPos === isCursorEndInTag.ltPos ) { 403 bookMarkEnd = ''; 404 } 486 var markedText = textArea.value.slice( htmlModeCursorStartPosition, htmlModeCursorEndPosition ), 487 bookMarkEnd = cursorMarkerSkeleton.clone().addClass( 'mce_SELRES_end' ); 405 488 406 489 selectedText = [ 407 490 markedText, 408 bookMarkEnd 491 bookMarkEnd[0].outerHTML 409 492 ].join( '' ); 410 493 } … … 433 516 endNode = editor.$( '.mce_SELRES_end' ); 434 517 435 if ( ! startNode.length ) {436 startNode = editor.$( '.mce_SELRES_start_target' );437 }438 439 518 if ( startNode.length ) { 440 519 editor.focus(); 441 520 442 521 if ( ! endNode.length ) { 443 editor.selection.select( startNode[ 0] );522 editor.selection.select( startNode[0] ); 444 523 } else { 445 524 var selection = editor.getDoc().createRange(); 446 525 447 selection.setStartAfter( startNode[ 0] );448 selection.setEndBefore( endNode[ 0] );526 selection.setStartAfter( startNode[0] ); 527 selection.setEndBefore( endNode[0] ); 449 528 450 529 editor.selection.setRng( selection ); 451 530 } 452 453 scrollVisualModeToStartElement( editor, startNode ); 454 } 455 456 if ( startNode.hasClass( 'mce_SELRES_start_target' ) ) { 457 startNode.removeClass( 'mce_SELRES_start_target' ); 531 } 532 533 scrollVisualModeToStartElement( editor, startNode ); 534 535 536 removeSelectionMarker( editor, startNode ); 537 removeSelectionMarker( editor, endNode ); 538 } 539 540 /** 541 * @summary Remove selection marker with optional `<p>` parent. 542 * 543 * By default TinyMCE puts every inline node at the main level in a `<p>` wrapping tag. 544 * 545 * In the case with selection markers, when removed they leave an empty `<p>` behind, 546 * which adds an empty paragraph line with ` ` when switched to Text mode. 547 * 548 * In order to prevent that the wrapping `<p>` needs to be removed when removing the 549 * selection marker. 550 * 551 * @param {object} editor The TinyMCE Editor instance 552 * @param {object} marker The marker to be removed from the editor DOM 553 */ 554 function removeSelectionMarker( editor, marker ) { 555 var markerParent = editor.$( marker ).parent(); 556 557 if ( 558 ! markerParent.length || 559 markerParent.prop('tagName').toLowerCase() !== 'p' || 560 markerParent[0].childNodes.length > 1 || 561 ! markerParent.prop('outerHTML').match(/^<p>/) 562 ) { 563 /** 564 * The selection marker is not self-contained in a <p>. 565 * In this case only the selection marker is removed, since 566 * it will affect the content. 567 */ 568 marker.remove(); 458 569 } 459 570 else { 460 startNode.remove(); 461 } 462 endNode.remove(); 571 /** 572 * The marker is self-contained in an blank `<p>` tag. 573 * 574 * This is usually inserted by TinyMCE 575 */ 576 markerParent.remove(); 577 } 463 578 } 464 579 … … 477 592 */ 478 593 function scrollVisualModeToStartElement( editor, element ) { 479 /** 480 * TODO: 481 * * Decide if we should animate the transition or not ( motion sickness/accessibility ) 482 */ 483 var elementTop = editor.$( element ).offset().top; 484 var TinyMCEContentAreaTop = editor.$( editor.getContentAreaContainer() ).offset().top; 485 486 var edTools = $('#wp-content-editor-tools'); 487 var edToolsHeight = edTools.height(); 488 var edToolsOffsetTop = edTools.offset().top; 489 490 var toolbarHeight = getToolbarHeight( editor ); 491 492 var windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; 493 494 var selectionPosition = TinyMCEContentAreaTop + elementTop; 495 var visibleAreaHeight = windowHeight - ( edToolsHeight + toolbarHeight ); 594 var elementTop = editor.$( element ).offset().top, 595 TinyMCEContentAreaTop = editor.$( editor.getContentAreaContainer() ).offset().top, 596 597 edTools = $( '#wp-content-editor-tools' ), 598 edToolsHeight = edTools.height(), 599 edToolsOffsetTop = edTools.offset().top, 600 601 toolbarHeight = getToolbarHeight( editor ), 602 603 windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight, 604 605 selectionPosition = TinyMCEContentAreaTop + elementTop, 606 visibleAreaHeight = windowHeight - ( edToolsHeight + toolbarHeight ); 496 607 497 608 /** … … 503 614 * the top of the viewport (under the Master Bar) 504 615 */ 505 var adjustedScroll = Math.max(selectionPosition - visibleAreaHeight / 2, edToolsOffsetTop - edToolsHeight); 506 507 508 $( 'body' ).animate( { 616 var adjustedScroll = Math.max( selectionPosition - visibleAreaHeight / 2, edToolsOffsetTop - edToolsHeight ); 617 618 $( 'html,body' ).animate( { 509 619 scrollTop: parseInt( adjustedScroll, 10 ) 510 620 }, 100 ); … … 561 671 * random content flickering in the editor when switching between modes. 562 672 */ 563 var spanSkeleton = getCursorMarkerSpan(editor, selectionID); 564 565 var startElement = spanSkeleton.clone().addClass('mce_SELRES_start'); 566 var endElement = spanSkeleton.clone().addClass('mce_SELRES_end'); 673 var spanSkeleton = getCursorMarkerSpan( editor, selectionID ), 674 startElement = spanSkeleton.clone().addClass( 'mce_SELRES_start' ), 675 endElement = spanSkeleton.clone().addClass( 'mce_SELRES_end' ); 567 676 568 677 /** … … 599 708 boundaryRange = range.cloneRange(); 600 709 601 boundaryRange.collapse( false );602 boundaryRange.insertNode( endElement[0] );603 604 710 /** 605 * Sometimes the selection starts at the `<img>` tag, which makes the 606 * boundary range `insertNode` insert `startElement` inside the `<img>` tag itself, i.e.: 607 * 608 * `<img><span class="mce_SELRES_start"...>...</span></img>` 609 * 610 * As this is an invalid syntax, it breaks the selection. 611 * 612 * The conditional below checks if `startNode` is a tag that suffer from that and 613 * manually inserts the selection start maker before it. 614 * 615 * In the future this will probably include a list of tags, not just `<img>`, depending on the needs. 711 * If the selection is on a shortcode with Live View, TinyMCE creates a bogus markup, 712 * which we have to account for. 616 713 */ 617 if ( startNode && startNode.tagName && startNode.tagName.toLowerCase() === 'img' ) { 618 editor.$( startNode ).before( startElement[ 0 ] ); 714 if ( editor.$( startNode ).parents( '.mce-offscreen-selection' ).length > 0 ) { 715 startNode = editor.$( '[data-mce-selected]' )[0]; 716 717 /** 718 * Marking the start and end element with `data-mce-object-selection` helps 719 * discern when the selected object is a Live Preview selection. 720 * 721 * This way we can adjust the selection to properly select only the content, ignoring 722 * whitespace inserted around the selected object by the Editor. 723 */ 724 startElement.attr('data-mce-object-selection', 'true'); 725 endElement.attr('data-mce-object-selection', 'true'); 726 727 editor.$( startNode ).before( startElement[0] ); 728 editor.$( startNode ).after( endElement[0] ); 619 729 } 620 730 else { 731 boundaryRange.collapse( false ); 732 boundaryRange.insertNode( endElement[0] ); 733 621 734 boundaryRange.setStart( startNode, startOffset ); 622 735 boundaryRange.collapse( true ); 623 boundaryRange.insertNode( startElement[ 0 ] ); 624 } 625 626 627 range.setStartAfter( startElement[0] ); 628 range.setEndBefore( endElement[0] ); 629 selection.removeAllRanges(); 630 selection.addRange( range ); 736 boundaryRange.insertNode( startElement[0] ); 737 738 range.setStartAfter( startElement[0] ); 739 range.setEndBefore( endElement[0] ); 740 selection.removeAllRanges(); 741 selection.addRange( range ); 742 } 631 743 632 744 /** … … 646 758 647 759 var startRegex = new RegExp( 648 '<span[^>]*\\s*class="mce_SELRES_start"[^>]+>\\s*' + selectionID + '[^<]*<\\/span> '760 '<span[^>]*\\s*class="mce_SELRES_start"[^>]+>\\s*' + selectionID + '[^<]*<\\/span>(\\s*)' 649 761 ); 650 762 651 763 var endRegex = new RegExp( 652 ' <span[^>]*\\s*class="mce_SELRES_end"[^>]+>\\s*' + selectionID + '[^<]*<\\/span>'764 '(\\s*)<span[^>]*\\s*class="mce_SELRES_end"[^>]+>\\s*' + selectionID + '[^<]*<\\/span>' 653 765 ); 654 766 655 var startMatch = content.match( startRegex ); 656 var endMatch = content.match( endRegex ); 767 var startMatch = content.match( startRegex ), 768 endMatch = content.match( endRegex ); 769 657 770 if ( ! startMatch ) { 658 771 return null; 659 772 } 660 773 774 var startIndex = startMatch.index, 775 startMatchLength = startMatch[0].length, 776 endIndex = null; 777 778 if (endMatch) { 779 /** 780 * Adjust the selection index, if the selection contains a Live Preview object or not. 781 * 782 * Check where the `data-mce-object-selection` attribute is set above for more context. 783 */ 784 if ( startMatch[0].indexOf( 'data-mce-object-selection' ) !== -1 ) { 785 startMatchLength -= startMatch[1].length; 786 } 787 788 var endMatchIndex = endMatch.index; 789 790 if ( endMatch[0].indexOf( 'data-mce-object-selection' ) !== -1 ) { 791 endMatchIndex -= endMatch[1].length; 792 } 793 794 // We need to adjust the end position to discard the length of the range start marker 795 endIndex = endMatchIndex - startMatchLength; 796 } 797 661 798 return { 662 start: startMatch.index, 663 664 // We need to adjust the end position to discard the length of the range start marker 665 end: endMatch ? endMatch.index - startMatch[ 0 ].length : null 799 start: startIndex, 800 end: endIndex 666 801 }; 667 802 } … … 673 808 * 674 809 * For `selection` parameter: 675 * @ seefindBookmarkedPosition810 * @link findBookmarkedPosition 676 811 * 677 812 * @param {Object} editor TinyMCE's editor instance.
Note: See TracChangeset
for help on using the changeset viewer.