diff --git a/src/wp-admin/js/editor.js b/src/wp-admin/js/editor.js
index 0e47b3e022..4d2c986554 100644
|
a
|
b
|
window.wp = window.wp || {};
|
| 234 | 234 | function getShortcodeWrapperInfo( content, cursorPosition ) { |
| 235 | 235 | var contentShortcodes = getShortCodePositionsInText( content ); |
| 236 | 236 | |
| 237 | | return _.find( contentShortcodes, function( element ) { |
| 238 | | return cursorPosition >= element.startIndex && cursorPosition <= element.endIndex; |
| 239 | | } ); |
| | 237 | for ( var i = 0; i < contentShortcodes.length; i++ ) { |
| | 238 | var element = contentShortcodes[ i ]; |
| | 239 | |
| | 240 | if ( cursorPosition >= element.startIndex && cursorPosition <= element.endIndex ) { |
| | 241 | return element; |
| | 242 | } |
| | 243 | } |
| 240 | 244 | } |
| 241 | 245 | |
| 242 | 246 | /** |
| … |
… |
window.wp = window.wp || {};
|
| 245 | 249 | * @param {string} content The content we want to scan for shortcodes. |
| 246 | 250 | */ |
| 247 | 251 | function getShortcodesInText( content ) { |
| 248 | | var shortcodes = content.match( /\[+([\w_-])+/g ); |
| | 252 | var shortcodes = content.match( /\[+([\w_-])+/g ), |
| | 253 | result = []; |
| 249 | 254 | |
| 250 | | return _.uniq( |
| 251 | | _.map( shortcodes, function( element ) { |
| 252 | | return element.replace( /^\[+/g, '' ); |
| 253 | | } ) |
| 254 | | ); |
| | 255 | for ( var i = 0; i < shortcodes.length; i++ ) { |
| | 256 | var shortcode = shortcodes[ i ].replace( /^\[+/g, '' ); |
| | 257 | |
| | 258 | if ( result.indexOf( shortcode ) === -1 ) { |
| | 259 | result.push( shortcode ); |
| | 260 | } |
| | 261 | } |
| | 262 | |
| | 263 | return result; |
| 255 | 264 | } |
| 256 | 265 | |
| 257 | 266 | /** |
| … |
… |
window.wp = window.wp || {};
|
| 335 | 344 | shortcodesDetails.push( shortcodeInfo ); |
| 336 | 345 | } |
| 337 | 346 | |
| | 347 | /** |
| | 348 | * Get all URL matches, and treat them as embeds. |
| | 349 | * |
| | 350 | * Since there isn't a good way to detect if a URL by itself on a line is a previewable |
| | 351 | * object, it's best to treat all of them as such. |
| | 352 | * |
| | 353 | * This means that the selection will capture the whole URL, in a similar way shrotcodes |
| | 354 | * are treated. |
| | 355 | */ |
| | 356 | var urlRegexp = new RegExp( |
| | 357 | '(^|[\\n\\r][\\n\\r]|<p>)(https?:\\/\\/[^\s"]+?)(<\\/p>\s*|[\\n\\r][\\n\\r]|$)', 'gi' |
| | 358 | ); |
| | 359 | |
| | 360 | while ( shortcodeMatch = urlRegexp.exec( content ) ) { |
| | 361 | shortcodeInfo = { |
| | 362 | shortcodeName: 'url', |
| | 363 | showAsPlainText: false, |
| | 364 | startIndex: shortcodeMatch.index, |
| | 365 | endIndex: shortcodeMatch.index + shortcodeMatch[ 0 ].length, |
| | 366 | length: shortcodeMatch[ 0 ].length, |
| | 367 | isPreviewable: true, |
| | 368 | urlAtStartOfContent: shortcodeMatch[ 1 ] === '', |
| | 369 | urlAtEndOfContent: shortcodeMatch[ 3 ] === '' |
| | 370 | }; |
| | 371 | |
| | 372 | shortcodesDetails.push( shortcodeInfo ); |
| | 373 | } |
| | 374 | |
| 338 | 375 | return shortcodesDetails; |
| 339 | 376 | } |
| 340 | 377 | |
| … |
… |
window.wp = window.wp || {};
|
| 412 | 449 | |
| 413 | 450 | var isCursorStartInShortcode = getShortcodeWrapperInfo( content, cursorStart ); |
| 414 | 451 | if ( isCursorStartInShortcode && isCursorStartInShortcode.isPreviewable ) { |
| 415 | | cursorStart = isCursorStartInShortcode.startIndex; |
| | 452 | /** |
| | 453 | * If a URL is at the start or the end of the content, |
| | 454 | * the selection doesn't work, because it inserts a marker in the text, |
| | 455 | * which breaks the embedURL detection. |
| | 456 | * |
| | 457 | * The best way to avoid that and not modify the user content is to |
| | 458 | * adjust the cursor to either after or before URL. |
| | 459 | */ |
| | 460 | if (isCursorStartInShortcode.urlAtStartOfContent) { |
| | 461 | cursorStart = isCursorStartInShortcode.endIndex; |
| | 462 | } |
| | 463 | else { |
| | 464 | cursorStart = isCursorStartInShortcode.startIndex; |
| | 465 | } |
| 416 | 466 | } |
| 417 | 467 | |
| 418 | 468 | var isCursorEndInShortcode = getShortcodeWrapperInfo( content, cursorEnd ); |
| 419 | 469 | if ( isCursorEndInShortcode && isCursorEndInShortcode.isPreviewable ) { |
| 420 | | cursorEnd = isCursorEndInShortcode.endIndex; |
| | 470 | if (isCursorEndInShortcode.urlAtEndOfContent) { |
| | 471 | cursorEnd = isCursorEndInShortcode.startIndex; |
| | 472 | } |
| | 473 | else { |
| | 474 | cursorEnd = isCursorEndInShortcode.endIndex; |
| | 475 | } |
| 421 | 476 | } |
| 422 | 477 | |
| 423 | 478 | return { |
| … |
… |
window.wp = window.wp || {};
|
| 455 | 510 | mode = htmlModeCursorStartPosition !== htmlModeCursorEndPosition ? 'range' : 'single', |
| 456 | 511 | |
| 457 | 512 | selectedText = null, |
| 458 | | cursorMarkerSkeleton = getCursorMarkerSpan( $$, '' ); |
| | 513 | cursorMarkerSkeleton = getCursorMarkerSpan( $$, '' ).attr( 'data-mce-type','bookmark' ); |
| 459 | 514 | |
| 460 | 515 | if ( mode === 'range' ) { |
| 461 | 516 | var markedText = textArea.value.slice( htmlModeCursorStartPosition, htmlModeCursorEndPosition ), |
| … |
… |
window.wp = window.wp || {};
|
| 470 | 525 | textArea.value = [ |
| 471 | 526 | textArea.value.slice( 0, htmlModeCursorStartPosition ), // text until the cursor/selection position |
| 472 | 527 | cursorMarkerSkeleton.clone() // cursor/selection start marker |
| 473 | | .addClass( 'mce_SELRES_start')[0].outerHTML, |
| | 528 | .addClass( 'mce_SELRES_start' )[0].outerHTML, |
| 474 | 529 | selectedText, // selected text with end cursor/position marker |
| 475 | 530 | textArea.value.slice( htmlModeCursorEndPosition ) // text from last cursor/selection position to end |
| 476 | 531 | ].join( '' ); |
| … |
… |
window.wp = window.wp || {};
|
| 487 | 542 | * @param {Object} editor TinyMCE editor instance. |
| 488 | 543 | */ |
| 489 | 544 | function focusHTMLBookmarkInVisualEditor( editor ) { |
| 490 | | var startNode = editor.$( '.mce_SELRES_start' ), |
| 491 | | endNode = editor.$( '.mce_SELRES_end' ); |
| | 545 | var startNode = editor.$( '.mce_SELRES_start' ).attr( 'data-mce-bogus', 1 ), |
| | 546 | endNode = editor.$( '.mce_SELRES_end' ).attr( 'data-mce-bogus', 1 ); |
| 492 | 547 | |
| 493 | 548 | if ( startNode.length ) { |
| 494 | 549 | editor.focus(); |
| … |
… |
window.wp = window.wp || {};
|
| 507 | 562 | |
| 508 | 563 | scrollVisualModeToStartElement( editor, startNode ); |
| 509 | 564 | |
| 510 | | |
| 511 | 565 | removeSelectionMarker( startNode ); |
| 512 | 566 | removeSelectionMarker( endNode ); |
| 513 | 567 | } |
| … |
… |
window.wp = window.wp || {};
|
| 675 | 729 | * This way we can adjust the selection to properly select only the content, ignoring |
| 676 | 730 | * whitespace inserted around the selected object by the Editor. |
| 677 | 731 | */ |
| 678 | | startElement.attr('data-mce-object-selection', 'true'); |
| 679 | | endElement.attr('data-mce-object-selection', 'true'); |
| | 732 | startElement.attr( 'data-mce-object-selection', 'true' ); |
| | 733 | endElement.attr( 'data-mce-object-selection', 'true' ); |
| 680 | 734 | |
| 681 | 735 | editor.$( startNode ).before( startElement[0] ); |
| 682 | 736 | editor.$( startNode ).after( endElement[0] ); |