-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13822 from ckeditor/ck/11585-fix-range-selection
Fix (engine): `Selection#getSelectedBlocks()` should ignore trailing blocks where no content is selected. The selection of such blocks is not visible to the content author and is usually there unintentionally. Closes #11585.
- Loading branch information
Showing
9 changed files
with
328 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/** | ||
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. | ||
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license | ||
*/ | ||
|
||
import Model from '../../src/model/model'; | ||
import Element from '../../src/model/element'; | ||
import Text from '../../src/model/text'; | ||
import Position from '../../src/model/position'; | ||
import LiveRange from '../../src/model/liverange'; | ||
import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; | ||
import { setData } from '../../src/dev-utils/model'; | ||
|
||
import { stringifyBlocks } from '../model/_utils/utils'; | ||
|
||
describe( '#11585', () => { | ||
let model, doc, root, liveRange; | ||
|
||
testUtils.createSinonSandbox(); | ||
|
||
beforeEach( () => { | ||
model = new Model(); | ||
doc = model.document; | ||
root = doc.createRoot(); | ||
root._appendChild( [ | ||
new Element( 'p' ), | ||
new Element( 'p' ), | ||
new Element( 'p', [], new Text( 'foobar' ) ), | ||
new Element( 'p' ), | ||
new Element( 'p' ), | ||
new Element( 'p' ), | ||
new Element( 'p', [], new Text( 'foobar' ) ) | ||
] ); | ||
|
||
liveRange = new LiveRange( new Position( root, [ 0 ] ), new Position( root, [ 1 ] ) ); | ||
|
||
model.schema.register( 'p', { inheritAllFrom: '$block' } ); | ||
model.schema.register( 'h', { inheritAllFrom: '$block' } ); | ||
|
||
model.schema.register( 'blockquote' ); | ||
model.schema.extend( 'blockquote', { allowIn: '$root' } ); | ||
model.schema.extend( '$block', { allowIn: 'blockquote' } ); | ||
|
||
model.schema.register( 'imageBlock', { | ||
allowIn: [ '$root', '$block' ], | ||
allowChildren: '$text' | ||
} ); | ||
|
||
// Special block which can contain another blocks. | ||
model.schema.register( 'nestedBlock', { inheritAllFrom: '$block' } ); | ||
model.schema.extend( 'nestedBlock', { allowIn: '$block' } ); | ||
|
||
model.schema.register( 'table', { isBlock: true, isLimit: true, isObject: true, allowIn: '$root' } ); | ||
model.schema.register( 'tableRow', { allowIn: 'table', isLimit: true } ); | ||
model.schema.register( 'tableCell', { allowIn: 'tableRow', isLimit: true, isSelectable: true } ); | ||
|
||
model.schema.extend( 'p', { allowIn: 'tableCell' } ); | ||
} ); | ||
|
||
afterEach( () => { | ||
model.destroy(); | ||
liveRange.detach(); | ||
} ); | ||
|
||
it( 'does not return the first block if none of its contents is selected', () => { | ||
setData( model, '<p>a[</p><p>b</p><p>c]</p>' ); | ||
|
||
expect( stringifyBlocks( doc.selection.getSelectedBlocks() ) ).to.deep.equal( [ 'p#b', 'p#c' ] ); | ||
} ); | ||
|
||
it( 'returns the first block if at least one of its child nodes is selected', () => { | ||
setData( model, '<p>a[<imageBlock></imageBlock></p><p>b</p><p>c]</p>' ); | ||
|
||
expect( stringifyBlocks( doc.selection.getSelectedBlocks() ) ).to.deep.equal( [ 'p#a', 'p#b', 'p#c' ] ); | ||
} ); | ||
|
||
it( 'returns the block if it has a collapsed selection at the beginning', () => { | ||
setData( model, '<p>[]a</p><p>b</p>' ); | ||
|
||
expect( stringifyBlocks( doc.selection.getSelectedBlocks() ) ).to.deep.equal( [ 'p#a' ] ); | ||
} ); | ||
|
||
it( 'returns the block if it has a collapsed selection at the end', () => { | ||
setData( model, '<p>a[]</p><p>b</p>' ); | ||
|
||
expect( stringifyBlocks( doc.selection.getSelectedBlocks() ) ).to.deep.equal( [ 'p#a' ] ); | ||
} ); | ||
|
||
it( 'does not return first and last blocks if no content is selected', () => { | ||
setData( model, '<p>a[</p><p>]b</p>' ); | ||
|
||
expect( stringifyBlocks( doc.selection.getSelectedBlocks() ) ).to.deep.equal( [] ); | ||
} ); | ||
|
||
it( 'returns the first and last blocks if no content is selected but both blocks are empty', () => { | ||
setData( model, '<p>[</p><p>]</p>' ); | ||
|
||
expect( stringifyBlocks( doc.selection.getSelectedBlocks() ) ).to.deep.equal( [ 'p', 'p' ] ); | ||
} ); | ||
} ); |
Oops, something went wrong.