X-Git-Url: https://git.immae.eu/?p=perso%2FImmae%2FProjets%2Fpackagist%2Fpiedsjaloux-ckeditor-component.git;a=blobdiff_plain;f=sources%2Fcore%2Feditable.js;fp=sources%2Fcore%2Feditable.js;h=6b3fa9f7d7e64c4454d9a02e3e8fb3009b912bf3;hp=b9b0270b1443b52a0b6424127022eebad3b2ba28;hb=317f8f8f0651488f226b5280a8f036c7c135c639;hpb=1096cdefb1c9a3f3c4ca6807e272da6c92e5ed9c diff --git a/sources/core/editable.js b/sources/core/editable.js index b9b0270..6b3fa9f 100644 --- a/sources/core/editable.js +++ b/sources/core/editable.js @@ -1,9 +1,12 @@ /** - * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved. + * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or http://ckeditor.com/license */ ( function() { + var isNotWhitespace, isNotBookmark, isEmpty, isBogus, emptyParagraphRegexp, + insert, fixTableAfterContentsDeletion, fixListAfterContentsDelete, getHtmlFromRangeHelpers, extractHtmlFromRangeHelpers; + /** * Editable class which provides all editing related activities by * the `contenteditable` element, dynamically get attached to editor instance. @@ -71,17 +74,36 @@ } } - // [IE] Use instead "setActive" method to focus the editable if it belongs to - // the host page document, to avoid bringing an unexpected scroll. + // [Edge] Starting from EdgeHTML 14.14393, it does not support `setActive`. We need to use focus which + // causes unexpected scroll. Store scrollTop value so it can be restored after focusing editor. + // Scroll only happens if the editor is focused for the first time. (http://dev.ckeditor.com/ticket/14825) + if ( CKEDITOR.env.edge && CKEDITOR.env.version > 14 && !this.hasFocus && this.getDocument().equals( CKEDITOR.document ) ) { + this.editor._.previousScrollTop = this.$.scrollTop; + } + + // [IE] Use instead "setActive" method to focus the editable if it belongs to the host page document, + // to avoid bringing an unexpected scroll. try { - this.$[ CKEDITOR.env.ie && this.getDocument().equals( CKEDITOR.document ) ? 'setActive' : 'focus' ](); + if ( CKEDITOR.env.ie && !( CKEDITOR.env.edge && CKEDITOR.env.version > 14 ) && this.getDocument().equals( CKEDITOR.document ) ) { + this.$.setActive(); + } else { + // We have no control over exactly what happens when the native `focus` method is called, + // so save the scroll position and restore it later. + if ( CKEDITOR.env.chrome ) { + var scrollPos = this.$.scrollTop; + this.$.focus(); + this.$.scrollTop = scrollPos; + } else { + this.$.focus(); + } + } } catch ( e ) { // IE throws unspecified error when focusing editable after closing dialog opened on nested editable. if ( !CKEDITOR.env.ie ) throw e; } - // Remedy if Safari doens't applies focus properly. (#279) + // Remedy if Safari doens't applies focus properly. (http://dev.ckeditor.com/ticket/279) if ( CKEDITOR.env.safari && !this.isInline() ) { active = CKEDITOR.document.getActive(); if ( !active.equals( this.getWindow().getFrame() ) ) @@ -103,7 +125,7 @@ // The "focusin/focusout" events bubbled, e.g. If there are elements with layout // they fire this event when clicking in to edit them but it must be ignored - // to allow edit their contents. (#4682) + // to allow edit their contents. (http://dev.ckeditor.com/ticket/4682) fn = isNotBubbling( fn, this ); args[ 0 ] = name; args[ 1 ] = fn; @@ -238,7 +260,7 @@ * @param {String} text */ insertText: function( text ) { - // Focus the editor before calling transformPlainTextToHtml. (#12726) + // Focus the editor before calling transformPlainTextToHtml. (http://dev.ckeditor.com/ticket/12726) this.editor.focus(); this.insertHtml( this.transformPlainTextToHtml( text ), 'text' ); }, @@ -336,7 +358,7 @@ insertElement: function( element, range ) { var editor = this.editor; - // Prepare for the insertion. For example - focus editor (#11848). + // Prepare for the insertion. For example - focus editor (http://dev.ckeditor.com/ticket/11848). editor.focus(); editor.fire( 'saveSnapshot' ); @@ -349,12 +371,12 @@ range = selection.getRanges()[ 0 ]; } - // Insert element into first range only and ignore the rest (#11183). + // Insert element into first range only and ignore the rest (http://dev.ckeditor.com/ticket/11183). if ( this.insertElementIntoRange( element, range ) ) { range.moveToPosition( element, CKEDITOR.POSITION_AFTER_END ); // If we're inserting a block element, the new cursor position must be - // optimized. (#3100,#5436,#8950) + // optimized. (http://dev.ckeditor.com/ticket/3100,http://dev.ckeditor.com/ticket/5436,http://dev.ckeditor.com/ticket/8950) if ( isBlock ) { // Find next, meaningful element. var next = element.getNext( function( node ) { @@ -415,12 +437,19 @@ // Remove the original contents, merge split nodes. range.deleteContents( 1 ); - // If range is placed in inermediate element (not td or th), we need to do three things: - // * fill emptied s with if browser needs them, - // * remove empty text nodes so IE8 won't crash (http://dev.ckeditor.com/ticket/11183#comment:8), - // * fix structure and move range into the element. - if ( range.startContainer.type == CKEDITOR.NODE_ELEMENT && range.startContainer.is( { tr: 1, table: 1, tbody: 1, thead: 1, tfoot: 1 } ) ) - fixTableAfterContentsDeletion( range ); + if ( range.startContainer.type == CKEDITOR.NODE_ELEMENT ) { + // If range is placed in intermediate element (not td or th), we need to do three things: + // * fill emptied s with if browser needs them, + // * remove empty text nodes so IE8 won't crash + // (http://dev.ckeditor.com/ticket/11183#comment:8), + // * fix structure and move range into the element. + if ( range.startContainer.is( { tr: 1, table: 1, tbody: 1, thead: 1, tfoot: 1 } ) ) { + fixTableAfterContentsDeletion( range ); + } else if ( range.startContainer.is( CKEDITOR.dtd.$list ) ) { + // Similarly there's a need for lists. + fixListAfterContentsDelete( range ); + } + } // If we're inserting a block at dtd-violated position, split // the parent blocks until we reach blockLimit. @@ -435,7 +464,7 @@ range.splitElement( current ); // If we're in an empty block which indicate a new paragraph, - // simply replace it with the inserting block.(#3664) + // simply replace it with the inserting block.(http://dev.ckeditor.com/ticket/3664) else if ( range.checkStartOfBlock() && range.checkEndOfBlock() ) { range.setStartBefore( current ); range.collapse( true ); @@ -749,7 +778,7 @@ range.checkEndOfBlock() && path.block && !range.root.equals( path.block ) && - // Do not remove a block with bookmarks. (#13465) + // Do not remove a block with bookmarks. (http://dev.ckeditor.com/ticket/13465) !hasBookmarks( path.block ) ) { range.moveToPosition( path.block, CKEDITOR.POSITION_BEFORE_START ); path.block.remove(); @@ -811,7 +840,7 @@ // IE considers control-type element as separate // focus host when selected, avoid destroying the - // selection in such case. (#5812) (#8949) + // selection in such case. (http://dev.ckeditor.com/ticket/5812) (http://dev.ckeditor.com/ticket/8949) if ( ieSel && ieSel.type == 'Control' ) return; @@ -862,6 +891,30 @@ this.hasFocus = true; }, null, null, -1 ); + if ( CKEDITOR.env.webkit ) { + // [WebKit] Save scrollTop value so it can be used when restoring locked selection. (http://dev.ckeditor.com/ticket/14659) + this.on( 'scroll', function() { + editor._.previousScrollTop = editor.editable().$.scrollTop; + }, null, null, -1 ); + } + + // [Edge] This is the other part of the workaround for Edge which restores saved + // scrollTop value and removes listener which is not needed anymore. (http://dev.ckeditor.com/ticket/14825) + if ( CKEDITOR.env.edge && CKEDITOR.env.version > 14 ) { + + var fixScrollOnFocus = function() { + var editable = editor.editable(); + + if ( editor._.previousScrollTop != null && editable.getDocument().equals( CKEDITOR.document ) ) { + editable.$.scrollTop = editor._.previousScrollTop; + editor._.previousScrollTop = null; + this.removeListener( 'scroll', fixScrollOnFocus ); + } + }; + + this.on( 'scroll', fixScrollOnFocus ); + } + // Register to focus manager. editor.focusManager.add( this ); @@ -902,12 +955,16 @@ // Create the content stylesheet for this document. var styles = CKEDITOR.getCss(); if ( styles ) { - var head = doc.getHead(); - if ( !head.getCustomData( 'stylesheet' ) ) { + var head = doc.getHead(), + stylesElement = head.getCustomData( 'stylesheet' ); + + if ( !stylesElement ) { var sheet = doc.appendStyleText( styles ); sheet = new CKEDITOR.dom.element( sheet.ownerNode || sheet.owningElement ); head.setCustomData( 'stylesheet', sheet ); sheet.data( 'cke-temp', 1 ); + } else if ( styles != stylesElement.getText() ) { + CKEDITOR.env.ie && CKEDITOR.env.version < 9 ? stylesElement.$.styleSheet.cssText = styles : stylesElement.setText( styles ); } } @@ -918,7 +975,7 @@ // Pass this configuration to styles system. this.setCustomData( 'cke_includeReadonly', !editor.config.disableReadonlyStyling ); - // Prevent the browser opening read-only links. (#6032 & #10912) + // Prevent the browser opening read-only links. (http://dev.ckeditor.com/ticket/6032 & http://dev.ckeditor.com/ticket/10912) this.attachListener( this, 'click', function( evt ) { evt = evt.data; @@ -931,7 +988,7 @@ var backspaceOrDelete = { 8: 1, 46: 1 }; // Override keystrokes which should have deletion behavior - // on fully selected element . (#4047) (#7645) + // on fully selected element . (http://dev.ckeditor.com/ticket/4047) (http://dev.ckeditor.com/ticket/7645) this.attachListener( editor, 'key', function( evt ) { if ( editor.readOnly ) return true; @@ -941,10 +998,15 @@ var keyCode = evt.data.domEvent.getKey(), isHandled; + // Prevent of reading path of empty range (http://dev.ckeditor.com/ticket/13096, #457). + var sel = editor.getSelection(); + if ( sel.getRanges().length === 0 ) { + return; + } + // Backspace OR Delete. if ( keyCode in backspaceOrDelete ) { - var sel = editor.getSelection(), - selected, + var selected, range = sel.getRanges()[ 0 ], path = range.startPath(), block, @@ -952,16 +1014,17 @@ next, rtl = keyCode == 8; + if ( - // [IE<11] Remove selected image/anchor/etc here to avoid going back in history. (#10055) + // [IE<11] Remove selected image/anchor/etc here to avoid going back in history. (http://dev.ckeditor.com/ticket/10055) ( CKEDITOR.env.ie && CKEDITOR.env.version < 11 && ( selected = sel.getSelectedElement() ) ) || - // Remove the entire list/table on fully selected content. (#7645) + // Remove the entire list/table on fully selected content. (http://dev.ckeditor.com/ticket/7645) ( selected = getSelectedTableList( sel ) ) ) { // Make undo snapshot. editor.fire( 'saveSnapshot' ); // Delete any element that 'hasLayout' (e.g. hr,table) in IE8 will - // break up the selection, safely manage it here. (#4795) + // break up the selection, safely manage it here. (http://dev.ckeditor.com/ticket/4795) range.moveToPosition( selected, CKEDITOR.POSITION_BEFORE_START ); // Remove the control manually. selected.remove(); @@ -971,7 +1034,7 @@ isHandled = 1; } else if ( range.collapsed ) { - // Handle the following special cases: (#6217) + // Handle the following special cases: (http://dev.ckeditor.com/ticket/6217) // 1. Del/Backspace key before/after table; // 2. Backspace Key after start of table. if ( ( block = path.block ) && @@ -1046,28 +1109,28 @@ editor.fire( 'doubleclick', data ); } ); - // Prevent automatic submission in IE #6336 + // Prevent automatic submission in IE http://dev.ckeditor.com/ticket/6336 CKEDITOR.env.ie && this.attachListener( this, 'click', blockInputClick ); - // Gecko/Webkit need some help when selecting control type elements. (#3448) - // We apply same behavior for IE Edge. (#13386) + // Gecko/Webkit need some help when selecting control type elements. (http://dev.ckeditor.com/ticket/3448) + // We apply same behavior for IE Edge. (http://dev.ckeditor.com/ticket/13386) if ( !CKEDITOR.env.ie || CKEDITOR.env.edge ) { this.attachListener( this, 'mousedown', function( ev ) { var control = ev.data.getTarget(); - // #11727. Note: htmlDP assures that input/textarea/select have contenteditable=false + // http://dev.ckeditor.com/ticket/11727. Note: htmlDP assures that input/textarea/select have contenteditable=false // attributes. However, they also have data-cke-editable attribute, so isReadOnly() returns false, // and therefore those elements are correctly selected by this code. if ( control.is( 'img', 'hr', 'input', 'textarea', 'select' ) && !control.isReadOnly() ) { editor.getSelection().selectElement( control ); - // Prevent focus from stealing from the editable. (#9515) + // Prevent focus from stealing from the editable. (http://dev.ckeditor.com/ticket/9515) if ( control.is( 'input', 'textarea', 'select' ) ) ev.data.preventDefault(); } } ); } - // For some reason, after click event is done, IE Edge loses focus on the selected element. (#13386) + // For some reason, after click event is done, IE Edge loses focus on the selected element. (http://dev.ckeditor.com/ticket/13386) if ( CKEDITOR.env.edge ) { this.attachListener( this, 'mouseup', function( ev ) { var selectedElement = ev.data.getTarget(); @@ -1078,7 +1141,7 @@ } // Prevent right click from selecting an empty block even - // when selection is anchored inside it. (#5845) + // when selection is anchored inside it. (http://dev.ckeditor.com/ticket/5845) if ( CKEDITOR.env.gecko ) { this.attachListener( this, 'mouseup', function( ev ) { if ( ev.data.$.button == 2 ) { @@ -1109,7 +1172,7 @@ } // Prevent Webkit/Blink from going rogue when joining - // blocks on BACKSPACE/DEL (#11861,#9998). + // blocks on BACKSPACE/DEL (http://dev.ckeditor.com/ticket/11861,http://dev.ckeditor.com/ticket/9998). if ( CKEDITOR.env.webkit ) { this.attachListener( editor, 'key', function( evt ) { if ( editor.readOnly ) { @@ -1123,8 +1186,14 @@ if ( !( key in backspaceOrDelete ) ) return; + // Prevent of reading path of empty range (http://dev.ckeditor.com/ticket/13096, #457). + var sel = editor.getSelection(); + if ( sel.getRanges().length === 0 ) { + return; + } + var backspace = key == 8, - range = editor.getSelection().getRanges()[ 0 ], + range = sel.getRanges()[ 0 ], startPath = range.startPath(); if ( range.collapsed ) { @@ -1135,7 +1204,7 @@ return; } - // Scroll to the new position of the caret (#11960). + // Scroll to the new position of the caret (http://dev.ckeditor.com/ticket/11960). editor.getSelection().scrollIntoView(); editor.fire( 'saveSnapshot' ); @@ -1190,8 +1259,9 @@ * * @method editable * @member CKEDITOR.editor - * @param {CKEDITOR.dom.element/CKEDITOR.editable} elementOrEditable The + * @param {CKEDITOR.dom.element/CKEDITOR.editable} [elementOrEditable] The * DOM element to become the editable or a {@link CKEDITOR.editable} object. + * @returns {CKEDITOR.dom.element/null} The editor's editable element, or `null` if not available. */ CKEDITOR.editor.prototype.editable = function( element ) { var editable = this._.editable; @@ -1214,7 +1284,7 @@ CKEDITOR.on( 'instanceLoaded', function( evt ) { var editor = evt.editor; - // and flag that the element was locked by our code so it'll be editable by the editor functions (#6046). + // and flag that the element was locked by our code so it'll be editable by the editor functions (http://dev.ckeditor.com/ticket/6046). editor.on( 'insertElement', function( evt ) { var element = evt.data; if ( element.type == CKEDITOR.NODE_ELEMENT && ( element.is( 'input' ) || element.is( 'textarea' ) ) ) { @@ -1229,9 +1299,9 @@ if ( editor.readOnly ) return; - // Auto fixing on some document structure weakness to enhance usabilities. (#3190 and #3189) + // Auto fixing on some document structure weakness to enhance usabilities. (http://dev.ckeditor.com/ticket/3190 and http://dev.ckeditor.com/ticket/3189) var sel = editor.getSelection(); - // Do it only when selection is not locked. (#8222) + // Do it only when selection is not locked. (http://dev.ckeditor.com/ticket/8222) if ( sel && !sel.isLocked ) { var isDirty = editor.checkDirty(); @@ -1281,7 +1351,7 @@ } ); } ); - // #9222: Show text cursor in Gecko. + // http://dev.ckeditor.com/ticket/9222: Show text cursor in Gecko. // Show default cursor over control elements on all non-IEs. CKEDITOR.addCss( '.cke_editable{cursor:text}.cke_editable img,.cke_editable input,.cke_editable textarea{cursor:default}' ); @@ -1291,15 +1361,15 @@ // // - var isNotWhitespace = CKEDITOR.dom.walker.whitespaces( true ), - isNotBookmark = CKEDITOR.dom.walker.bookmark( false, true ), - isEmpty = CKEDITOR.dom.walker.empty(), - isBogus = CKEDITOR.dom.walker.bogus(), - // Matching an empty paragraph at the end of document. - emptyParagraphRegexp = /(^|]*>)\s*<(p|div|address|h\d|center|pre)[^>]*>\s*(?:]*>| |\u00A0| )?\s*(:?<\/\2>)?\s*(?=$|<\/body>)/gi; + isNotWhitespace = CKEDITOR.dom.walker.whitespaces( true ), + isNotBookmark = CKEDITOR.dom.walker.bookmark( false, true ), + isEmpty = CKEDITOR.dom.walker.empty(), + isBogus = CKEDITOR.dom.walker.bogus(), + // Matching an empty paragraph at the end of document. + emptyParagraphRegexp = /(^|]*>)\s*<(p|div|address|h\d|center|pre)[^>]*>\s*(?:]*>| |\u00A0| )?\s*(:?<\/\2>)?\s*(?=$|<\/body>)/gi; - // Auto-fixing block-less content by wrapping paragraph (#3190), prevent - // non-exitable-block by padding extra br.(#3189) + // Auto-fixing block-less content by wrapping paragraph (http://dev.ckeditor.com/ticket/3190), prevent + // non-exitable-block by padding extra br.(http://dev.ckeditor.com/ticket/3189) // Returns truly value when dom was changed, falsy otherwise. function fixDom( evt ) { var editor = evt.editor, @@ -1320,7 +1390,7 @@ } // When we're in block enter mode, a new paragraph will be established - // to encapsulate inline contents inside editable. (#3657) + // to encapsulate inline contents inside editable. (http://dev.ckeditor.com/ticket/3657) // Don't autoparagraph if browser (namely - IE) incorrectly anchored selection // inside non-editable content. This happens e.g. if non-editable block is the only // content of editable. @@ -1348,7 +1418,7 @@ selectionUpdateNeeded = 1; - // Cancel this selection change in favor of the next (correct). (#6811) + // Cancel this selection change in favor of the next (correct). (http://dev.ckeditor.com/ticket/6811) evt.cancel(); } } @@ -1364,13 +1434,13 @@ if ( selection.isFake ) return 0; - // Ensure bogus br could help to move cursor (out of styles) to the end of block. (#7041) + // Ensure bogus br could help to move cursor (out of styles) to the end of block. (http://dev.ckeditor.com/ticket/7041) var pathBlock = path.block || path.blockLimit, lastNode = pathBlock && pathBlock.getLast( isNotEmpty ); // Check some specialities of the current path block: - // 1. It is really displayed as block; (#7221) - // 2. It doesn't end with one inner block; (#7467) + // 1. It is really displayed as block; (http://dev.ckeditor.com/ticket/7221) + // 2. It doesn't end with one inner block; (http://dev.ckeditor.com/ticket/7467) // 3. It doesn't have bogus br yet. if ( pathBlock && pathBlock.isBlockBoundary() && @@ -1507,7 +1577,7 @@ // Whether in given context (pathBlock, pathBlockLimit and editor settings) // editor should automatically wrap inline contents with blocks. function shouldAutoParagraph( editor, pathBlock, pathBlockLimit ) { - // Check whether pathBlock equals pathBlockLimit to support nested editable (#12162). + // Check whether pathBlock equals pathBlockLimit to support nested editable (http://dev.ckeditor.com/ticket/12162). return editor.config.autoParagraph !== false && editor.activeEnterMode != CKEDITOR.ENTER_BR && ( @@ -1523,7 +1593,7 @@ // // Functions related to insertXXX methods // - var insert = ( function() { + insert = ( function() { 'use strict'; var DTD = CKEDITOR.dtd; @@ -1574,7 +1644,7 @@ // Select range and stop execution. // If data has been totally emptied after the filtering, - // any insertion is pointless (#10339). + // any insertion is pointless (http://dev.ckeditor.com/ticket/10339). if ( data && processDataForInsertion( that, data ) ) { // DATA INSERTION insertDataIntoRange( that ); @@ -1959,7 +2029,7 @@ nodeName = node.getName(); // Extract only the list items, when insertion happens - // inside of a list, reads as rearrange list items. (#7957) + // inside of a list, reads as rearrange list items. (http://dev.ckeditor.com/ticket/7957) if ( insideOfList && nodeName in CKEDITOR.dtd.$list ) { nodesData = nodesData.concat( extractNodesData( node, that ) ); continue; @@ -2207,7 +2277,7 @@ } // Don't use String.replace because it fails in IE7 if special replacement - // characters ($$, $&, etc.) are in data (#10367). + // characters ($$, $&, etc.) are in data (http://dev.ckeditor.com/ticket/10367). return wrapper.getOuterHtml().split( '{cke-peak}' ).join( data ); } @@ -2232,7 +2302,7 @@ // 1. Fixes a range which is a result of deleteContents() and is placed in an intermediate element (see dtd.$intermediate), // inside a table. A goal is to find a closest or element and when this fails, recreate the structure of the table. // 2. Fixes empty cells by appending bogus
s or deleting empty text nodes in IE<=8 case. - var fixTableAfterContentsDeletion = ( function() { + fixTableAfterContentsDeletion = ( function() { // Creates an element walker which can only "go deeper". It won't // move out from any element. Therefore it can be used to find x in cases like: // ^... @@ -2330,6 +2400,65 @@ }; } )(); + fixListAfterContentsDelete = ( function() { + // Creates an element walker which operates only within lists. + function getFixListSelectionWalker( testRange ) { + var walker = new CKEDITOR.dom.walker( testRange ); + walker.guard = function( node, isMovingOut ) { + if ( isMovingOut ) + return false; + if ( node.type == CKEDITOR.NODE_ELEMENT ) + return node.is( CKEDITOR.dtd.$list ) || node.is( CKEDITOR.dtd.$listItem ); + }; + walker.evaluator = function( node ) { + return node.type == CKEDITOR.NODE_ELEMENT && node.is( CKEDITOR.dtd.$listItem ); + }; + + return walker; + } + + return function( range ) { + var container = range.startContainer, + appendToStart = false, + testRange, + deeperSibling; + + // Look left. + testRange = range.clone(); + testRange.setStart( container, 0 ); + deeperSibling = getFixListSelectionWalker( testRange ).lastBackward(); + + // If left is empty, look right. + if ( !deeperSibling ) { + testRange = range.clone(); + testRange.setEndAt( container, CKEDITOR.POSITION_BEFORE_END ); + deeperSibling = getFixListSelectionWalker( testRange ).lastForward(); + appendToStart = true; + } + + // If there's no deeper nested element in both direction - container is empty - we'll use it then. + if ( !deeperSibling ) + deeperSibling = container; + + // We found a list what means that it's empty - remove it completely. + if ( deeperSibling.is( CKEDITOR.dtd.$list ) ) { + range.setStartAt( deeperSibling, CKEDITOR.POSITION_BEFORE_START ); + range.collapse( true ); + deeperSibling.remove(); + return; + } + + // To avoid setting selection after bogus, remove it from the target list item. + // We can safely do that, because we'll insert element into that cell. + var bogus = deeperSibling.getBogus(); + if ( bogus ) + bogus.remove(); + + range.moveToPosition( deeperSibling, appendToStart ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_BEFORE_END ); + range.select(); + }; + } )(); + function mergeBlocksCollapsedSelection( editor, range, backspace, startPath ) { var startBlock = startPath.block; @@ -2409,7 +2538,7 @@ if ( ( bogus = startBlock.getBogus() ) ) bogus.remove(); - // Changing end container to element from text node (#12503). + // Changing end container to element from text node (http://dev.ckeditor.com/ticket/12503). range.enlarge( CKEDITOR.ENLARGE_INLINE ); // Delete range contents. Do NOT merge. Merging is weird. @@ -2432,7 +2561,7 @@ range = editor.getSelection().getRanges()[ 0 ]; range.collapse( 1 ); - // Optimizing range containers from text nodes to elements (#12503). + // Optimizing range containers from text nodes to elements (http://dev.ckeditor.com/ticket/12503). range.optimize(); if ( range.startContainer.getHtml() === '' ) { range.startContainer.appendBogus(); @@ -2473,7 +2602,7 @@ // // Helpers for editable.getHtmlFromRange. // - var getHtmlFromRangeHelpers = { + getHtmlFromRangeHelpers = { eol: { detect: function( that, editable ) { var range = that.range, @@ -2638,7 +2767,7 @@ // // Helpers for editable.extractHtmlFromRange. // - var extractHtmlFromRangeHelpers = ( function() { + extractHtmlFromRangeHelpers = ( function() { function optimizeBookmarkNode( node, toStart ) { var parent = node.getParent(); @@ -2654,7 +2783,7 @@ while ( ( next = endBookmark.getNext() ) ) { next.insertAfter( startBookmark ); - // Update startBookmark after insertion to avoid the reversal of nodes (#13449). + // Update startBookmark after insertion to avoid the reversal of nodes (http://dev.ckeditor.com/ticket/13449). startBookmark = next; } @@ -2805,7 +2934,7 @@ walker.guard = function( node, leaving ) { // Guard may be executed on some node boundaries multiple times, - // what results in creating more than one range for each selected cell. (#12964) + // what results in creating more than one range for each selected cell. (http://dev.ckeditor.com/ticket/12964) if ( node.type == CKEDITOR.NODE_ELEMENT ) { var key = 'visited_' + ( leaving ? 'out' : 'in' ); if ( node.getCustomData( key ) ) {
x