/**
* @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', attributes: [ 'bold', 'italic' ] } );
schema.allow( { name: 'p', attributes: [ 'align' ] } );
} );
describe( 'deleteContents', () => {
describe( 'in simple scenarios', () => {
test(
'does nothing on collapsed selection',
'foo',
'foo'
);
test(
'deletes single character',
'foo',
'fo'
);
test(
'xdeletes single character (backward selection)',
'foo',
'fo'
);
test(
'deletes whole text',
'foo',
''
);
test(
'deletes whole text between nodes',
'
foo
',
'![]()
'
);
test(
'deletes an element',
'x
y',
'xy'
);
test(
'deletes a bunch of nodes',
'wx
yz',
'wz'
);
test(
'does not break things when option.merge passed',
'wx
yz',
'wz',
{ merge: true }
);
} );
describe( 'with text attributes', () => {
test(
'deletes characters (first half has attrs)',
'<$text bold=true>foo$text>bar',
'<$text bold=true>fo$text>ar'
);
test(
'deletes characters (2nd half has attrs)',
'foo<$text bold=true>bar$text>',
'fo<$text bold=true>ar$text>'
);
test(
'clears selection attrs when emptied content',
'
x
<$text bold=true>foo$text>
y
',
'x
y
'
);
test(
'leaves selection attributes when text contains them',
'x<$text bold=true>afoob$text>y
',
'x<$text bold=true>ab$text>y
'
);
} );
// 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 like .
// Those case should, again, be handled by their specific implementations.
describe( 'in multi-element scenarios', () => {
test(
'do not merge when no need to',
' x foo y ',
'x
y ',
{ merge: true }
);
test(
'merges second element into the first one (same name)',
'x foo bar y ',
'x foar y ',
{ merge: true }
);
test(
'does not merge second element into the first one (same name, !option.merge)',
'x foo bar y ',
'x fo ar y '
);
test(
'merges second element into the first one (same name)',
'x foo bar y ',
'x foar y ',
{ merge: true }
);
test(
'merges second element into the first one (different name)',
'x foobar y ',
'x foary ',
{ merge: true }
);
test(
'merges second element into the first one (different name, backward selection)',
'x foobar y ',
'x foary ',
{ merge: true }
);
test(
'merges second element into the first one (different attrs)',
'x foo bar y ',
'x foar y ',
{ merge: true }
);
test(
'merges second element to an empty first element',
'x
foo y ',
'x oy ',
{ merge: true }
);
test(
'merges elements when deep nested',
'xfoo bary ',
'xfoary ',
{ merge: true }
);
// For code coverage reasons.
test(
'merges element when selection is in two consecutive nodes even when it is empty',
'foo bar ',
'foobar ',
{ merge: true }
);
// If you disagree with this case please read the notes before this section.
test(
'merges elements when left end deep nested',
'xfoo bary ',
'xfoary ',
{ merge: true }
);
// If you disagree with this case please read the notes before this section.
test(
'merges elements when right end deep nested',
'xfoo bary![]() ',
'xfoary![]() ',
{ merge: true }
);
test(
'merges elements when more content in the right branch',
'xfoo bary ',
'xfoary ',
{ merge: true }
);
test(
'leaves just one element when all selected',
'xfoo y ',
'',
{ merge: true }
);
} );
function test( title, input, output, options ) {
it( title, () => {
setData( document, input );
deleteContents( document.batch(), document.selection, options );
expect( getData( document ) ).to.equal( output );
} );
}
} );
} );
|