refactor(admonitions): remove unnecessary tests

This commit is contained in:
Elian Doran 2025-03-13 18:37:19 +02:00
parent a0b60eed8f
commit 303a943b81
12 changed files with 0 additions and 1898 deletions

View File

@ -1,14 +0,0 @@
/**
* @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 BlockQuote from '../src/blockquote.js';
import BlockQuoteEditing from '../src/blockquoteediting.js';
import BlockQuoteUI from '../src/blockquoteui.js';
describe( 'BlockQuote', () => {
it( 'requires BlockQuoteEditing and BlockQuoteUI', () => {
expect( BlockQuote.requires ).to.deep.equal( [ BlockQuoteEditing, BlockQuoteUI ] );
} );
} );

View File

@ -1,648 +0,0 @@
/**
* @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, '<paragraph>x[]x</paragraph>' );
expect( command ).to.have.property( 'value', false );
} );
it( 'is false when start of the selection is not in a block quote', () => {
setModelData( model, '<paragraph>x[x</paragraph><blockQuote><paragraph>y]y</paragraph></blockQuote>' );
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, '<blockQuote><paragraph>x[]x</paragraph></blockQuote>' );
expect( command ).to.have.property( 'value', true );
} );
it( 'is true when selection starts in a block quote', () => {
setModelData( model, '<blockQuote><paragraph>x[x</paragraph></blockQuote><paragraph>y]y</paragraph>' );
expect( command ).to.have.property( 'value', true );
} );
} );
describe( 'isEnabled', () => {
it( 'is true when selection is in a block which can be wrapped with blockQuote', () => {
setModelData( model, '<paragraph>x[]x</paragraph>' );
expect( command ).to.have.property( 'isEnabled', true );
} );
it( 'is true when selection is in a block which is already in blockQuote', () => {
setModelData( model, '<blockQuote><paragraph>x[]x</paragraph></blockQuote>' );
expect( command ).to.have.property( 'isEnabled', true );
} );
it( 'is true when selection starts in a block which can be wrapped with blockQuote', () => {
setModelData( model, '<paragraph>x[x</paragraph><widget>y]y</widget>' );
expect( command ).to.have.property( 'isEnabled', true );
} );
it( 'is false when selection is in an element which cannot be wrapped with blockQuote (because it cannot be its child)', () => {
setModelData( model, '<widget>x[]x</widget>' );
expect( command ).to.have.property( 'isEnabled', false );
} );
it(
'is false when selection is in an element which cannot be wrapped with blockQuote' +
'(because mQ is not allowed in its parent)',
() => {
model.schema.addChildCheck( ( ctx, childDef ) => {
if ( childDef.name == 'blockQuote' ) {
return false;
}
} );
setModelData( model, '<paragraph>x[]x</paragraph>' );
expect( command ).to.have.property( 'isEnabled', false );
}
);
// https://github.com/ckeditor/ckeditor5-engine/issues/826
// it( 'is false when selection starts in an element which cannot be wrapped with blockQuote', () => {
// setModelData( model, '<widget>x[x</widget><paragraph>y]y</paragraph>' );
// expect( command ).to.have.property( 'isEnabled', false );
// } );
} );
describe( 'execute()', () => {
describe( 'applying quote', () => {
it( 'should wrap a single block', () => {
setModelData(
model,
'<paragraph>abc</paragraph>' +
'<paragraph>x[]x</paragraph>' +
'<paragraph>def</paragraph>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<paragraph>abc</paragraph>' +
'<blockQuote><paragraph>x[]x</paragraph></blockQuote>' +
'<paragraph>def</paragraph>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<p>abc</p><blockquote><p>x{}x</p></blockquote><p>def</p>'
);
} );
it( 'should wrap multiple blocks', () => {
setModelData(
model,
'<heading>a[bc</heading>' +
'<paragraph>xx</paragraph>' +
'<paragraph>de]f</paragraph>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<blockQuote>' +
'<heading>a[bc</heading>' +
'<paragraph>xx</paragraph>' +
'<paragraph>de]f</paragraph>' +
'</blockQuote>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<blockquote><h>a{bc</h><p>xx</p><p>de}f</p></blockquote>'
);
} );
it( 'should merge with an existing quote', () => {
setModelData(
model,
'<heading>a[bc</heading>' +
'<blockQuote><paragraph>x]x</paragraph><paragraph>yy</paragraph></blockQuote>' +
'<paragraph>def</paragraph>'
);
editor.execute( 'blockQuote' );
// Selection incorrectly trimmed.
expect( getModelData( model ) ).to.equal(
'<blockQuote>' +
'<heading>abc</heading>' +
'<paragraph>[x]x</paragraph>' +
'<paragraph>yy</paragraph>' +
'</blockQuote>' +
'<paragraph>def</paragraph>'
);
// Selection incorrectly trimmed.
expect( getViewData( editor.editing.view ) ).to.equal(
'<blockquote><h>abc</h><p>{x}x</p><p>yy</p></blockquote><p>def</p>'
);
} );
it( 'should not merge with a quote preceding the current block', () => {
setModelData(
model,
'<blockQuote><paragraph>abc</paragraph></blockQuote>' +
'<paragraph>x[]x</paragraph>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<blockQuote><paragraph>abc</paragraph></blockQuote>' +
'<blockQuote><paragraph>x[]x</paragraph></blockQuote>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<blockquote><p>abc</p></blockquote>' +
'<blockquote><p>x{}x</p></blockquote>'
);
} );
it( 'should not merge with a quote following the current block', () => {
setModelData(
model,
'<paragraph>x[]x</paragraph>' +
'<blockQuote><paragraph>abc</paragraph></blockQuote>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<blockQuote><paragraph>x[]x</paragraph></blockQuote>' +
'<blockQuote><paragraph>abc</paragraph></blockQuote>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<blockquote><p>x{}x</p></blockquote>' +
'<blockquote><p>abc</p></blockquote>'
);
} );
it( 'should merge with an existing quote (more blocks)', () => {
setModelData(
model,
'<heading>a[bc</heading>' +
'<paragraph>def</paragraph>' +
'<blockQuote><paragraph>x]x</paragraph></blockQuote>' +
'<paragraph>ghi</paragraph>'
);
editor.execute( 'blockQuote' );
// Selection incorrectly trimmed.
expect( getModelData( model ) ).to.equal(
'<blockQuote>' +
'<heading>abc</heading>' +
'<paragraph>def</paragraph>' +
'<paragraph>[x]x</paragraph>' +
'</blockQuote>' +
'<paragraph>ghi</paragraph>'
);
// Selection incorrectly trimmed.
expect( getViewData( editor.editing.view ) ).to.equal(
'<blockquote><h>abc</h><p>def</p><p>{x}x</p></blockquote><p>ghi</p>'
);
} );
it( 'should not wrap non-block content', () => {
setModelData(
model,
'<paragraph>a[bc</paragraph>' +
'<widget>xx</widget>' +
'<paragraph>de]f</paragraph>'
);
editor.execute( 'blockQuote' );
// Selection incorrectly trimmed.
expect( getModelData( model ) ).to.equal(
'<blockQuote>' +
'<paragraph>abc</paragraph>' +
'</blockQuote>' +
'[<widget>xx</widget>' +
'<blockQuote>' +
'<paragraph>de]f</paragraph>' +
'</blockQuote>'
);
// Selection incorrectly trimmed.
expect( getViewData( editor.editing.view ) ).to.equal(
'<blockquote><p>abc</p></blockquote>[<widget>xx</widget><blockquote><p>de}f</p></blockquote>'
);
} );
it( 'should correctly wrap and merge groups of blocks', () => {
setModelData(
model,
'<paragraph>a[bc</paragraph>' +
'<widget>xx</widget>' +
'<paragraph>def</paragraph>' +
'<blockQuote><paragraph>ghi</paragraph></blockQuote>' +
'<widget>yy</widget>' +
'<paragraph>jk]l</paragraph>'
);
editor.execute( 'blockQuote' );
// Selection incorrectly trimmed.
expect( getModelData( model ) ).to.equal(
'<blockQuote><paragraph>abc</paragraph></blockQuote>' +
'[<widget>xx</widget>' +
'<blockQuote><paragraph>def</paragraph><paragraph>ghi</paragraph></blockQuote>' +
'<widget>yy</widget>' +
'<blockQuote><paragraph>jk]l</paragraph></blockQuote>'
);
// Selection incorrectly trimmed.
expect( getViewData( editor.editing.view ) ).to.equal(
'<blockquote><p>abc</p></blockquote>' +
'[<widget>xx</widget>' +
'<blockquote><p>def</p><p>ghi</p></blockquote>' +
'<widget>yy</widget>' +
'<blockquote><p>jk}l</p></blockquote>'
);
} );
it( 'should correctly merge a couple of subsequent quotes', () => {
setModelData(
model,
'<paragraph>x</paragraph>' +
'<paragraph>a[bc</paragraph>' +
'<blockQuote><paragraph>def</paragraph></blockQuote>' +
'<paragraph>ghi</paragraph>' +
'<blockQuote><paragraph>jkl</paragraph></blockQuote>' +
'<paragraph>mn]o</paragraph>' +
'<paragraph>y</paragraph>'
);
editor.execute( 'blockQuote' );
// Selection incorrectly trimmed.
expect( getModelData( model ) ).to.equal(
'<paragraph>x</paragraph>' +
'<blockQuote>' +
'<paragraph>abc</paragraph>' +
'<paragraph>def</paragraph>' +
'<paragraph>ghi</paragraph>' +
'<paragraph>jkl</paragraph>' +
'<paragraph>[mn]o</paragraph>' +
'</blockQuote>' +
'<paragraph>y</paragraph>'
);
// Selection incorrectly trimmed.
expect( getViewData( editor.editing.view ) ).to.equal(
'<p>x</p>' +
'<blockquote>' +
'<p>abc</p>' +
'<p>def</p>' +
'<p>ghi</p>' +
'<p>jkl</p>' +
'<p>{mn}o</p>' +
'</blockquote>' +
'<p>y</p>'
);
} );
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,
'<paragraph>a[bc</paragraph>' +
'<fooBlock>xx</fooBlock>' +
'<paragraph>de]f</paragraph>'
);
editor.execute( 'blockQuote' );
// Selection incorrectly trimmed.
expect( getModelData( model ) ).to.equal(
'<blockQuote>' +
'<paragraph>abc</paragraph>' +
'</blockQuote>' +
'<fooBlock>[xx</fooBlock>' +
'<blockQuote>' +
'<paragraph>de]f</paragraph>' +
'</blockQuote>'
);
} );
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,
'<paragraph>a[bc</paragraph>' +
'<fooWrapper><fooBlock>xx</fooBlock></fooWrapper>' +
'<paragraph>de]f</paragraph>'
);
editor.execute( 'blockQuote' );
// Selection incorrectly trimmed.
expect( getModelData( model ) ).to.equal(
'<blockQuote>' +
'<paragraph>abc</paragraph>' +
'</blockQuote>' +
'<fooWrapper><fooBlock>[xx</fooBlock></fooWrapper>' +
'<blockQuote>' +
'<paragraph>de]f</paragraph>' +
'</blockQuote>'
);
} );
it( 'should handle forceValue = true param', () => {
setModelData(
model,
'<blockQuote>' +
'<paragraph>x[x</paragraph>' +
'</blockQuote>' +
'<paragraph>d]ef</paragraph>'
);
editor.execute( 'blockQuote', { forceValue: true } );
expect( getModelData( model ) ).to.equal(
'<blockQuote>' +
'<paragraph>x[x</paragraph>' +
'<paragraph>d]ef</paragraph>' +
'</blockQuote>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<blockquote><p>x{x</p><p>d}ef</p></blockquote>'
);
} );
} );
describe( 'removing quote', () => {
it( 'should unwrap a single block', () => {
setModelData(
model,
'<paragraph>abc</paragraph>' +
'<blockQuote><paragraph>x[]x</paragraph></blockQuote>' +
'<paragraph>def</paragraph>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<paragraph>abc</paragraph>' +
'<paragraph>x[]x</paragraph>' +
'<paragraph>def</paragraph>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<p>abc</p><p>x{}x</p><p>def</p>'
);
} );
it( 'should unwrap multiple blocks', () => {
setModelData(
model,
'<blockQuote>' +
'<paragraph>a[bc</paragraph>' +
'<paragraph>xx</paragraph>' +
'<paragraph>de]f</paragraph>' +
'</blockQuote>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<paragraph>a[bc</paragraph>' +
'<paragraph>xx</paragraph>' +
'<paragraph>de]f</paragraph>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<p>a{bc</p><p>xx</p><p>de}f</p>'
);
} );
it( 'should unwrap only the selected blocks - at the beginning', () => {
setModelData(
model,
'<paragraph>xx</paragraph>' +
'<blockQuote>' +
'<paragraph>a[b]c</paragraph>' +
'<paragraph>xx</paragraph>' +
'</blockQuote>' +
'<paragraph>yy</paragraph>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<paragraph>xx</paragraph>' +
'<paragraph>a[b]c</paragraph>' +
'<blockQuote>' +
'<paragraph>xx</paragraph>' +
'</blockQuote>' +
'<paragraph>yy</paragraph>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<p>xx</p><p>a{b}c</p><blockquote><p>xx</p></blockquote><p>yy</p>'
);
} );
it( 'should unwrap only the selected blocks - at the end', () => {
setModelData(
model,
'<blockQuote>' +
'<paragraph>abc</paragraph>' +
'<paragraph>x[x</paragraph>' +
'</blockQuote>' +
'<paragraph>de]f</paragraph>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<blockQuote>' +
'<paragraph>abc</paragraph>' +
'</blockQuote>' +
'<paragraph>x[x</paragraph>' +
'<paragraph>de]f</paragraph>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<blockquote><p>abc</p></blockquote><p>x{x</p><p>de}f</p>'
);
} );
it( 'should unwrap only the selected blocks - in the middle', () => {
setModelData(
model,
'<paragraph>xx</paragraph>' +
'<blockQuote>' +
'<paragraph>abc</paragraph>' +
'<paragraph>c[]de</paragraph>' +
'<paragraph>fgh</paragraph>' +
'</blockQuote>' +
'<paragraph>xx</paragraph>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<paragraph>xx</paragraph>' +
'<blockQuote><paragraph>abc</paragraph></blockQuote>' +
'<paragraph>c[]de</paragraph>' +
'<blockQuote><paragraph>fgh</paragraph></blockQuote>' +
'<paragraph>xx</paragraph>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<p>xx</p>' +
'<blockquote><p>abc</p></blockquote>' +
'<p>c{}de</p>' +
'<blockquote><p>fgh</p></blockquote>' +
'<p>xx</p>'
);
} );
it( 'should remove multiple quotes', () => {
setModelData(
model,
'<blockQuote><paragraph>a[bc</paragraph></blockQuote>' +
'<paragraph>xx</paragraph>' +
'<blockQuote><paragraph>def</paragraph><paragraph>ghi</paragraph></blockQuote>' +
'<paragraph>yy</paragraph>' +
'<blockQuote><paragraph>de]f</paragraph><paragraph>ghi</paragraph></blockQuote>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<paragraph>a[bc</paragraph>' +
'<paragraph>xx</paragraph>' +
'<paragraph>def</paragraph><paragraph>ghi</paragraph>' +
'<paragraph>yy</paragraph>' +
'<paragraph>de]f</paragraph>' +
'<blockQuote><paragraph>ghi</paragraph></blockQuote>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<p>a{bc</p>' +
'<p>xx</p>' +
'<p>def</p><p>ghi</p>' +
'<p>yy</p>' +
'<p>de}f</p>' +
'<blockquote><p>ghi</p></blockquote>'
);
} );
it( 'should handle forceValue = false param', () => {
setModelData(
model,
'<paragraph>a[bc</paragraph>' +
'<blockQuote>' +
'<paragraph>x]x</paragraph>' +
'</blockQuote>'
);
editor.execute( 'blockQuote', { forceValue: false } );
// Incorrect selection.
expect( getModelData( model ) ).to.equal(
'<paragraph>a[bc]</paragraph>' +
'<paragraph>xx</paragraph>'
);
expect( getViewData( editor.editing.view ) ).to.equal(
'<p>a{bc}</p><p>xx</p>'
);
} );
} );
} );
} );

View File

@ -1,196 +0,0 @@
/**
* @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 Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph.js';
import ListEditing from '@ckeditor/ckeditor5-list/src/list/listediting.js';
import BoldEditing from '@ckeditor/ckeditor5-basic-styles/src/bold/boldediting.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 BlockQuoteCommand from '../src/blockquotecommand.js';
describe( 'BlockQuoteEditing', () => {
let editor, model;
beforeEach( () => {
return VirtualTestEditor
.create( {
plugins: [ BlockQuoteEditing, Paragraph, BoldEditing ]
} )
.then( newEditor => {
editor = newEditor;
model = editor.model;
} );
} );
afterEach( () => {
return editor.destroy();
} );
it( 'should have pluginName', () => {
expect( BlockQuoteEditing.pluginName ).to.equal( 'BlockQuoteEditing' );
} );
it( 'adds a blockQuote command', () => {
expect( editor.commands.get( 'blockQuote' ) ).to.be.instanceOf( BlockQuoteCommand );
} );
it( 'allows for blockQuote in the $root', () => {
expect( model.schema.checkChild( [ '$root' ], 'blockQuote' ) ).to.be.true;
} );
it( 'allows for $block in blockQuote', () => {
expect( model.schema.checkChild( [ '$root', 'blockQuote' ], '$block' ) ).to.be.true;
expect( model.schema.checkChild( [ '$root', 'blockQuote' ], 'paragraph' ) ).to.be.true;
} );
it( 'allows for blockQuote in blockQuote', () => {
expect( model.schema.checkChild( [ '$root', 'blockQuote' ], 'blockQuote' ) ).to.be.true;
} );
it( 'does not break when checking an unregisterd item', () => {
expect( model.schema.checkChild( [ '$root', 'blockQuote' ], 'foo' ) ).to.be.false;
} );
it( 'inherits attributes from $container', () => {
model.schema.extend( '$container', {
allowAttributes: 'foo'
} );
expect( model.schema.checkAttribute( 'blockQuote', 'foo' ) ).to.be.true;
} );
it( 'adds converters to the data pipeline', () => {
const data = '<blockquote><p>x</p></blockquote>';
editor.setData( data );
expect( getModelData( model ) ).to.equal( '<blockQuote><paragraph>[]x</paragraph></blockQuote>' );
expect( editor.getData() ).to.equal( data );
} );
it( 'adds a converter to the view pipeline', () => {
setModelData( model, '<blockQuote><paragraph>x</paragraph></blockQuote>' );
expect( editor.getData() ).to.equal( '<blockquote><p>x</p></blockquote>' );
} );
it( 'allows list items inside blockQuote', () => {
return VirtualTestEditor
.create( {
plugins: [ BlockQuoteEditing, Paragraph, ListEditing ]
} )
.then( editor => {
editor.setData( '<blockquote><ul><li>xx</li></ul></blockquote>' );
expect( editor.getData() ).to.equal( '<blockquote><ul><li>xx</li></ul></blockquote>' );
return editor.destroy();
} );
} );
it( 'should remove empty blockQuote elements', () => {
setModelData( model, '<blockQuote></blockQuote><paragraph>Foo</paragraph>' );
expect( editor.getData() ).to.equal( '<p>Foo</p>' );
} );
it( 'should remove blockQuotes which became empty', () => {
setModelData( model, '<blockQuote><paragraph>Foo</paragraph></blockQuote>' );
model.change( writer => {
const root = model.document.getRoot();
const bq = root.getChild( 0 );
writer.remove( writer.createRangeIn( bq ) );
} );
expect( editor.getData( { trim: 'none' } ) ).to.equal( '<p>&nbsp;</p>' ); // Autoparagraphed.
} );
it( 'should not unwrap a blockQuote if it was inserted into another blockQuote', () => {
setModelData( model, '<blockQuote><paragraph>Foo</paragraph></blockQuote>' );
model.change( writer => {
const root = model.document.getRoot();
const bq = writer.createElement( 'blockQuote' );
const p = writer.createElement( 'paragraph' );
writer.insertText( 'Bar', p, 0 ); // <p>Bar</p>.
writer.insert( p, bq, 0 ); // <blockquote><p>Bar</p></blockquote>.
writer.insert( bq, root.getChild( 0 ), 1 ); // Insert after <p>Foo</p>.
} );
expect( editor.getData() ).to.equal( '<blockquote><p>Foo</p><blockquote><p>Bar</p></blockquote></blockquote>' );
} );
it( 'should not unwrap nested blockQuote if it was wrapped into another blockQuote', () => {
setModelData( model, '<blockQuote><paragraph>Foo</paragraph></blockQuote><paragraph>Bar</paragraph>' );
model.change( writer => {
const root = model.document.getRoot();
writer.wrap( writer.createRangeIn( root ), 'blockQuote' );
} );
expect( editor.getData() ).to.equal( '<blockquote><blockquote><p>Foo</p></blockquote><p>Bar</p></blockquote>' );
} );
it( 'postfixer should do nothing on attribute change', () => {
// This is strictly a 100% CC test.
setModelData( model, '<blockQuote><paragraph>Foo</paragraph></blockQuote>' );
model.change( writer => {
const root = model.document.getRoot();
const p = root.getChild( 0 ).getChild( 0 );
writer.setAttribute( 'bold', true, writer.createRangeIn( p ) );
} );
expect( editor.getData() ).to.equal( '<blockquote><p><strong>Foo</strong></p></blockquote>' );
} );
describe( 'nested blockQuote forbidden by custom rule', () => {
// Nested block quotes are supported since https://github.com/ckeditor/ckeditor5/issues/9210, so let's check
// if the editor will not blow up in case nested block quotes are forbidden by custom scheme rule.
beforeEach( () => {
model.schema.addChildCheck( ( ctx, childDef ) => {
if ( ctx.endsWith( 'blockQuote' ) && childDef.name == 'blockQuote' ) {
return false;
}
} );
} );
it( 'should unwrap a blockQuote if it was inserted into another blockQuote', () => {
setModelData( model, '<blockQuote><paragraph>Foo</paragraph></blockQuote>' );
model.change( writer => {
const root = model.document.getRoot();
const bq = writer.createElement( 'blockQuote' );
const p = writer.createElement( 'paragraph' );
writer.insertText( 'Bar', p, 0 ); // <p>Bar</p>.
writer.insert( p, bq, 0 ); // <blockquote><p>Bar</p></blockquote>.
writer.insert( bq, root.getChild( 0 ), 1 ); // Insert after <p>Foo</p>.
} );
expect( editor.getData() ).to.equal( '<blockquote><p>Foo</p><p>Bar</p></blockquote>' );
} );
it( 'should unwrap nested blockQuote if it was wrapped into another blockQuote', () => {
setModelData( model, '<blockQuote><paragraph>Foo</paragraph></blockQuote><paragraph>Bar</paragraph>' );
model.change( writer => {
const root = model.document.getRoot();
writer.wrap( writer.createRangeIn( root ), 'blockQuote' );
} );
expect( editor.getData() ).to.equal( '<blockquote><p>Foo</p><p>Bar</p></blockquote>' );
} );
} );
} );

View File

@ -1,91 +0,0 @@
/**
* @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
*/
/* global document */
import BlockQuoteEditing from '../src/blockquoteediting.js';
import BlockQuoteUI from '../src/blockquoteui.js';
import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor.js';
describe( 'BlockQuoteUI', () => {
let editor, command, element, button;
beforeEach( () => {
element = document.createElement( 'div' );
document.body.appendChild( element );
return ClassicTestEditor
.create( element, {
plugins: [ BlockQuoteEditing, BlockQuoteUI ]
} )
.then( newEditor => {
editor = newEditor;
command = editor.commands.get( 'blockQuote' );
} );
} );
afterEach( () => {
element.remove();
return editor.destroy();
} );
describe( 'toolbar block quote button', () => {
beforeEach( () => {
button = editor.ui.componentFactory.create( 'blockQuote' );
} );
it( 'has the base properties', () => {
expect( button ).to.have.property( 'label', 'Block quote' );
expect( button ).to.have.property( 'icon' );
expect( button ).to.have.property( 'tooltip', true );
expect( button ).to.have.property( 'isToggleable', true );
} );
it( 'has isOn bound to command\'s value', () => {
command.value = false;
expect( button ).to.have.property( 'isOn', false );
command.value = true;
expect( button ).to.have.property( 'isOn', true );
} );
testButton();
} );
describe( 'menu bar block quote button', () => {
beforeEach( () => {
button = editor.ui.componentFactory.create( 'menuBar:blockQuote' );
} );
it( 'has the base properties', () => {
expect( button ).to.have.property( 'label', 'Block quote' );
expect( button ).to.have.property( 'icon' );
expect( button ).to.have.property( 'isToggleable', true );
} );
testButton();
} );
function testButton() {
it( 'has isEnabled bound to command\'s isEnabled', () => {
command.isEnabled = true;
expect( button ).to.have.property( 'isEnabled', true );
command.isEnabled = false;
expect( button ).to.have.property( 'isEnabled', false );
} );
it( 'executes command when it\'s executed', () => {
const spy = sinon.stub( editor, 'execute' );
button.fire( 'execute' );
expect( spy.calledOnce ).to.be.true;
expect( spy.args[ 0 ][ 0 ] ).to.equal( 'blockQuote' );
} );
}
} );

View File

@ -1,830 +0,0 @@
/**
* @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
*/
/* global document */
import BlockQuote from '../src/blockquote.js';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph.js';
import Image from '@ckeditor/ckeditor5-image/src/image.js';
import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption.js';
import LegacyList from '@ckeditor/ckeditor5-list/src/legacylist.js';
import Enter from '@ckeditor/ckeditor5-enter/src/enter.js';
import Delete from '@ckeditor/ckeditor5-typing/src/delete.js';
import Heading from '@ckeditor/ckeditor5-heading/src/heading.js';
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold.js';
import Table from '@ckeditor/ckeditor5-table/src/table.js';
import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor.js';
import {
parse as parseModel,
getData as getModelData,
setData as setModelData
} from '@ckeditor/ckeditor5-engine/src/dev-utils/model.js';
describe( 'BlockQuote integration', () => {
let editor, model, element, viewDocument;
beforeEach( () => {
element = document.createElement( 'div' );
document.body.appendChild( element );
return ClassicTestEditor
.create( element, {
plugins: [ BlockQuote, Paragraph, Bold, Image, ImageCaption, LegacyList, Enter, Delete, Heading, Table ]
} )
.then( newEditor => {
editor = newEditor;
model = editor.model;
viewDocument = editor.editing.view.document;
} );
} );
afterEach( () => {
element.remove();
return editor.destroy();
} );
describe( 'enter key support', () => {
function fakeEventData() {
return {
preventDefault: sinon.spy()
};
}
it( 'does nothing if selection is in an empty block but not in a block quote', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
setModelData( model, '<paragraph>x</paragraph><paragraph>[]</paragraph><paragraph>x</paragraph>' );
viewDocument.fire( 'enter', data );
// Only enter command should be executed.
expect( data.preventDefault.called ).to.be.true;
expect( execSpy.calledOnce ).to.be.true;
expect( execSpy.args[ 0 ][ 0 ] ).to.equal( 'enter' );
} );
it( 'does nothing if selection is in a non-empty block (at the end) in a block quote', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
setModelData( model, '<blockQuote><paragraph>xx[]</paragraph></blockQuote>' );
viewDocument.fire( 'enter', data );
// Only enter command should be executed.
expect( data.preventDefault.called ).to.be.true;
expect( execSpy.calledOnce ).to.be.true;
expect( execSpy.args[ 0 ][ 0 ] ).to.equal( 'enter' );
} );
it( 'does nothing if selection is in a non-empty block (at the beginning) in a block quote', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
setModelData( model, '<blockQuote><paragraph>[]xx</paragraph></blockQuote>' );
viewDocument.fire( 'enter', data );
// Only enter command should be executed.
expect( data.preventDefault.called ).to.be.true;
expect( execSpy.calledOnce ).to.be.true;
expect( execSpy.args[ 0 ][ 0 ] ).to.equal( 'enter' );
} );
it( 'does nothing if selection is not collapsed', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
setModelData( model, '<blockQuote><paragraph>[</paragraph><paragraph>]</paragraph></blockQuote>' );
viewDocument.fire( 'enter', data );
// Only enter command should be executed.
expect( data.preventDefault.called ).to.be.true;
expect( execSpy.calledOnce ).to.be.true;
expect( execSpy.args[ 0 ][ 0 ] ).to.equal( 'enter' );
} );
it( 'does not interfere with a similar handler in the list feature', () => {
const data = fakeEventData();
setModelData( model,
'<paragraph>x</paragraph>' +
'<blockQuote>' +
'<listItem listIndent="0" listType="bulleted">a</listItem>' +
'<listItem listIndent="0" listType="bulleted">[]</listItem>' +
'</blockQuote>' +
'<paragraph>x</paragraph>'
);
viewDocument.fire( 'enter', data );
expect( data.preventDefault.called ).to.be.true;
expect( getModelData( model ) ).to.equal(
'<paragraph>x</paragraph>' +
'<blockQuote>' +
'<listItem listIndent="0" listType="bulleted">a</listItem>' +
'<paragraph>[]</paragraph>' +
'</blockQuote>' +
'<paragraph>x</paragraph>'
);
} );
it( 'escapes block quote if selection is in an empty block in an empty block quote', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
setModelData( model, '<paragraph>x</paragraph><blockQuote><paragraph>[]</paragraph></blockQuote><paragraph>x</paragraph>' );
viewDocument.fire( 'enter', data );
expect( data.preventDefault.called ).to.be.true;
expect( execSpy.calledOnce ).to.be.true;
expect( execSpy.args[ 0 ][ 0 ] ).to.equal( 'blockQuote' );
expect( getModelData( model ) ).to.equal( '<paragraph>x</paragraph><paragraph>[]</paragraph><paragraph>x</paragraph>' );
} );
it( 'escapes block quote if selection is in an empty block in the middle of a block quote', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
setModelData( model,
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>a</paragraph><paragraph>[]</paragraph><paragraph>b</paragraph></blockQuote>' +
'<paragraph>x</paragraph>'
);
viewDocument.fire( 'enter', data );
expect( data.preventDefault.called ).to.be.true;
expect( execSpy.calledOnce ).to.be.true;
expect( execSpy.args[ 0 ][ 0 ] ).to.equal( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>a</paragraph></blockQuote>' +
'<paragraph>[]</paragraph>' +
'<blockQuote><paragraph>b</paragraph></blockQuote>' +
'<paragraph>x</paragraph>'
);
} );
it( 'escapes block quote if selection is in an empty block at the end of a block quote', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
setModelData( model,
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>a</paragraph><paragraph>[]</paragraph></blockQuote>' +
'<paragraph>x</paragraph>'
);
viewDocument.fire( 'enter', data );
expect( data.preventDefault.called ).to.be.true;
expect( execSpy.calledOnce ).to.be.true;
expect( execSpy.args[ 0 ][ 0 ] ).to.equal( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>a</paragraph></blockQuote>' +
'<paragraph>[]</paragraph>' +
'<paragraph>x</paragraph>'
);
} );
it( 'scrolls the view document to the selection after the command is executed', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
const scrollSpy = sinon.stub( editor.editing.view, 'scrollToTheSelection' );
setModelData( model,
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>a</paragraph><paragraph>[]</paragraph></blockQuote>' +
'<paragraph>x</paragraph>'
);
viewDocument.fire( 'enter', data );
sinon.assert.calledOnce( scrollSpy );
sinon.assert.callOrder( execSpy, scrollSpy );
} );
} );
describe( 'backspace key support', () => {
function fakeEventData() {
return {
preventDefault: sinon.spy(),
direction: 'backward',
inputType: 'deleteContentBackward',
unit: 'character'
};
}
it( 'merges paragraph into paragraph in the quote', () => {
const data = fakeEventData();
setModelData( model,
'<blockQuote><paragraph>a</paragraph><paragraph>b</paragraph></blockQuote>' +
'<paragraph>[]c</paragraph>' +
'<paragraph>d</paragraph>'
);
viewDocument.fire( 'delete', data );
expect( getModelData( model ) ).to.equal(
'<blockQuote><paragraph>a</paragraph><paragraph>b[]c</paragraph></blockQuote>' +
'<paragraph>d</paragraph>'
);
} );
it( 'merges paragraph from a quote into a paragraph before quote', () => {
const data = fakeEventData();
setModelData( model,
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>[]a</paragraph><paragraph>b</paragraph></blockQuote>' +
'<paragraph>y</paragraph>'
);
viewDocument.fire( 'delete', data );
expect( getModelData( model ) ).to.equal(
'<paragraph>x[]a</paragraph>' +
'<blockQuote><paragraph>b</paragraph></blockQuote>' +
'<paragraph>y</paragraph>'
);
} );
it( 'merges two quotes', () => {
const data = fakeEventData();
setModelData( model,
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>a</paragraph><paragraph>b</paragraph></blockQuote>' +
'<blockQuote><paragraph>[]c</paragraph><paragraph>d</paragraph></blockQuote>' +
'<paragraph>y</paragraph>'
);
viewDocument.fire( 'delete', data );
expect( getModelData( model ) ).to.equal(
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>a</paragraph><paragraph>b[]c</paragraph><paragraph>d</paragraph></blockQuote>' +
'<paragraph>y</paragraph>'
);
} );
it( 'unwraps empty quote when the backspace key pressed in the first empty paragraph in a quote', () => {
const data = fakeEventData();
setModelData( model,
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>a</paragraph></blockQuote>' +
'<blockQuote><paragraph>[]</paragraph></blockQuote>' +
'<paragraph>y</paragraph>'
);
viewDocument.fire( 'delete', data );
expect( getModelData( model ) ).to.equal(
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>a</paragraph></blockQuote>' +
'<paragraph>[]</paragraph>' +
'<paragraph>y</paragraph>'
);
} );
it( 'unwraps empty quote when the backspace key pressed in the empty paragraph that is the only content of quote', () => {
const data = fakeEventData();
setModelData( model,
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>[]</paragraph></blockQuote>' +
'<paragraph>y</paragraph>'
);
viewDocument.fire( 'delete', data );
expect( getModelData( model ) ).to.equal(
'<paragraph>x</paragraph>' +
'<paragraph>[]</paragraph>' +
'<paragraph>y</paragraph>'
);
} );
it( 'unwraps quote from the first paragraph when the backspace key pressed', () => {
const data = fakeEventData();
setModelData( model,
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>[]</paragraph><paragraph>foo</paragraph></blockQuote>' +
'<paragraph>y</paragraph>'
);
viewDocument.fire( 'delete', data );
expect( getModelData( model ) ).to.equal(
'<paragraph>x</paragraph>' +
'<paragraph>[]</paragraph>' +
'<blockQuote><paragraph>foo</paragraph></blockQuote>' +
'<paragraph>y</paragraph>'
);
} );
it( 'merges paragraphs in a quote when the backspace key pressed not in the first paragraph', () => {
const data = fakeEventData();
setModelData( model,
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph></paragraph><paragraph>[]</paragraph></blockQuote>' +
'<paragraph>y</paragraph>'
);
viewDocument.fire( 'delete', data );
expect( getModelData( model ) ).to.equal(
'<paragraph>x</paragraph>' +
'<blockQuote><paragraph>[]</paragraph></blockQuote>' +
'<paragraph>y</paragraph>'
);
} );
it( 'does nothing if selection is in an empty block but not in a block quote', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
setModelData( model, '<paragraph>x</paragraph><paragraph>[]</paragraph><paragraph>x</paragraph>' );
viewDocument.fire( 'delete', data );
// Only delete command should be executed.
expect( data.preventDefault.called ).to.be.true;
expect( execSpy.calledOnce ).to.be.true;
expect( execSpy.args[ 0 ][ 0 ] ).to.equal( 'delete' );
} );
it( 'does nothing if selection is in a non-empty block (at the end) in a block quote', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
setModelData( model, '<blockQuote><paragraph>xx[]</paragraph></blockQuote>' );
viewDocument.fire( 'delete', data );
// Only delete command should be executed.
expect( data.preventDefault.called ).to.be.true;
expect( execSpy.calledOnce ).to.be.true;
expect( execSpy.args[ 0 ][ 0 ] ).to.equal( 'delete' );
} );
it( 'does nothing if selection is in a non-empty block (at the beginning) in a block quote', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
setModelData( model, '<blockQuote><paragraph>[]xx</paragraph></blockQuote>' );
viewDocument.fire( 'delete', data );
// Only delete command should be executed.
expect( data.preventDefault.called ).to.be.true;
expect( execSpy.calledOnce ).to.be.true;
expect( execSpy.args[ 0 ][ 0 ] ).to.equal( 'delete' );
} );
it( 'does nothing if selection is not collapsed', () => {
const data = fakeEventData();
const execSpy = sinon.spy( editor, 'execute' );
setModelData( model, '<blockQuote><paragraph>[</paragraph><paragraph>]</paragraph></blockQuote>' );
viewDocument.fire( 'delete', data );
// Only delete command should be executed.
expect( data.preventDefault.called ).to.be.true;
expect( execSpy.calledOnce ).to.be.true;
expect( execSpy.args[ 0 ][ 0 ] ).to.equal( 'delete' );
} );
} );
// Historically, due to problems with schema, images were not quotable.
// These tests were left here to confirm that after schema was fixed, images are properly quotable.
describe( 'compatibility with images', () => {
it( 'quotes a simple image', () => {
const element = document.createElement( 'div' );
document.body.appendChild( element );
// We can't load ImageCaption in this test because it adds <caption> to all images automatically.
return ClassicTestEditor
.create( element, {
plugins: [ BlockQuote, Paragraph, Image ]
} )
.then( editor => {
setModelData( editor.model,
'<paragraph>fo[o</paragraph>' +
'<imageBlock src="/assets/sample.png"></imageBlock>' +
'<paragraph>b]ar</paragraph>'
);
editor.execute( 'blockQuote' );
expect( getModelData( editor.model ) ).to.equal(
'<blockQuote>' +
'<paragraph>fo[o</paragraph>' +
'<imageBlock src="/assets/sample.png"></imageBlock>' +
'<paragraph>b]ar</paragraph>' +
'</blockQuote>'
);
element.remove();
return editor.destroy();
} );
} );
it( 'quotes an image with caption', () => {
setModelData( model,
'<paragraph>fo[o</paragraph>' +
'<imageBlock src="/assets/sample.png">' +
'<caption>xxx</caption>' +
'</imageBlock>' +
'<paragraph>b]ar</paragraph>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<blockQuote>' +
'<paragraph>fo[o</paragraph>' +
'<imageBlock src="/assets/sample.png">' +
'<caption>xxx</caption>' +
'</imageBlock>' +
'<paragraph>b]ar</paragraph>' +
'</blockQuote>'
);
} );
it( 'adds an image to an existing quote', () => {
setModelData( model,
'<paragraph>fo[o</paragraph>' +
'<imageBlock src="/assets/sample.png">' +
'<caption>xxx</caption>' +
'</imageBlock>' +
'<blockQuote><paragraph>b]ar</paragraph></blockQuote>'
);
editor.execute( 'blockQuote' );
// Selection incorrectly trimmed.
expect( getModelData( model ) ).to.equal(
'<blockQuote>' +
'<paragraph>foo</paragraph>' +
'<imageBlock src="/assets/sample.png">' +
'<caption>xxx</caption>' +
'</imageBlock>' +
'<paragraph>[b]ar</paragraph>' +
'</blockQuote>'
);
} );
it( 'wraps paragraph+image', () => {
setModelData( model,
'<paragraph>[foo</paragraph><imageBlock><caption>foo</caption></imageBlock>]'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<blockQuote><paragraph>[foo</paragraph><imageBlock><caption>foo</caption></imageBlock>]</blockQuote>'
);
} );
it( 'unwraps paragraph+image', () => {
setModelData( model,
'<blockQuote><paragraph>[foo</paragraph><imageBlock><caption>foo</caption></imageBlock>]</blockQuote>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<paragraph>[foo</paragraph><imageBlock><caption>foo</caption></imageBlock>]'
);
} );
it( 'wraps image+paragraph', () => {
setModelData( model,
'[<imageBlock><caption>foo</caption></imageBlock><paragraph>foo]</paragraph>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<blockQuote>[<imageBlock><caption>foo</caption></imageBlock><paragraph>foo]</paragraph></blockQuote>'
);
} );
it( 'unwraps image+paragraph', () => {
setModelData( model,
'[<imageBlock><caption>foo</caption></imageBlock><paragraph>foo]</paragraph>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<blockQuote>[<imageBlock><caption>foo</caption></imageBlock><paragraph>foo]</paragraph></blockQuote>'
);
} );
} );
// When blockQuote with a paragraph was pasted into a list item, the item contained the paragraph. It was invalid.
// There is a test which checks whether blockQuote will split the list items instead of merging with.
describe( 'compatibility with lists', () => {
it( 'does not merge the paragraph with list item', () => {
setModelData( model, '<listItem listIndent="0" listType="bulleted">fo[]o</listItem>' );
const df = parseModel(
'<blockQuote><paragraph>xxx</paragraph></blockQuote><heading1>yyy</heading1>',
model.schema
);
model.insertContent( df, model.document.selection );
expect( getModelData( model ) ).to.equal(
'<listItem listIndent="0" listType="bulleted">fo</listItem>' +
'<blockQuote>' +
'<paragraph>xxx</paragraph>' +
'</blockQuote>' +
'<heading1>yyy[]o</heading1>'
);
} );
} );
describe( 'compatibility with tables', () => {
it( 'wraps whole table', () => {
setModelData( model, '[<table><tableRow><tableCell><paragraph>foo</paragraph></tableCell></tableRow></table>]' );
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<blockQuote>[<table><tableRow><tableCell><paragraph>foo</paragraph></tableCell></tableRow></table>]</blockQuote>'
);
} );
it( 'unwraps whole table', () => {
setModelData(
model,
'<blockQuote>[<table><tableRow><tableCell><paragraph>foo</paragraph></tableCell></tableRow></table>]</blockQuote>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'[<table><tableRow><tableCell><paragraph>foo</paragraph></tableCell></tableRow></table>]'
);
} );
it( 'wraps paragraph in table cell', () => {
setModelData( model, '<table><tableRow><tableCell><paragraph>[]foo</paragraph></tableCell></tableRow></table>' );
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<table><tableRow><tableCell><blockQuote><paragraph>[]foo</paragraph></blockQuote></tableCell></tableRow></table>'
);
} );
it( 'unwraps paragraph in table cell', () => {
setModelData(
model,
'<table><tableRow><tableCell><blockQuote><paragraph>[]foo</paragraph></blockQuote></tableCell></tableRow></table>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<table><tableRow><tableCell><paragraph>[]foo</paragraph></tableCell></tableRow></table>'
);
} );
it( 'wraps image in table cell', () => {
setModelData( model,
'<table>' +
'<tableRow>' +
'<tableCell>[<imageBlock><caption>foo</caption></imageBlock>]</tableCell>' +
' </tableRow>' +
'</table>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<table>' +
'<tableRow>' +
'<tableCell><blockQuote>[<imageBlock><caption>foo</caption></imageBlock>]</blockQuote></tableCell>' +
'</tableRow>' +
'</table>'
);
} );
it( 'unwraps image in table cell', () => {
setModelData( model,
'<table>' +
'<tableRow>' +
'<tableCell><blockQuote>[<imageBlock><caption>foo</caption></imageBlock>]</blockQuote></tableCell>' +
'</tableRow>' +
'</table>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<table>' +
'<tableRow>' +
'<tableCell>[<imageBlock><caption>foo</caption></imageBlock>]</tableCell>' +
'</tableRow>' +
'</table>'
);
} );
it( 'wraps paragraph+image in table cell', () => {
setModelData( model,
'<table>' +
'<tableRow>' +
'<tableCell><paragraph>[foo</paragraph><imageBlock><caption>foo</caption></imageBlock>]</tableCell>' +
'</tableRow>' +
'</table>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<table>' +
'<tableRow>' +
'<tableCell>' +
'<blockQuote><paragraph>[foo</paragraph><imageBlock><caption>foo</caption></imageBlock>]</blockQuote>' +
'</tableCell>' +
'</tableRow>' +
'</table>'
);
} );
it( 'unwraps paragraph+image in table cell', () => {
setModelData( model,
'<table>' +
'<tableRow>' +
'<tableCell>' +
'<blockQuote><paragraph>[foo</paragraph><imageBlock><caption>foo</caption></imageBlock>]</blockQuote>' +
'</tableCell>' +
'</tableRow>' +
'</table>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<table>' +
'<tableRow>' +
'<tableCell><paragraph>[foo</paragraph><imageBlock><caption>foo</caption></imageBlock>]</tableCell>' +
'</tableRow>' +
'</table>'
);
} );
it( 'wraps image+paragraph in table cell', () => {
setModelData( model,
'<table>' +
'<tableRow>' +
'<tableCell>[<imageBlock><caption>foo</caption></imageBlock><paragraph>foo]</paragraph></tableCell>' +
'</tableRow>' +
'</table>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<table>' +
'<tableRow>' +
'<tableCell>' +
'<blockQuote>[<imageBlock><caption>foo</caption></imageBlock><paragraph>foo]</paragraph></blockQuote>' +
'</tableCell>' +
'</tableRow>' +
'</table>'
);
} );
it( 'unwraps image+paragraph in table cell', () => {
setModelData( model,
'<table>' +
'<tableRow>' +
'<tableCell>[<imageBlock><caption>foo</caption></imageBlock><paragraph>foo]</paragraph></tableCell>' +
'</tableRow>' +
'</table>'
);
editor.execute( 'blockQuote' );
expect( getModelData( model ) ).to.equal(
'<table>' +
'<tableRow>' +
'<tableCell>' +
'<blockQuote>[<imageBlock><caption>foo</caption></imageBlock><paragraph>foo]</paragraph></blockQuote>' +
'</tableCell>' +
'</tableRow>' +
'</table>'
);
} );
} );
describe( 'autoparagraphing', () => {
it( 'text in block quote in div', () => {
const data =
'<blockquote>' +
'<div>foo<strong>bar</strong></div>' +
'</blockquote>' +
'xyz';
editor.setData( data );
expect( editor.getData() ).to.equal(
'<blockquote>' +
'<p>foo<strong>bar</strong></p>' +
'</blockquote>' +
'<p>xyz</p>'
);
} );
it( 'text directly in block quote', () => {
const data =
'<blockquote>' +
'foo<strong>bar</strong>' +
'</blockquote>' +
'xyz';
editor.setData( data );
expect( editor.getData() ).to.equal(
'<blockquote>' +
'<p>foo<strong>bar</strong></p>' +
'</blockquote>' +
'<p>xyz</p>'
);
} );
it( 'text after block quote in div', () => {
const data =
'<blockquote>' +
'foo<strong>bar</strong>' +
'</blockquote>' +
'<div>xyz</div>';
editor.setData( data );
expect( editor.getData() ).to.equal(
'<blockquote>' +
'<p>foo<strong>bar</strong></p>' +
'</blockquote>' +
'<p>xyz</p>'
);
} );
it( 'text inside block quote in and after div', () => {
const data =
'<blockquote>' +
'<div>foo</div><strong>bar</strong>' +
'</blockquote>' +
'xyz';
editor.setData( data );
expect( editor.getData() ).to.equal(
'<blockquote>' +
'<p>foo</p><p><strong>bar</strong></p>' +
'</blockquote>' +
'<p>xyz</p>'
);
} );
it( 'text inside block quote in div split by heading', () => {
const data =
'<blockquote>' +
'<div>foo<h2>bar</h2><strong>baz</strong></div>' +
'</blockquote>' +
'xyz';
editor.setData( data );
expect( editor.getData() ).to.equal(
'<blockquote>' +
'<p>foo</p><h2>bar</h2><p><strong>baz</strong></p>' +
'</blockquote>' +
'<p>xyz</p>'
);
} );
} );
} );

View File

@ -1,25 +0,0 @@
<div id="editor">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla finibus consequat placerat. Vestibulum id tellus et mauris sagittis tincidunt quis id mauris. Curabitur consectetur lectus sit amet tellus mattis, non lobortis leo interdum.</p>
<blockquote>
<p>Nulla finibus consequat placerat. Vestibulum id tellus et mauris sagittis tincidunt quis id mauris. Curabitur consectetur lectus sit amet tellus mattis, non lobortis leo interdum.</p>
</blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla finibus consequat placerat.</p>
<figure class="image">
<img src="logo.png" alt="CKEditor logo" />
</figure>
<p>Vestibulum id tellus et mauris sagittis tincidunt quis id mauris. Curabitur consectetur lectus sit amet tellus mattis, non lobortis leo interdum.</p>
<blockquote>
<p>Nulla finibus consequat placerat. Vestibulum id tellus et mauris sagittis tincidunt quis id mauris.</p>
<ul>
<li>Curabitur consectetur lectus sit amet tellus mattis, non lobortis leo interdum.</li>
</ul>
</blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla finibus consequat placerat. Vestibulum id tellus et mauris sagittis tincidunt quis id mauris. Curabitur consectetur lectus sit amet tellus mattis, non lobortis leo interdum.</p>
<blockquote>
<p>Nulla finibus consequat placerat. Vestibulum id tellus et mauris sagittis tincidunt quis id mauris.</p>
<blockquote>
<p>Curabitur consectetur lectus sit amet tellus mattis, non lobortis leo interdum.</p>
</blockquote>
</blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla finibus consequat placerat. Vestibulum id tellus et mauris sagittis tincidunt quis id mauris. Curabitur consectetur lectus sit amet tellus mattis, non lobortis leo interdum.</p>
</div>

View File

@ -1,24 +0,0 @@
/**
* @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
*/
/* global document, console, window */
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor.js';
import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset.js';
ClassicEditor
.create( document.querySelector( '#editor' ), {
image: { toolbar: [ 'toggleImageCaption', 'imageTextAlternative' ] },
plugins: [
ArticlePluginSet
],
toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ]
} )
.then( editor => {
window.editor = editor;
} )
.catch( err => {
console.error( err.stack );
} );

View File

@ -1,12 +0,0 @@
## Block quote feature
Check block quote related behaviors:
* applying quotes to multiple blocks,
* removing quotes,
* <kbd>Enter</kbd> (should leave quote when pressed in an empty block),
* <kbd>Backspace</kbd>,
* undo/redo,
* applying headings and lists,
* stability when used with nested lists,
* stability when used with nested block quotes.

View File

@ -1,20 +0,0 @@
<style>
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 14px;
}
</style>
<div id="editor">
<p>Nested block quotes (in the data):</p>
<blockquote>
<p>Nulla finibus consequat placerat. Vestibulum id tellus et mauris sagittis tincidunt quis id mauris.</p>
<blockquote>
<p>Curabitur consectetur lectus sit amet tellus mattis, non lobortis leo interdum.</p>
<blockquote>
<p>Vestibulum id tellus et mauris sagittis tincidunt quis id mauris. Curabitur consectetur lectus sit amet tellus mattis, non lobortis leo interdum.</p>
</blockquote>
</blockquote>
</blockquote>
</div>

View File

@ -1,36 +0,0 @@
/**
* @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
*/
/* globals console, window, document */
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor.js';
import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset.js';
function DisallowNestingBlockQuotes( editor ) {
editor.model.schema.addChildCheck( ( context, childDefinition ) => {
if ( context.endsWith( 'blockQuote' ) && childDefinition.name == 'blockQuote' ) {
return false;
}
} );
}
ClassicEditor
.create( document.querySelector( '#editor' ), {
image: { toolbar: [ 'toggleImageCaption', 'imageTextAlternative' ] },
plugins: [ ArticlePluginSet, DisallowNestingBlockQuotes ],
toolbar: [
'heading', '|', 'insertTable', '|', 'bold', 'italic', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo'
],
table: {
contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ],
tableToolbar: [ 'bold', 'italic' ]
}
} )
.then( editor => {
window.editor = editor;
} )
.catch( err => {
console.error( err.stack );
} );

View File

@ -1,2 +0,0 @@
* The nested block quote present in the data should be "unnested" ("unwrapped") on data load. All block quotes (the top level block quote and all nested ones) should be converted to siblings in editor's root.
* It should not be possible to insert a block quote into another block quote as a direct child in any way (UI, paste, d&d, etc.). It is allowed to have nested block quotes indirectly, i.e. a block quote inside a table, which is inside another block quote.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB