Skip to content

Commit ed52709

Browse files
committed
Merge branch 't/11183'
2 parents a1baa1d + f966e67 commit ed52709

File tree

2 files changed

+118
-23
lines changed

2 files changed

+118
-23
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Fixed Issues:
1818
* [#11202](http://dev.ckeditor.com/ticket/11202): Fixed: No newline at BB-code mode.
1919
* [#10890](http://dev.ckeditor.com/ticket/10890): Fixed: Error thrown when pressing *Delete* key in a list item.
2020
* [#10055](http://dev.ckeditor.com/ticket/10055): [IE8-10] Fixed: *Delete* pressed on selected image causes browser to go back.
21+
* [#11183](http://dev.ckeditor.com/ticket/11183): Fixed: Inserting line or table in multiple rows selection causes browser crash. Additionally, the [`editor.insertElement`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertElement) method does not insert element into every range of a selection any more.
2122

2223

2324
## CKEditor 4.3

core/editable.js

Lines changed: 117 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,13 @@
263263
// Remove the original contents, merge split nodes.
264264
range.deleteContents( 1 );
265265

266+
// If range is placed in inermediate element (not td or th), we need to do three things:
267+
// * fill emptied <td/th>s with if browser needs them,
268+
// * remove empty text nodes so IE8 won't crash (http://dev.ckeditor.com/ticket/11183#comment:8),
269+
// * fix structure and move range into the <td/th> element.
270+
if ( range.startContainer.type == CKEDITOR.NODE_ELEMENT && range.startContainer.is( { tr:1,table:1,tbody:1,thead:1,tfoot:1 } ) )
271+
fixTableAfterContentsDeletion( range );
272+
266273
// If we're inserting a block at dtd-violated position, split
267274
// the parent blocks until we reach blockLimit.
268275
var current, dtd;
@@ -303,48 +310,32 @@
303310
var editor = this.editor,
304311
enterMode = editor.activeEnterMode,
305312
selection = editor.getSelection(),
306-
ranges = selection.getRanges(),
313+
range = selection.getRanges()[ 0 ],
307314
elementName = element.getName(),
308-
isBlock = CKEDITOR.dtd.$block[ elementName ],
309-
clone, lastElement, range;
315+
isBlock = CKEDITOR.dtd.$block[ elementName ];
310316

311317
// Prepare for the insertion.
312318
beforeInsert( this );
313319

314-
// Insert the element into all ranges by cloning.
315-
for ( var i = ranges.length; i--; ) {
316-
range = ranges[ i ];
317-
318-
// Clone is an element for the first range.
319-
clone = !i && element || element.clone( 1 );
320-
321-
// Put the clone into a particular range.
322-
// Save the last **successfully inserted** element reference
323-
// so we can make the selection later.
324-
if ( this.insertElementIntoRange( clone, range ) && !lastElement )
325-
lastElement = clone;
326-
}
327-
328-
if ( lastElement ) {
329-
range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END );
320+
// Insert element into first range only and ignore the rest (#11183).
321+
if ( this.insertElementIntoRange( element, range ) ) {
322+
range.moveToPosition( element, CKEDITOR.POSITION_AFTER_END );
330323

331324
// If we're inserting a block element, the new cursor position must be
332325
// optimized. (#3100,#5436,#8950)
333326
if ( isBlock ) {
334-
335327
// Find next, meaningful element.
336-
var next = lastElement.getNext( function( node ) {
328+
var next = element.getNext( function( node ) {
337329
return isNotEmpty( node ) && !isBogus( node );
338330
} );
339331

340332
if ( next && next.type == CKEDITOR.NODE_ELEMENT && next.is( CKEDITOR.dtd.$block ) ) {
341-
342333
// If the next one is a text block, move cursor to the start of it's content.
343334
if ( next.getDtd()[ '#' ] )
344335
range.moveToElementEditStart( next );
345336
// Otherwise move cursor to the before end of the last element.
346337
else
347-
range.moveToElementEditEnd( lastElement );
338+
range.moveToElementEditEnd( element );
348339
}
349340
// Open a new line if the block is inserted at the end of parent.
350341
else if ( !next && enterMode != CKEDITOR.ENTER_BR ) {
@@ -1810,6 +1801,109 @@
18101801
}, 0 );
18111802
}
18121803

1804+
// 1. Fixes a range which is a result of deleteContents() and is placed in an intermediate element (see dtd.$intermediate),
1805+
// inside a table. A goal is to find a closest <td> or <th> element and when this fails, recreate the structure of the table.
1806+
// 2. Fixes empty cells by appending bogus <br>s or deleting empty text nodes in IE<=8 case.
1807+
var fixTableAfterContentsDeletion = (function() {
1808+
// Creates an element walker which can only "go deeper". It won't
1809+
// move out from any element. Therefore it can be used to find <td>x</td> in cases like:
1810+
// <table><tbody><tr><td>x</td></tr></tbody>^<tfoot>...
1811+
function getFixTableSelectionWalker( testRange ) {
1812+
var walker = new CKEDITOR.dom.walker( testRange );
1813+
walker.guard = function( node, isMovingOut ) {
1814+
if ( isMovingOut )
1815+
return false;
1816+
if ( node.type == CKEDITOR.NODE_ELEMENT )
1817+
return node.is( CKEDITOR.dtd.$tableContent );
1818+
};
1819+
walker.evaluator = function( node ) {
1820+
return node.type == CKEDITOR.NODE_ELEMENT;
1821+
};
1822+
1823+
return walker;
1824+
}
1825+
1826+
function fixTableStructure( element, newElementName, appendToStart ) {
1827+
var temp = element.getDocument().createElement( newElementName );
1828+
element.append( temp, appendToStart );
1829+
return temp;
1830+
}
1831+
1832+
// Fix empty cells. This means:
1833+
// * add bogus <br> if browser needs it
1834+
// * remove empty text nodes on IE8, because it will crash (http://dev.ckeditor.com/ticket/11183#comment:8).
1835+
function fixEmptyCells( cells ) {
1836+
var i = cells.count(),
1837+
cell;
1838+
1839+
for ( i; i-- > 0; ) {
1840+
cell = cells.getItem( i );
1841+
1842+
if ( !CKEDITOR.tools.trim( cell.getHtml() ) ) {
1843+
cell.appendBogus();
1844+
if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 && cell.getChildCount() )
1845+
cell.getFirst().remove();
1846+
}
1847+
}
1848+
}
1849+
1850+
return function( range ) {
1851+
var container = range.startContainer,
1852+
table = container.getAscendant( 'table', 1 ),
1853+
testRange,
1854+
walker,
1855+
deeperSibling,
1856+
doc = range.document,
1857+
appendToStart = false;
1858+
1859+
fixEmptyCells( table.getElementsByTag( 'td' ) );
1860+
fixEmptyCells( table.getElementsByTag( 'th' ) );
1861+
1862+
// Look left.
1863+
testRange = range.clone();
1864+
testRange.setStart( container, 0 );
1865+
deeperSibling = getFixTableSelectionWalker( testRange ).lastBackward();
1866+
1867+
// If left is empty, look right.
1868+
if ( !deeperSibling ) {
1869+
testRange = range.clone();
1870+
testRange.setEndAt( container, CKEDITOR.POSITION_BEFORE_END );
1871+
deeperSibling = getFixTableSelectionWalker( testRange ).lastForward();
1872+
appendToStart = true;
1873+
}
1874+
1875+
// If there's no deeper nested element in both direction - container is empty - we'll use it then.
1876+
if ( !deeperSibling )
1877+
deeperSibling = container;
1878+
1879+
// Fix structure...
1880+
1881+
// We found a table what means that it's empty - remove it completely.
1882+
if ( deeperSibling.is( 'table' ) ) {
1883+
range.setStartAt( deeperSibling, CKEDITOR.POSITION_BEFORE_START );
1884+
range.collapse( true );
1885+
deeperSibling.remove();
1886+
return;
1887+
}
1888+
1889+
// Found an empty txxx element - append tr.
1890+
if ( deeperSibling.is( { tbody:1,thead:1,tfoot:1 } ) )
1891+
deeperSibling = fixTableStructure( deeperSibling, 'tr', appendToStart );
1892+
1893+
// Found an empty tr element - append td/th.
1894+
if ( deeperSibling.is( 'tr' ) )
1895+
deeperSibling = fixTableStructure( deeperSibling, deeperSibling.getParent().is( 'thead' ) ? 'th' : 'td', appendToStart );
1896+
1897+
// To avoid setting selection after bogus, remove it from the current cell.
1898+
// We can safely do that, because we'll insert element into that cell.
1899+
var bogus = deeperSibling.getBogus();
1900+
if ( bogus )
1901+
bogus.remove();
1902+
1903+
range.moveToPosition( deeperSibling, appendToStart ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_BEFORE_END );
1904+
}
1905+
})();
1906+
18131907
})();
18141908

18151909
/**

0 commit comments

Comments
 (0)