/**
* @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
import DowncastWriter from '../../../src/view/downcastwriter';
import Range from '../../../src/view/range';
import { stringify, parse } from '../../../src/dev-utils/view';
import ContainerElement from '../../../src/view/containerelement';
import AttributeElement from '../../../src/view/attributeelement';
import EmptyElement from '../../../src/view/emptyelement';
import UIElement from '../../../src/view/uielement';
import Document from '../../../src/view/document';
import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
import { StylesProcessor } from '../../../src/view/stylesmap';
describe( 'DowncastWriter', () => {
describe( 'clear()', () => {
let writer, document;
// Executes test using `parse` and `stringify` utils functions. Uses range delimiters `[]{}` to create ranges.
//
// @param {Object} elementToRemove
// @param {String} input
// @param {String} expectedResult
function testDowncast( elementToRemove, input, expectedResult ) {
const { view, selection } = parse( input );
writer.clear( selection.getFirstRange(), elementToRemove );
expect( stringify( view, null, { showType: true } ) ).to.equal( expectedResult );
}
beforeEach( () => {
document = new Document( new StylesProcessor() );
writer = new DowncastWriter( document );
} );
it( 'should throw when range placed in two containers', () => {
const p1 = new ContainerElement( document, 'p' );
const p2 = new ContainerElement( document, 'p' );
expectToThrowCKEditorError( () => {
writer.clear( Range._createFromParentsAndOffsets( p1, 0, p2, 0 ) );
}, 'view-writer-invalid-range-container', document );
} );
it( 'should throw when range has no parent container', () => {
const el = new AttributeElement( document, 'b' );
expectToThrowCKEditorError( () => {
writer.clear( Range._createFromParentsAndOffsets( el, 0, el, 0 ) );
}, 'view-writer-invalid-range-container', document );
} );
it( 'should remove matched element from range', () => {
const elementToRemove = new AttributeElement( document, 'b' );
testDowncast(
elementToRemove,
'[bar]',
'br'
);
} );
it( 'should remove matched element from range when range is inside text node', () => {
const elementToRemove = new AttributeElement( document, 'b' );
testDowncast(
elementToRemove,
'F{oo ba}r',
'Fo bar'
);
} );
it( 'should remove multiple matched elements from range', () => {
const elementToRemove = new AttributeElement( document, 'b' );
testDowncast(
elementToRemove,
'[Foo bar]',
'Fo br'
);
} );
it( 'should remove multiple matched elements from range when range is inside text node', () => {
const elementToRemove = new AttributeElement( document, 'b' );
testDowncast(
elementToRemove,
'F{oo ba}r',
'Fo ar'
);
} );
it( 'should remove only matched element', () => {
const elementToRemove = new AttributeElement( document, 'b' );
testDowncast(
elementToRemove,
'F{oo ba}r',
'Foo ar'
);
} );
it( 'should remove part of node when range ends inside this node', () => {
const elementToRemove = new AttributeElement( document, 'b' );
testDowncast(
elementToRemove,
'f{ooba}r',
'foor'
);
} );
it( 'should remove part of node when range starts inside this node', () => {
const elementToRemove = new AttributeElement( document, 'b' );
testDowncast(
elementToRemove,
'foob{arbi}z',
'foobbiz'
);
} );
it( 'should remove part of node when range starts and ends inside this node', () => {
const elementToRemove = new AttributeElement( document, 'b' );
testDowncast(
elementToRemove,
'foob{a}rbiz',
'foobrbiz'
);
} );
it( 'should merge after removing', () => {
const elementToRemove = new AttributeElement( document, 'b' );
testDowncast(
elementToRemove,
'' +
'fo{oab}iz' +
'',
'foobiz'
);
} );
it( 'should remove EmptyElement', () => {
const elementToRemove = new EmptyElement( document, 'img' );
testDowncast(
elementToRemove,
'f{ooba}r',
'foobar'
);
} );
it( 'should remove UIElement', () => {
const elementToRemove = new UIElement( document, 'span' );
testDowncast(
elementToRemove,
'f{ooba}r',
'foobar'
);
} );
it( 'should remove ContainerElement', () => {
const elementToRemove = new ContainerElement( document, 'p' );
testDowncast(
elementToRemove,
'[foobarbiz]',
'foobiz'
);
} );
} );
} );