/** * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md. */ /* bender-tags: model, composer */ 'use strict'; 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( 'main', '$root' ); 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', 'xy', 'xy' ); test( 'deletes a bunch of nodes', 'wxyz', 'wz' ); test( 'does not break things when option.merge passed', 'wxyz', 'wz', { merge: true } ); } ); describe( 'with text attributes', () => { test( 'deletes characters (first half has attrs)', '<$text bold=true>foobar', '<$text bold=true>foar' ); test( 'deletes characters (2nd half has attrs)', 'foo<$text bold=true>bar', 'fo<$text bold=true>ar' ); test( 'clears selection attrs when emptied content', '

x

<$text bold=true>foo

y

', '

x

y

' ); test( 'leaves selection attributes when text contains them', '

x<$text bold=true>afooby

', '

x<$text bold=true>aby

' ); } ); // 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

foo

bar

y

', '

x

foar

y

', { merge: true } ); test( 'merges second element into the first one (different name, backward selection)', '

x

foo

bar

y

', '

x

foar

y

', { 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

o

y

', { merge: true } ); test( 'merges elements when deep nested', '

xfoo

bary

', '

xfoary

', { 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', '

x

foo

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 ); } ); } } ); } );