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