Skip to content

Commit bf96388

Browse files
committed
We must shrink range when at outer boundaries or not a path block boundary.
1 parent 306d4aa commit bf96388

File tree

2 files changed

+128
-21
lines changed

2 files changed

+128
-21
lines changed

core/dom/iterator.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,10 +361,40 @@
361361
function startIterator() {
362362
var range = this.range.clone(),
363363
// Indicate at least one of the range boundaries is inside a preformat block.
364-
touchPre;
364+
touchPre,
365+
startPath,
366+
endPath,
367+
startAtInnerBoundary,
368+
endAtInnerBoundary,
369+
testRange;
370+
371+
// Remember if following situation takes place:
372+
// * startAtInnerBoundary: <p>foo[</p>...
373+
// * endAtInnerBoundary: ...<p>]bar</p>
374+
// Because information about line break will be lost when shrinking range.
375+
// Note that we test only if path block exist, because we must properly shrink
376+
// range containing table and/or table cells.
377+
// (#12178)
378+
startPath = range.startPath();
379+
if ( startPath.block ) {
380+
testRange = range.clone();
381+
testRange.collapse( true );
382+
startAtInnerBoundary = testRange.checkBoundaryOfElement( startPath.block, CKEDITOR.END );
383+
}
384+
endPath = range.endPath();
385+
if ( endPath.block ) {
386+
testRange = range.clone();
387+
testRange.collapse();
388+
endAtInnerBoundary = testRange.checkBoundaryOfElement( endPath.block, CKEDITOR.START );
389+
}
365390

366391
// Shrink the range to exclude harmful "noises" (#4087, #4450, #5435).
367-
range.shrink( CKEDITOR.SHRINK_ELEMENT, true, false );
392+
range.shrink( CKEDITOR.SHRINK_ELEMENT, true );
393+
394+
if ( startAtInnerBoundary )
395+
range.setStartAt( startPath.block, CKEDITOR.POSITION_BEFORE_END );
396+
if ( endAtInnerBoundary )
397+
range.setEndAt( endPath.block, CKEDITOR.POSITION_AFTER_START );
368398

369399
touchPre = range.endContainer.hasAscendant( 'pre', true ) || range.startContainer.hasAscendant( 'pre', true );
370400

tests/core/dom/iterator.js

Lines changed: 96 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ function iterateScopedRange( html, opt ) {
4646
return { html: tools.compatHtml( sandbox.getOuterHtml() ), list: results };
4747
}
4848

49+
function iterateWithRangeIterator( ranges, mergeConsequent, rangeIteratorOpts ) {
50+
var rangesIterator = ranges.createIterator(),
51+
range,
52+
blockList = [];
53+
54+
while ( range = rangesIterator.getNextRange( mergeConsequent ) ) {
55+
var iter = range.createIterator(), block;
56+
CKEDITOR.tools.extend( iter, rangeIteratorOpts, true );
57+
while ( ( block = iter.getNextParagraph() ) )
58+
blockList.push( block.getName() );
59+
}
60+
61+
return blockList;
62+
}
63+
4964
function checkActiveFilter( source, opt, results, msg ) {
5065
var sandbox = doc.getById( 'sandbox' );
5166
var range = tools.setHtmlWithRange( sandbox, source )[ 0 ];
@@ -96,14 +111,13 @@ bender.test( {
96111
if ( !CKEDITOR.env.needsBrFiller )
97112
assert.ignore();
98113

99-
var source = '<h1>para1[<br /></h1><p>para2]</p>';
114+
var source = '<h1>para1[<br /></h1><p>par]a2</p>';
100115
checkRangeIteration( source, null, [ 'h1', 'p' ], null, 'Iteration will yield heading and paragraph.' );
101116
},
102117

103118
// #12178
104-
// This case may happen on Webkit/Blink.
105119
'test iterating over end of line - no bogus br': function() {
106-
var source = '<h1>para1[</h1><p>para2]</p>';
120+
var source = '<h1>para1[</h1><p>par]a2</p>';
107121
checkRangeIteration( source, null, [ 'h1', 'p' ], null, 'Iteration will yield heading and paragraph.' );
108122
},
109123

@@ -112,17 +126,32 @@ bender.test( {
112126
if ( !CKEDITOR.env.needsBrFiller )
113127
assert.ignore();
114128

115-
var source = '<h1>[para1<br /></h1><p>]para2</p>';
129+
var source = '<h1>pa[ra1<br /></h1><p>]para2</p>';
116130
checkRangeIteration( source, null, [ 'h1', 'p' ], null, 'Iteration will yield heading and paragraph.' );
117131
},
118132

119133
// #12178
120-
// This case may happen on Webkit/Blink.
121134
'test iterating over start of line - no bogus br': function() {
122-
var source = '<h1>[para1</h1><p>]para2</p>';
135+
var source = '<h1>pa[ra1</h1><p>]para2</p>';
136+
checkRangeIteration( source, null, [ 'h1', 'p' ], null, 'Iteration will yield heading and paragraph.' );
137+
},
138+
139+
// #12178
140+
'test iterating over start of line 2 - no bogus br': function() {
141+
var source = '<h1>pa[ra1</h1><p><b>]para2</b></p>';
123142
checkRangeIteration( source, null, [ 'h1', 'p' ], null, 'Iteration will yield heading and paragraph.' );
124143
},
125144

145+
// #12178
146+
'test iterating over start of line 2 - no bogus br - rangeIterator': function() {
147+
var source = '<h1>pa[ra1</h1><p><b>]para2</b></p>';
148+
149+
var sandbox = doc.getById( 'sandbox' ),
150+
ranges = tools.setHtmlWithRange( sandbox, source );
151+
152+
assert.areSame( 'h1,p', iterateWithRangeIterator( ranges ).join( ',' ) );
153+
},
154+
126155
'test iterating over pseudo block': function() {
127156
var source = '<div><p>[paragraph</p>text]</div>';
128157
var output = '<div><p>paragraph</p><p>text</p></div>';
@@ -171,31 +200,79 @@ bender.test( {
171200
},
172201

173202
// #6728, #4450
203+
// While this test may seem to be totally broken (why would someone create bookmakrs between <tr> and <td>?)
204+
// it has a deeper sense. It tests what rangeIterator#getNextRange does.
174205
'test iterating over table cells (with bookmarks among cells)': function() {
175206
var source = '<table><tbody><tr>[<td id="cell1">cell1</td>][<td id="cell2">cell2</td>]</tr></tbody></table>',
176207
output = source.replace( /\[|\]|\^/g, '' );
177208

178-
var sandbox = doc.getById( 'sandbox' );
179-
var ranges = tools.setHtmlWithRange( sandbox, source );
209+
var sandbox = doc.getById( 'sandbox' ),
210+
ranges = tools.setHtmlWithRange( sandbox, source );
180211

181-
// Create bookmarks by intention.
212+
// Create bookmarks intentionally.
182213
var bms = ranges.createBookmarks();
183214

184-
// Check iteration sequence.
185-
var rangeIterator = ranges.createIterator(), range, blockList = [];
186-
// Merge multiple ranges.
187-
while ( range = rangeIterator.getNextRange( true ) ) {
188-
var iter = range.createIterator(), block;
189-
while ( ( block = iter.getNextParagraph() ) )
190-
blockList.push( block.getName() );
191-
}
215+
assert.areSame( 'td,td', iterateWithRangeIterator( ranges ).join( ',' ), true );
216+
217+
// Just to remove bookmarks.
218+
ranges.moveToBookmarks( bms );
219+
220+
assert.areSame( tools.compatHtml( output ), tools.compatHtml( sandbox.getHtml() ) );
221+
},
222+
223+
// See above an explanation of this test.
224+
'test iterating over table cells (with bookmarks among cells) - do not merge subsequent ranges': function() {
225+
var source = '<table><tbody><tr>[<td id="cell1">cell1</td>][<td id="cell2">cell2</td>]</tr></tbody></table>',
226+
output = source.replace( /\[|\]|\^/g, '' );
227+
228+
var sandbox = doc.getById( 'sandbox' ),
229+
ranges = tools.setHtmlWithRange( sandbox, source );
192230

193-
assert.areSame( 'td,td', blockList.join( ',' ) );
231+
// Create bookmarks intentionally.
232+
var bms = ranges.createBookmarks();
233+
234+
assert.areSame( 'td,td', iterateWithRangeIterator( ranges ).join( ',' ) );
194235

195236
// Just to remove bookmarks.
196237
ranges.moveToBookmarks( bms );
197238

198-
assert.areSame( tools.compatHtml( output ) , tools.compatHtml( sandbox.getHtml() ) );
239+
assert.areSame( output, tools.compatHtml( sandbox.getHtml() ) );
240+
},
241+
242+
// #6728, #4450
243+
'test iterating over entire table': function() {
244+
var source = '[<table><tbody><tr><th>cell1</th><td>cell2</td></tr></tbody></table>]',
245+
output1 = source.replace( /\[|\]|\^/g, '' ),
246+
output2 = '<table><tbody><tr><th><p>cell1</p></th><td><p>cell2</p></td></tr></tbody></table>';
247+
248+
checkRangeIteration( source, null, [ 'th', 'td' ], output1, 'Iteration should report table cells' );
249+
checkRangeIteration( source, { enforceRealBlocks: 1 }, [ 'p', 'p' ], output2, 'Iteration should establish paragraphs inside table cells' );
250+
},
251+
252+
// #6728, #4450
253+
'test iterating over entire table - use rangeIterator': function() {
254+
var source = '[<table><tbody><tr><th>cell1</th><td>cell2</td></tr></tbody></table>]',
255+
output = source.replace( /\[|\]|\^/g, '' );
256+
257+
var sandbox = doc.getById( 'sandbox' ),
258+
ranges = tools.setHtmlWithRange( sandbox, source );
259+
260+
assert.areSame( 'th,td', iterateWithRangeIterator( ranges, true ).join( ',' ) );
261+
262+
assert.areSame( output, tools.compatHtml( sandbox.getHtml() ) );
263+
},
264+
265+
// #6728, #4450
266+
'test iterating over entire table - use rangeIterator and enforceRealBlocks': function() {
267+
var source = '[<table><tbody><tr><th>cell1</th><td>cell2</td></tr></tbody></table>]',
268+
output = '<table><tbody><tr><th><p>cell1</p></th><td><p>cell2</p></td></tr></tbody></table>';
269+
270+
var sandbox = doc.getById( 'sandbox' ),
271+
ranges = tools.setHtmlWithRange( sandbox, source );
272+
273+
assert.areSame( 'p,p', iterateWithRangeIterator( ranges, true, { enforceRealBlocks: true } ).join( ',' ) );
274+
275+
assert.areSame( output, tools.compatHtml( sandbox.getHtml() ) );
199276
},
200277

201278
'test iterating over list items': function() {

0 commit comments

Comments
 (0)