/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
import BlockQuoteEditing from '../src/blockquoteediting.js';
import BlockQuoteCommand from '../src/blockquotecommand.js';
import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor.js';
import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model.js';
import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view.js';
import Command from '@ckeditor/ckeditor5-core/src/command.js';
describe( 'BlockQuoteCommand', () => {
let editor, model, command;
beforeEach( () => {
return VirtualTestEditor
.create( {
plugins: [ BlockQuoteEditing ]
} )
.then( newEditor => {
editor = newEditor;
model = editor.model;
model.schema.register( 'paragraph', { inheritAllFrom: '$block' } );
model.schema.register( 'heading', { inheritAllFrom: '$block' } );
model.schema.register( 'widget' );
model.schema.extend( 'widget', {
allowIn: '$root',
allowChildren: '$text',
isLimit: true,
isObject: true
} );
editor.conversion.for( 'downcast' ).elementToElement( { model: 'paragraph', view: 'p' } );
editor.conversion.for( 'downcast' ).elementToElement( { model: 'heading', view: 'h' } );
editor.conversion.for( 'downcast' ).elementToElement( { model: 'widget', view: 'widget' } );
command = editor.commands.get( 'blockQuote' );
} );
} );
afterEach( async () => {
await editor.destroy();
} );
it( 'is a command', () => {
expect( BlockQuoteCommand.prototype ).to.be.instanceOf( Command );
expect( command ).to.be.instanceOf( Command );
} );
describe( 'value', () => {
it( 'is false when selection is not in a block quote', () => {
setModelData( model, '
' ); expect( command ).to.have.property( 'value', false ); } ); it( 'is false when selection starts in a blockless space', () => { model.schema.extend( '$text', { allowIn: '$root' } ); setModelData( model, 'x[]x' ); expect( command ).to.have.property( 'value', false ); } ); it( 'is true when selection is in a block quote', () => { setModelData( model, 'y]y
' ); expect( command ).to.have.property( 'value', true ); } ); it( 'is true when selection starts in a block quote', () => { setModelData( model, 'x[]x
x[x
' ); expect( command ).to.have.property( 'isEnabled', true ); } ); it( 'is true when selection starts in a block which can be wrapped with blockQuote', () => { setModelData( model, 'x[]x
' + 'x[]x
abc
x{}x
def
' ); } ); it( 'should wrap multiple blocks', () => { setModelData( model, '' + '' ); expect( getViewData( editor.editing.view ) ).to.equal( 'a[bc ' + 'xx ' + 'de]f ' + '
' ); } ); it( 'should merge with an existing quote', () => { setModelData( model, 'a{bc xx
de}f
' + 'x]x yy
' + '' + 'abc ' + '[x]x ' + 'yy ' + '
abc {x}x
yy
def
' ); } ); it( 'should not merge with a quote preceding the current block', () => { setModelData( model, '' + 'abc
' + 'abc
' ); expect( getViewData( editor.editing.view ) ).to.equal( 'x[]x
' + 'abc
' ); } ); it( 'should not merge with a quote following the current block', () => { setModelData( model, 'x{}x
' ); editor.execute( 'blockQuote' ); expect( getModelData( model ) ).to.equal( 'abc
' + 'x[]x
' ); expect( getViewData( editor.editing.view ) ).to.equal( 'abc
' + 'x{}x
' ); } ); it( 'should merge with an existing quote (more blocks)', () => { setModelData( model, 'abc
' + 'x]x
' + '' + 'abc ' + 'def ' + '[x]x ' + '
abc def
{x}x
ghi
' ); } ); it( 'should not wrap non-block content', () => { setModelData( model, '' + '' + '[abc ' + '
' + '' ); // Selection incorrectly trimmed. expect( getViewData( editor.editing.view ) ).to.equal( 'de]f ' + '
[abc
' ); } ); it( 'should correctly wrap and merge groups of blocks', () => { setModelData( model, 'de}f
' + 'ghi
' + '[abc
' + 'def ghi
' ); // Selection incorrectly trimmed. expect( getViewData( editor.editing.view ) ).to.equal( 'jk]l
' + '[abc
' + 'def
ghi
' ); } ); it( 'should correctly merge a couple of subsequent quotes', () => { setModelData( model, 'jk}l
' + 'def
' + 'jkl
' + '' + 'abc ' + 'def ' + 'ghi ' + 'jkl ' + '[mn]o ' + '
x
' + '' + '' + 'abc
' + 'def
' + 'ghi
' + 'jkl
' + '{mn}o
' + '
y
' ); } ); it( 'should not wrap a block which can not be in a quote', () => { // blockQuote is allowed in root, but fooBlock can not be inside blockQuote. model.schema.register( 'fooBlock', { inheritAllFrom: '$block' } ); model.schema.addChildCheck( ( ctx, childDef ) => { if ( ctx.endsWith( 'blockQuote' ) && childDef.name == 'fooBlock' ) { return false; } } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'fooBlock', view: 'fooblock' } ); setModelData( model, '' + '' + 'abc ' + '
' + '' ); } ); it( 'should not wrap a block which parent does not allow quote inside itself', () => { // blockQuote is not be allowed in fooWrapper, but fooBlock can be inside blockQuote. model.schema.register( 'fooWrapper' ); model.schema.register( 'fooBlock', { inheritAllFrom: '$block' } ); model.schema.extend( 'fooWrapper', { allowIn: '$root' } ); model.schema.extend( 'fooBlock', { allowIn: 'fooWrapper' } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'fooWrapper', view: 'foowrapper' } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'fooBlock', view: 'fooblock' } ); setModelData( model, 'de]f ' + '
' + '' + 'abc ' + '
' + '' ); } ); it( 'should handle forceValue = true param', () => { setModelData( model, 'de]f ' + '
' + '' + 'x[x ' + '
' + '' ); expect( getViewData( editor.editing.view ) ).to.equal( 'x[x ' + 'd]ef ' + '
' ); } ); } ); describe( 'removing quote', () => { it( 'should unwrap a single block', () => { setModelData( model, 'x{x
d}ef
' + 'x[]x
abc
x{}x
def
' ); } ); it( 'should unwrap multiple blocks', () => { setModelData( model, '' + '' ); editor.execute( 'blockQuote' ); expect( getModelData( model ) ).to.equal( 'a[bc ' + 'xx ' + 'de]f ' + '
a{bc
xx
de}f
' ); } ); it( 'should unwrap only the selected blocks - at the beginning', () => { setModelData( model, '' + '' + 'a[b]c ' + 'xx ' + '
' + '' + 'xx ' + '
xx
a{b}c
xx
yy
' ); } ); it( 'should unwrap only the selected blocks - at the end', () => { setModelData( model, '' + '' + 'abc ' + 'x[x ' + '
' + '' + 'abc ' + '
abc
x{x
de}f
' ); } ); it( 'should unwrap only the selected blocks - in the middle', () => { setModelData( model, '' + '' + 'abc ' + 'c[]de ' + 'fgh ' + '
' + 'abc
' + 'fgh
xx
' + '' + 'abc
c{}de
' + '' + 'fgh
xx
' ); } ); it( 'should remove multiple quotes', () => { setModelData( model, '' + 'a[bc
' + 'def ghi
' ); editor.execute( 'blockQuote' ); expect( getModelData( model ) ).to.equal( 'de]f ghi
' ); expect( getViewData( editor.editing.view ) ).to.equal( 'ghi
a{bc
' + 'xx
' + 'def
ghi
' + 'yy
' + 'de}f
' + '' ); } ); it( 'should handle forceValue = false param', () => { setModelData( model, 'ghi
' + '' ); editor.execute( 'blockQuote', { forceValue: false } ); // Incorrect selection. expect( getModelData( model ) ).to.equal( 'x]x ' + '
a{bc}
xx
' ); } ); } ); } ); } );