/**
* @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 deleteContents from '/ckeditor5/engine/model/composer/deletecontents.js';
import { setData, getData } from '/tests/engine/_utils/model.js';
describe( 'Delete utils', () => {
let document;
beforeEach( () => {
document = new Document();
document.createRoot();
const schema = document.schema;
// Note: We used short names instead of "image", "paragraph", etc. to make the tests shorter.
// We could use any random names in fact, but using HTML tags may explain the tests a bit better.
schema.registerItem( 'img', '$inline' );
schema.registerItem( 'p', '$block' );
schema.registerItem( 'h1', '$block' );
schema.registerItem( 'pchild' );
schema.allow( { name: 'pchild', inside: 'p' } );
schema.allow( { name: '$text', inside: '$root' } );
schema.allow( { name: 'img', inside: '$root' } );
schema.allow( { name: '$text', attributes: [ 'bold', 'italic' ] } );
schema.allow( { name: 'p', attributes: [ 'align' ] } );
} );
describe( 'deleteContents', () => {
describe( 'in simple scenarios', () => {
test(
'does nothing on collapsed selection',
'f[]oo',
'f[]oo'
);
test(
'deletes single character',
'f[o]o',
'f[]o'
);
it( 'deletes single character (backward selection)' , () => {
setData( document, 'f[o]o', { lastRangeBackward: true } );
deleteContents( document.batch(), document.selection );
expect( getData( document ) ).to.equal( 'f[]o' );
} );
test(
'deletes whole text',
'[foo]',
'[]'
);
test(
'deletes whole text between nodes',
'[foo]
',
'
[]
'
);
test(
'deletes an element',
'x[
]y',
'x[]y'
);
test(
'deletes a bunch of nodes',
'w[x
y]z',
'w[]z'
);
test(
'does not break things when option.merge passed',
'w[x
y]z',
'w[]z',
{ merge: true }
);
} );
describe( 'with text attributes', () => {
it( 'deletes characters (first half has attrs)', () => {
setData( document, '<$text bold="true">fo[o$text>b]ar', { selectionAttributes: {
bold: true
} } );
deleteContents( document.batch(), document.selection );
expect( getData( document ) ).to.equal( '<$text bold="true">fo[]$text>ar' );
expect( document.selection.getAttribute( 'bold' ) ).to.equal( true );
} );
it( 'deletes characters (2nd half has attrs)', () => {
setData( document, 'fo[o<$text bold="true">b]ar$text>', { selectionAttributes: {
bold: true
} } );
deleteContents( document.batch(), document.selection );
expect( getData( document ) ).to.equal( 'fo[]<$text bold="true">ar$text>' );
expect( document.selection.getAttribute( 'bold' ) ).to.undefined;
} );
it( 'clears selection attrs when emptied content', () => {
setData( document, '
x
[<$text bold="true">foo$text>]
y
', { selectionAttributes: { bold: true } } ); deleteContents( document.batch(), document.selection ); expect( getData( document ) ).to.equal( 'x
[]
y
' ); expect( document.selection.getAttribute( 'bold' ) ).to.undefined; } ); it( 'leaves selection attributes when text contains them', () => { setData( document, 'x<$text bold="true">a[foo]b$text>y
', { selectionAttributes: { bold: true } } ); deleteContents( document.batch(), document.selection ); expect( getData( document ) ).to.equal( 'x<$text bold="true">a[]b$text>y
' ); expect( document.selection.getAttribute( 'bold' ) ).to.equal( true ); } ); } ); // Note: The algorithm does not care what kind of it's merging as it knows nothing useful about these elements. // In most cases it handles all elements like you'd expect to handle block elements in HTML. However, // in some scenarios where the tree depth is bigger results may be hard to justify. In fact, such cases // should not happen unless we're talking about lists or tables, but these features will need to cover // their scenarios themselves. In all generic scenarios elements are never nested. // // You may also be thinking – but I don't want my elements to be merged. It means that there are some special rules, // like – multiple editing hosts (cE=true/false in use) or block limit elements likex
[foo]
y
', 'x
[]
y
', { merge: true } ); test( 'merges second element into the first one (same name)', 'x
fo[o
b]ar
y
', 'x
fo[]ar
y
', { merge: true } ); test( 'does not merge second element into the first one (same name, !option.merge)', 'x
fo[o
b]ar
y
', 'x
fo[]
ar
y
' ); test( 'merges second element into the first one (same name)', 'x
fo[o
b]ar
y
', 'x
fo[]ar
y
', { merge: true } ); test( 'merges second element into the first one (different name)', 'x
b]ar
y
', 'x
y
', { merge: true } ); it( 'merges second element into the first one (different name, backward selection)', () => { setData( document, 'x
b]ar
y
', { lastRangeBackward: true } ); deleteContents( document.batch(), document.selection, { merge: true } ); expect( getData( document ) ).to.equal( 'x
y
' ); } ); test( 'merges second element into the first one (different attrs)', 'x
fo[o
b]ar
y
', 'x
fo[]ar
y
', { merge: true } ); test( 'merges second element to an empty first element', 'x
fo]o
y
', 'x
y
', { merge: true } ); test( 'merges elements when deep nested', 'x
x
foo[
]bar
', 'foo[]bar
', { merge: true } ); // If you disagree with this case please read the notes before this section. test( 'merges elements when left end deep nested', 'x
b]ary
', 'x
xfo[o
xfo[]
xfo[o
b]a
xfo[]a
foo
y]
', '