diff --git a/src/converters.js b/src/converters.js
index 6f78eee..3be0397 100644
--- a/src/converters.js
+++ b/src/converters.js
@@ -365,8 +365,14 @@ export function viewModelConverter( evt, data, consumable, conversionApi ) {
const type = data.input.parent && data.input.parent.name == 'ol' ? 'numbered' : 'bulleted';
writer.setAttribute( 'type', type, listItem );
- // 3. Handle `
` children.
- data.context.push( listItem );
+ let alteredContext = false;
+
+ // See https://github.com/ckeditor/ckeditor5-list/issues/87
+ if ( data.context[ data.context.length - 1 ].name != 'listItem' ) {
+ // 3. Handle `` children.
+ data.context.push( listItem );
+ alteredContext = true;
+ }
// `listItem`s created recursively should have bigger indent.
data.indent++;
@@ -394,7 +400,9 @@ export function viewModelConverter( evt, data, consumable, conversionApi ) {
}
data.indent--;
- data.context.pop();
+ if ( alteredContext ) {
+ data.context.pop();
+ }
data.output = items;
}
diff --git a/src/listcommand.js b/src/listcommand.js
index aca0609..071e77e 100644
--- a/src/listcommand.js
+++ b/src/listcommand.js
@@ -8,7 +8,6 @@
*/
import Command from '@ckeditor/ckeditor5-core/src/command';
-import Position from '@ckeditor/ckeditor5-engine/src/model/position';
import first from '@ckeditor/ckeditor5-utils/src/first';
/**
@@ -308,9 +307,5 @@ function _fixType( blocks, isBackward, lowestIndent ) {
// @param {module:engine/model/schema~Schema} schema The schema of the document.
// @returns {Boolean}
function checkCanBecomeListItem( block, schema ) {
- return schema.check( {
- name: 'listItem',
- attributes: [ 'type', 'indent' ],
- inside: Position.createBefore( block )
- } );
+ return schema.checkChild( block.parent, 'listItem' ) && !schema.isObject( block );
}
diff --git a/src/listengine.js b/src/listengine.js
index 7a3ab5e..fcae48d 100644
--- a/src/listengine.js
+++ b/src/listengine.js
@@ -50,18 +50,13 @@ export default class ListEngine extends Plugin {
const editor = this.editor;
// Schema.
- // Note: in case `$block` will be ever allowed in `listItem`, keep in mind that this feature
+ // Note: in case `$block` will ever be allowed in `listItem`, keep in mind that this feature
// uses `Selection#getSelectedBlocks()` without any additional processing to obtain all selected list items.
// If there are blocks allowed inside list item, algorithms using `getSelectedBlocks()` will have to be modified.
- const schema = editor.model.schema;
- schema.registerItem( 'listItem', '$block' );
- schema.allow( {
- name: 'listItem',
- inside: '$root',
- coinside: '$root',
- attributes: [ 'type', 'indent' ]
+ editor.model.schema.register( 'listItem', {
+ inheritAllFrom: '$block',
+ allowAttributes: [ 'type', 'indent' ]
} );
- schema.requireAttributes( 'listItem', [ 'type', 'indent' ] );
// Converters.
const data = editor.data;
diff --git a/tests/indentcommand.js b/tests/indentcommand.js
index 6648aaa..641e79a 100644
--- a/tests/indentcommand.js
+++ b/tests/indentcommand.js
@@ -21,12 +21,11 @@ describe( 'IndentCommand', () => {
doc = model.document;
root = doc.createRoot();
- model.schema.registerItem( 'listItem', '$block' );
- model.schema.registerItem( 'paragraph', '$block' );
-
- model.schema.allow( { name: '$block', inside: '$root' } );
- model.schema.allow( { name: 'listItem', attributes: [ 'type', 'indent' ], inside: '$root' } );
- model.schema.allow( { name: 'paragraph', inside: '$root' } );
+ model.schema.register( 'listItem', {
+ inheritAllFrom: '$block',
+ allowAttributes: [ 'type', 'indent' ]
+ } );
+ model.schema.register( 'paragraph', { inheritAllFrom: '$block' } );
setData(
model,
@@ -117,7 +116,7 @@ describe( 'IndentCommand', () => {
// Edge case but may happen that some other blocks will also use the indent attribute
// and before we fixed it the command was enabled in such a case.
it( 'should be false if selection starts in a paragraph with indent attribute', () => {
- model.schema.allow( { name: 'paragraph', attributes: [ 'indent' ], inside: '$root' } );
+ model.schema.extend( 'paragraph', { allowAttributes: 'indent' } );
setData( model, 'ab[]' );
diff --git a/tests/listcommand.js b/tests/listcommand.js
index c4843c5..d33bfdb 100644
--- a/tests/listcommand.js
+++ b/tests/listcommand.js
@@ -23,14 +23,24 @@ describe( 'ListCommand', () => {
command = new ListCommand( editor, 'bulleted' );
- model.schema.registerItem( 'listItem', '$block' );
- model.schema.registerItem( 'paragraph', '$block' );
- model.schema.registerItem( 'widget', '$block' );
+ model.schema.register( 'listItem', {
+ inheritAllFrom: '$block',
+ allowAttributes: [ 'type', 'indent' ]
+ } );
+ model.schema.register( 'paragraph', {
+ inheritAllFrom: '$block',
+ allowIn: 'widget'
+ } );
+ model.schema.register( 'widget', { inheritAllFrom: '$block' } );
- model.schema.allow( { name: '$block', inside: '$root' } );
- model.schema.allow( { name: 'paragraph', inside: 'widget' } );
- model.schema.allow( { name: 'listItem', attributes: [ 'type', 'indent' ], inside: '$root' } );
- model.schema.disallow( { name: 'listItem', attributes: [ 'type', 'indent' ], inside: 'widget' } );
+ model.schema.on( 'checkChild', ( evt, args ) => {
+ const def = model.schema.getDefinition( args[ 1 ] );
+
+ if ( args[ 0 ].endsWith( 'widget' ) && def.name == 'listItem' ) {
+ evt.stop();
+ evt.return = false;
+ }
+ } );
setData(
model,
@@ -247,13 +257,12 @@ describe( 'ListCommand', () => {
} );
// https://github.com/ckeditor/ckeditor5-list/issues/62
- it( 'should not rename blocks which cannot become listItems', () => {
- model.schema.registerItem( 'restricted' );
- model.schema.allow( { name: 'restricted', inside: '$root' } );
- model.schema.disallow( { name: 'paragraph', inside: 'restricted' } );
+ it( 'should not rename blocks which cannot become listItems (list item is not allowed in their parent)', () => {
+ model.schema.register( 'restricted' );
+ model.schema.extend( 'restricted', { allowIn: '$root' } );
- model.schema.registerItem( 'fooBlock', '$block' );
- model.schema.allow( { name: 'fooBlock', inside: 'restricted' } );
+ model.schema.register( 'fooBlock', { inheritAllFrom: '$block' } );
+ model.schema.extend( 'fooBlock', { allowIn: 'restricted' } );
setData(
model,
@@ -271,6 +280,29 @@ describe( 'ListCommand', () => {
);
} );
+ it( 'should not rename blocks which cannot become listItems (block is an object)', () => {
+ model.schema.register( 'image', {
+ isBlock: true,
+ isObject: true,
+ allowIn: '$root'
+ } );
+
+ setData(
+ model,
+ 'a[bc' +
+ '' +
+ 'de]f'
+ );
+
+ command.execute();
+
+ expect( getData( model ) ).to.equal(
+ 'a[bc' +
+ '' +
+ 'de]f'
+ );
+ } );
+
it( 'should rename closest block to listItem and set correct attributes', () => {
// From first paragraph to second paragraph.
// Command value=false, we are turning on list items.
diff --git a/tests/listengine.js b/tests/listengine.js
index b253ebf..97cb81c 100644
--- a/tests/listengine.js
+++ b/tests/listengine.js
@@ -51,17 +51,16 @@ describe( 'ListEngine', () => {
} );
it( 'should set proper schema rules', () => {
- expect( model.schema.hasItem( 'listItem' ) );
- expect( model.schema.itemExtends( 'listItem', '$block' ) );
+ expect( model.schema.isRegistered( 'listItem' ) );
+ expect( model.schema.isBlock( 'listItem' ) );
- expect( model.schema.check( { name: '$inline', inside: 'listItem' } ) ).to.be.true;
- expect( model.schema.check( { name: 'listItem', inside: 'listItem' } ) ).to.be.false;
- expect( model.schema.check( { name: '$block', inside: 'listItem' } ) ).to.be.false;
+ expect( model.schema.checkChild( [ '$root' ], 'listItem' ) ).to.be.true;
+ expect( model.schema.checkChild( [ '$root', 'listItem' ], '$text' ) ).to.be.true;
+ expect( model.schema.checkChild( [ '$root', 'listItem' ], 'listItem' ) ).to.be.false;
+ expect( model.schema.checkChild( [ '$root', 'listItem' ], '$block' ) ).to.be.false;
- expect( model.schema.check( { name: 'listItem', inside: '$root' } ) ).to.be.false;
- expect( model.schema.check( { name: 'listItem', inside: '$root', attributes: [ 'indent' ] } ) ).to.be.false;
- expect( model.schema.check( { name: 'listItem', inside: '$root', attributes: [ 'type' ] } ) ).to.be.false;
- expect( model.schema.check( { name: 'listItem', inside: '$root', attributes: [ 'indent', 'type' ] } ) ).to.be.true;
+ expect( model.schema.checkAttribute( [ '$root', 'listItem' ], 'indent' ) ).to.be.true;
+ expect( model.schema.checkAttribute( [ '$root', 'listItem' ], 'type' ) ).to.be.true;
} );
describe( 'commands', () => {