/** * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md. */ /* bender-tags: model, composer */ import Document from '/ckeditor5/engine/model/document.js'; import Selection from '/ckeditor5/engine/model/selection.js'; import modifySelection from '/ckeditor5/engine/model/composer/modifyselection.js'; import { setData, stringify } from '/tests/engine/_utils/model.js'; describe( 'Delete utils', () => { let document; beforeEach( () => { document = new Document(); document.schema.registerItem( 'p', '$block' ); document.schema.registerItem( 'x', '$block' ); document.schema.registerItem( 'img', '$inline' ); document.schema.allow( { name: '$text', inside: '$root' } ); document.createRoot(); } ); describe( 'modifySelection', () => { describe( 'unit=character', () => { describe( 'within element', () => { test( 'does nothing on empty content', '[]', '[]' ); test( 'does nothing on empty content (with empty element)', '

[]

', '

[]

' ); test( 'does nothing on empty content (backward)', '[]', '[]', { direction: 'backward' } ); test( 'does nothing on root boundary', '

foo[]

', '

foo[]

' ); test( 'does nothing on root boundary (backward)', '

[]foo

', '

[]foo

', { direction: 'backward' } ); test( 'extends one character forward', '

f[]oo

', '

f[o]o

' ); it( 'extends one character backward', () => { setData( document, '

fo[]o

', { lastRangeBackward: true } ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

f[o]o

' ); expect( document.selection.isBackward ).to.true; } ); test( 'extends one character forward (non-collapsed)', '

f[o]obar

', '

f[oo]bar

' ); it( 'extends one character backward (non-collapsed)', () => { setData( document, '

foob[a]r

', { lastRangeBackward: true } ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

foo[ba]r

' ); expect( document.selection.isBackward ).to.true; } ); test( 'extends to element boundary', '

fo[]o

', '

fo[o]

' ); it( 'extends to element boundary (backward)', () => { setData( document, '

f[]oo

' ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

[f]oo

' ); expect( document.selection.isBackward ).to.true; } ); test( 'shrinks forward selection (to collapsed)', '

foo[b]ar

', '

foo[]bar

', { direction: 'backward' } ); it( 'shrinks backward selection (to collapsed)', () => { setData( document, '

foo[b]ar

', { lastRangeBackward: true } ); modifySelection( document.selection ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

foob[]ar

' ); expect( document.selection.isBackward ).to.false; } ); test( 'extends one element forward', '

f[]oo

', '

f[]oo

' ); test( 'extends one non-empty element forward', '

f[]xoo

', '

f[x]oo

' ); it( 'extends one element backward', () => { setData( document, '

fo[]o

' ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

fo[]o

' ); expect( document.selection.isBackward ).to.true; } ); test( 'unicode support - combining mark forward', '

foo[]b̂ar

', '

foo[b̂]ar

' ); it( 'unicode support - combining mark backward', () => { setData( document, '

foob̂[]ar

' ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

foo[b̂]ar

' ); expect( document.selection.isBackward ).to.true; } ); test( 'unicode support - combining mark multiple', '

fo[]o̻̐ͩbar

', '

fo[o̻̐ͩ]bar

' ); it( 'unicode support - combining mark multiple backward', () => { setData( document, '

foo̻̐ͩ[]bar

' ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

fo[o̻̐ͩ]bar

' ); expect( document.selection.isBackward ).to.true; } ); test( 'unicode support - combining mark to the end', '

fo[]o̻̐ͩ

', '

fo[o̻̐ͩ]

' ); test( 'unicode support - surrogate pairs forward', '

[]\uD83D\uDCA9

', '

[\uD83D\uDCA9]

' ); it( 'unicode support - surrogate pairs backward', () => { setData( document, '

\uD83D\uDCA9[]

' ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

[\uD83D\uDCA9]

' ); expect( document.selection.isBackward ).to.true; } ); } ); describe( 'beyond element', () => { test( 'extends over boundary of empty elements', '

[]

', '

[

]

' ); it( 'extends over boundary of empty elements (backward)', () => { setData( document, '

[]

' ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

[

]

' ); expect( document.selection.isBackward ).to.true; } ); test( 'extends over boundary of non-empty elements', '

a[]

bcd

', '

a[

]bcd

' ); it( 'extends over boundary of non-empty elements (backward)', () => { setData( document, '

a

[]bcd

' ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

a[

]bcd

' ); expect( document.selection.isBackward ).to.true; } ); test( 'extends over character after boundary', '

a[

]bcd

', '

a[

b]cd

' ); it( 'extends over character after boundary (backward)', () => { setData( document, '

abc[

]d

', { lastRangeBackward: true } ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

ab[c

]d

' ); expect( document.selection.isBackward ).to.true; } ); test( 'extends over boundary when next element has nested elements', '

a[]

bcd

', '

a[

]bcd

' ); test( 'extends over element when next element has nested elements', '

a[

]bcdef

', '

a[

bcd]ef

' ); test( 'extends over element when next node is a text', '

a[]

bc', '

a[

]bc' ); it( 'extends over element when next node is a text (backward)', () => { setData( document, 'ab

[]c

' ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( 'ab[

]c

' ); expect( document.selection.isBackward ).to.true; } ); it( 'shrinks over boundary of empty elements', () => { setData( document, '

[

]

', { lastRangeBackward: true } ); modifySelection( document.selection ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

[]

' ); expect( document.selection.isBackward ).to.false; } ); it( 'shrinks over boundary of empty elements (backward)', () => { setData( document, '

[

]

' ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

[]

' ); expect( document.selection.isBackward ).to.false; } ); it( 'shrinks over boundary of non-empty elements', () => { setData( document, '

a[

]b

', { lastRangeBackward: true } ); modifySelection( document.selection ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

a

[]b

' ); expect( document.selection.isBackward ).to.false; } ); test( 'shrinks over boundary of non-empty elements (backward)', '

a[

]b

', '

a[]

b

', { direction: 'backward' } ); it( 'updates selection attributes', () => { setData( document, '

<$text bold="true">foo[b]

' ); modifySelection( document.selection, { direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

<$text bold="true">foo[]b

' ); expect( document.selection.getAttribute( 'bold' ) ).to.equal( true ); } ); } ); } ); describe( 'unit=codePoint', () => { test( 'does nothing on empty content', '[]', '[]', { unit: 'codePoint' } ); test( 'does nothing on empty content (with empty element)', '

[]

', '

[]

', { unit: 'codePoint' } ); test( 'extends one user-perceived character forward - latin letters', '

f[]oo

', '

f[o]o

', { unit: 'codePoint' } ); it( 'extends one user-perceived character backward - latin letters', () => { setData( document, '

fo[]o

' ); modifySelection( document.selection, { unit: 'codePoint', direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

f[o]o

' ); expect( document.selection.isBackward ).to.true; } ); test( 'unicode support - combining mark forward', '

foo[]b̂ar

', '

foo[b]̂ar

', { unit: 'codePoint' } ); it( 'unicode support - combining mark backward', () => { setData( document, '

foob̂[]ar

' ); // Creating new instance of selection instead of operation on engine.model.Document#selection. // Document's selection will throw errors in some test cases (which are correct cases, but only for // non-document selections). const testSelection = Selection.createFromSelection( document.selection ); modifySelection( testSelection, { unit: 'codePoint', direction: 'backward' } ); expect( stringify( document.getRoot(), testSelection ) ).to.equal( '

foob[̂]ar

' ); expect( testSelection.isBackward ).to.true; } ); test( 'unicode support - combining mark multiple', '

fo[]o̻̐ͩbar

', '

fo[o]̻̐ͩbar

', { unit: 'codePoint' } ); test( 'unicode support - surrogate pairs forward', '

[]\uD83D\uDCA9

', '

[\uD83D\uDCA9]

', { unit: 'codePoint' } ); it( 'unicode support surrogate pairs backward', () => { setData( document, '

\uD83D\uDCA9[]

' ); modifySelection( document.selection, { unit: 'codePoint', direction: 'backward' } ); expect( stringify( document.getRoot(), document.selection ) ).to.equal( '

[\uD83D\uDCA9]

' ); expect( document.selection.isBackward ).to.true; } ); } ); } ); function test( title, input, output, options ) { it( title, () => { input = input.normalize(); output = output.normalize(); setData( document, input ); // Creating new instance of selection instead of operation on engine.model.Document#selection. // Document's selection will throw errors in some test cases (which are correct cases, but only for // non-document selections). const testSelection = Selection.createFromSelection( document.selection ); modifySelection( testSelection, options ); expect( stringify( document.getRoot(), testSelection ) ).to.equal( output ); } ); } } );