From d00ed5a89342bb7be6a98da85b2db9ebe51025d4 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 7 Apr 2021 09:25:35 +0200 Subject: [PATCH 01/16] Added support for allowChildren property. --- packages/ckeditor5-engine/src/model/schema.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/ckeditor5-engine/src/model/schema.js b/packages/ckeditor5-engine/src/model/schema.js index af7db81d7b7..9e999a7cdef 100644 --- a/packages/ckeditor5-engine/src/model/schema.js +++ b/packages/ckeditor5-engine/src/model/schema.js @@ -883,6 +883,10 @@ export default class Schema { compiledDefinitions[ itemName ] = compileBaseItemRule( sourceRules[ itemName ], itemName ); } + for ( const itemName of itemNames ) { + compileAllowChildren( compiledDefinitions, itemName ); + } + for ( const itemName of itemNames ) { compileAllowContentOf( compiledDefinitions, itemName ); } @@ -1090,6 +1094,7 @@ mix( Schema, ObservableMixin ); * You can define the following rules: * * * {@link ~SchemaItemDefinition#allowIn `allowIn`} – Defines in which other items this item will be allowed. + * * {@link ~SchemaItemDefinition#allowChildren `allowChildren`} – Defines which other items are allowed inside this item. * * {@link ~SchemaItemDefinition#allowAttributes `allowAttributes`} – Defines allowed attributes of the given item. * * {@link ~SchemaItemDefinition#allowContentOf `allowContentOf`} – Inherits "allowed children" from other items. * * {@link ~SchemaItemDefinition#allowWhere `allowWhere`} – Inherits "allowed in" from other items. @@ -1157,6 +1162,14 @@ mix( Schema, ObservableMixin ); * isBlock: true * } ); * + * Allow `paragraph` inside a `$root` and allow `$text` as a `paragraph` child: + * + * schema.register( 'paragraph', { + * allowIn: '$root', + * allowChildren: '$text', + * isBlock: true + * } ); + * * Make `image` a block object, which is allowed everywhere where `$block` is. * Also, allow `src` and `alt` attributes in it: * @@ -1205,6 +1218,7 @@ mix( Schema, ObservableMixin ); * @typedef {Object} module:engine/model/schema~SchemaItemDefinition * * @property {String|Array.} allowIn Defines in which other items this item will be allowed. + * @property {String|Array.} allowChildren Defines which other items are allowed inside this item. * @property {String|Array.} allowAttributes Defines allowed attributes of the given item. * @property {String|Array.} allowContentOf Inherits "allowed children" from other items. * @property {String|Array.} allowWhere Inherits "allowed in" from other items. @@ -1566,6 +1580,8 @@ function compileBaseItemRule( sourceItemRules, itemName ) { allowAttributes: [], allowAttributesOf: [], + allowChildren: [], + inheritTypesFrom: [] }; @@ -1578,6 +1594,8 @@ function compileBaseItemRule( sourceItemRules, itemName ) { copyProperty( sourceItemRules, itemRule, 'allowAttributes' ); copyProperty( sourceItemRules, itemRule, 'allowAttributesOf' ); + copyProperty( sourceItemRules, itemRule, 'allowChildren' ); + copyProperty( sourceItemRules, itemRule, 'inheritTypesFrom' ); makeInheritAllWork( sourceItemRules, itemRule ); @@ -1585,6 +1603,22 @@ function compileBaseItemRule( sourceItemRules, itemName ) { return itemRule; } +function compileAllowChildren( compiledDefinitions, itemName ) { + const item = compiledDefinitions[ itemName ]; + + for ( const allowChildrenItem of item.allowChildren ) { + const allowedChildren = compiledDefinitions[ allowChildrenItem ]; + + if ( !allowedChildren ) { + continue; + } + + allowedChildren.allowIn.push( itemName ); + } + + delete item.allowChildren; +} + function compileAllowContentOf( compiledDefinitions, itemName ) { for ( const allowContentOfItemName of compiledDefinitions[ itemName ].allowContentOf ) { // The allowContentOf property may point to an unregistered element. From c9ddd79b441fb358d7c1a65b1aa44a71dd29cafd Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 7 Apr 2021 09:26:15 +0200 Subject: [PATCH 02/16] Added allowChildren tests. --- .../ckeditor5-engine/tests/model/schema.js | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/packages/ckeditor5-engine/tests/model/schema.js b/packages/ckeditor5-engine/tests/model/schema.js index 0baa547c7d1..8cc4da3af74 100644 --- a/packages/ckeditor5-engine/tests/model/schema.js +++ b/packages/ckeditor5-engine/tests/model/schema.js @@ -2411,6 +2411,173 @@ describe( 'Schema', () => { // } ); } ); + describe( 'allowChildren', () => { + it( 'allows item in another item', () => { + schema.register( 'paragraph' ); + + schema.register( '$root', { + allowChildren: 'paragraph' + } ); + + expect( schema.checkChild( root1, r1p1 ) ).to.be.true; + } ); + + it( 'supports the array syntax', () => { + schema.register( 'paragraph' ); + schema.register( 'blockQuote' ); + + schema.register( '$root', { + allowChildren: [ 'paragraph', 'blockQuote' ] + } ); + + expect( schema.checkChild( root1, r1p1 ) ).to.be.true; + expect( schema.checkChild( root1, r1bQ ) ).to.be.true; + } ); + + it( 'supports circular references', () => { + schema.register( '$root', { + allowChildren: [ 'paragraph', 'blockQuote' ] + } ); + + schema.register( 'paragraph', { + allowChildren: 'blockQuote' + } ); + + schema.register( 'blockQuote', { + allowChildren: 'paragraph' + } ); + + expect( schema.checkChild( r1p1, r1bQ ) ).to.be.true; + expect( schema.checkChild( r1bQ, r1p1 ) ).to.be.true; + } ); + + it( 'supports self-reference', () => { + schema.register( '$root', { + allowChildren: 'paragraph' + } ); + + schema.register( 'paragraph', { + allowChildren: 'paragraph' + } ); + + expect( schema.checkChild( r1p1, r1p1 ) ).to.be.true; + } ); + + it( 'passes $root>$paragraph>div>blockQuote - deep nesting', () => { + schema.register( '$root', { + allowChildren: 'paragraph' + } ); + + schema.register( 'paragraph', { + allowChildren: 'div' + } ); + + schema.register( 'div', { + allowChildren: 'blockQuote' + } ); + + schema.register( 'blockQuote' ); + + const paragraph = new Element( 'paragraph' ); + root1._appendChild( paragraph ); + + const div = new Element( 'div' ); + paragraph._appendChild( div ); + + const blockQuote = new Element( 'blockQuote' ); + div._appendChild( blockQuote ); + + expect( schema.checkChild( root1, paragraph ) ).to.be.true; + expect( schema.checkChild( paragraph, div ) ).to.be.true; + expect( schema.checkChild( div, blockQuote ) ).to.be.true; + + expect( schema.checkChild( paragraph, blockQuote ) ).to.be.false; + expect( schema.checkChild( div, paragraph ) ).to.be.false; + } ); + + it( 'should remove allowChildren from definition', () => { + schema.register( '$root', { + allowChildren: 'paragraph' + } ); + + schema.register( 'paragraph' ); + + expect( schema.getDefinition( '$root' ) ).to.deep.equal( { + allowAttributes: [], + allowIn: [], + name: '$root' + } ); + } ); + + it( 'should add parent item to child allowIn property', () => { + schema.register( '$root', { + allowChildren: 'paragraph' + } ); + + schema.register( 'div', { + allowChildren: 'paragraph' + } ); + + schema.register( 'paragraph' ); + + expect( schema.getDefinition( 'paragraph' ) ).to.deep.equal( { + allowAttributes: [], + allowIn: [ '$root', 'div' ], + name: 'paragraph' + } ); + } ); + + it( 'should add parent item to child allowIn property - self reference', () => { + schema.register( 'paragraph', { + allowChildren: 'paragraph' + } ); + + expect( schema.getDefinition( 'paragraph' ) ).to.deep.equal( { + allowAttributes: [], + allowIn: [ 'paragraph' ], + name: 'paragraph' + } ); + } ); + + it( 'should add parent item to child allowIn property - circular reference', () => { + schema.register( 'paragraph', { + allowChildren: 'blockQuote' + } ); + + schema.register( 'blockQuote', { + allowChildren: 'paragraph' + } ); + + expect( schema.getDefinition( 'paragraph' ) ).to.deep.equal( { + allowAttributes: [], + allowIn: [ 'blockQuote' ], + name: 'paragraph' + } ); + + expect( schema.getDefinition( 'blockQuote' ) ).to.deep.equal( { + allowAttributes: [], + allowIn: [ 'paragraph' ], + name: 'blockQuote' + } ); + } ); + + it( 'should include only one allowIn item for definition defined in both allowIn and allowChildren', () => { + schema.register( '$root', { + allowChildren: 'paragraph' + } ); + + schema.register( 'paragraph', { + allowIn: '$root' + } ); + + expect( schema.getDefinition( 'paragraph' ) ).to.deep.equal( { + allowAttributes: [], + allowIn: [ '$root' ], + name: 'paragraph' + } ); + } ); + } ); + describe( 'inheritTypesFrom', () => { it( 'inherit properties of another item', () => { schema.register( '$block', { @@ -2583,6 +2750,15 @@ describe( 'Schema', () => { expect( schema.checkChild( root1, '$text' ) ).to.be.false; } ); + it( 'does not break when used allowChildren pointing to an non-register element', () => { + schema.register( '$root' ); + schema.register( '$text', { + allowChildren: 'foo404' + } ); + + expect( schema.checkChild( root1, '$text' ) ).to.be.false; + } ); + it( 'does not break when used allowWhere pointing to an non-registered element', () => { schema.register( '$root' ); schema.register( '$text', { From ad4a59937f16f9c12425d88ec0aa91aff42263b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20Bogda=C5=84ski?= Date: Wed, 14 Apr 2021 12:28:27 +0200 Subject: [PATCH 03/16] Commenting. Co-authored-by: Kuba Niegowski <1232187+niegowski@users.noreply.github.com> --- packages/ckeditor5-engine/src/model/schema.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ckeditor5-engine/src/model/schema.js b/packages/ckeditor5-engine/src/model/schema.js index 9e999a7cdef..c71573525b7 100644 --- a/packages/ckeditor5-engine/src/model/schema.js +++ b/packages/ckeditor5-engine/src/model/schema.js @@ -1609,6 +1609,7 @@ function compileAllowChildren( compiledDefinitions, itemName ) { for ( const allowChildrenItem of item.allowChildren ) { const allowedChildren = compiledDefinitions[ allowChildrenItem ]; + // The allowChildren property may point to an unregistered element. if ( !allowedChildren ) { continue; } From 0b7e00134b10c593af9318900202e1383090a084 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 14 Apr 2021 13:09:29 +0200 Subject: [PATCH 04/16] Include allowChildren in schema definition. --- packages/ckeditor5-engine/src/model/schema.js | 15 +++++- .../ckeditor5-engine/tests/model/schema.js | 49 ++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/packages/ckeditor5-engine/src/model/schema.js b/packages/ckeditor5-engine/src/model/schema.js index c71573525b7..0ddc531b0ad 100644 --- a/packages/ckeditor5-engine/src/model/schema.js +++ b/packages/ckeditor5-engine/src/model/schema.js @@ -902,6 +902,7 @@ export default class Schema { for ( const itemName of itemNames ) { cleanUpAllowIn( compiledDefinitions, itemName ); + cleanUpAllowChildren( compiledDefinitions, itemName ); cleanUpAllowAttributes( compiledDefinitions, itemName ); } @@ -1617,7 +1618,9 @@ function compileAllowChildren( compiledDefinitions, itemName ) { allowedChildren.allowIn.push( itemName ); } - delete item.allowChildren; + // allowIn already includes correct items, reset allowChildren + // to avoid duplicates later when cleaning up compilation results. + item.allowChildren = []; } function compileAllowContentOf( compiledDefinitions, itemName ) { @@ -1693,6 +1696,16 @@ function cleanUpAllowIn( compiledDefinitions, itemName ) { itemRule.allowIn = Array.from( new Set( existingItems ) ); } +// Restore allowChildren items based on allowIn. +function cleanUpAllowChildren( compiledDefinitions, itemName ) { + const itemRule = compiledDefinitions[ itemName ]; + + for ( const allowItemName of itemRule.allowIn ) { + const allowedItem = compiledDefinitions[ allowItemName ]; + allowedItem.allowChildren.push( itemName ); + } +} + function cleanUpAllowAttributes( compiledDefinitions, itemName ) { const itemRule = compiledDefinitions[ itemName ]; diff --git a/packages/ckeditor5-engine/tests/model/schema.js b/packages/ckeditor5-engine/tests/model/schema.js index 8cc4da3af74..eb8b0d42116 100644 --- a/packages/ckeditor5-engine/tests/model/schema.js +++ b/packages/ckeditor5-engine/tests/model/schema.js @@ -164,6 +164,7 @@ describe( 'Schema', () => { expect( definitions.foo ).to.deep.equal( { name: 'foo', allowIn: [ '$root' ], + allowChildren: [], allowAttributes: [], isBlock: true } ); @@ -207,6 +208,7 @@ describe( 'Schema', () => { expect( definitions.foo ).to.deep.equal( { name: 'foo', allowIn: [ '$root' ], + allowChildren: [], allowAttributes: [] } ); } ); @@ -221,6 +223,7 @@ describe( 'Schema', () => { expect( definitions.foo ).to.deep.equal( { name: 'foo', allowIn: [], + allowChildren: [], allowAttributes: [] } ); } ); @@ -238,6 +241,7 @@ describe( 'Schema', () => { expect( definitions.paragraph ).to.deep.equal( { name: 'paragraph', allowIn: [], + allowChildren: [], allowAttributes: [ 'foo' ] } ); } ); @@ -256,6 +260,7 @@ describe( 'Schema', () => { expect( definitions.paragraph ).to.deep.equal( { name: 'paragraph', allowIn: [], + allowChildren: [], allowAttributes: [ 'foo' ] } ); } ); @@ -2495,7 +2500,7 @@ describe( 'Schema', () => { expect( schema.checkChild( div, paragraph ) ).to.be.false; } ); - it( 'should remove allowChildren from definition', () => { + it( 'should keep allowChildren', () => { schema.register( '$root', { allowChildren: 'paragraph' } ); @@ -2504,6 +2509,43 @@ describe( 'Schema', () => { expect( schema.getDefinition( '$root' ) ).to.deep.equal( { allowAttributes: [], + allowChildren: [ 'paragraph' ], + allowIn: [], + name: '$root' + } ); + } ); + + it( 'should resolve allowChildren from allowIn', () => { + schema.register( '$root' ); + + schema.register( 'paragraph', { + allowIn: '$root' + } ); + + schema.register( 'blockQuote', { + allowIn: '$root' + } ); + + expect( schema.getDefinition( '$root' ) ).to.deep.equal( { + allowAttributes: [], + allowChildren: [ 'paragraph', 'blockQuote' ], + allowIn: [], + name: '$root' + } ); + } ); + + it( 'should not duplicate allowChildren', () => { + schema.register( '$root', { + allowChildren: 'paragraph' + } ); + + schema.register( 'paragraph', { + allowIn: '$root' + } ); + + expect( schema.getDefinition( '$root' ) ).to.deep.equal( { + allowAttributes: [], + allowChildren: [ 'paragraph' ], allowIn: [], name: '$root' } ); @@ -2522,6 +2564,7 @@ describe( 'Schema', () => { expect( schema.getDefinition( 'paragraph' ) ).to.deep.equal( { allowAttributes: [], + allowChildren: [], allowIn: [ '$root', 'div' ], name: 'paragraph' } ); @@ -2534,6 +2577,7 @@ describe( 'Schema', () => { expect( schema.getDefinition( 'paragraph' ) ).to.deep.equal( { allowAttributes: [], + allowChildren: [ 'paragraph' ], allowIn: [ 'paragraph' ], name: 'paragraph' } ); @@ -2550,6 +2594,7 @@ describe( 'Schema', () => { expect( schema.getDefinition( 'paragraph' ) ).to.deep.equal( { allowAttributes: [], + allowChildren: [ 'blockQuote' ], allowIn: [ 'blockQuote' ], name: 'paragraph' } ); @@ -2557,6 +2602,7 @@ describe( 'Schema', () => { expect( schema.getDefinition( 'blockQuote' ) ).to.deep.equal( { allowAttributes: [], allowIn: [ 'paragraph' ], + allowChildren: [ 'paragraph' ], name: 'blockQuote' } ); } ); @@ -2572,6 +2618,7 @@ describe( 'Schema', () => { expect( schema.getDefinition( 'paragraph' ) ).to.deep.equal( { allowAttributes: [], + allowChildren: [], allowIn: [ '$root' ], name: 'paragraph' } ); From 603734d307ef636ceea45c169c8bc938dbb7870f Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 14 Apr 2021 14:23:53 +0200 Subject: [PATCH 05/16] Simplified code by introducing allowChildren where possible. --- .../tests/blockquotecommand.js | 2 +- .../tests/ckfindercommand.js | 27 ++++++++++++------- .../src/codeblockediting.js | 5 +--- .../tests/codeblockediting.js | 7 +++-- .../tests/ballooneditor.js | 7 ++--- .../tests/inlineeditor.js | 7 ++--- packages/ckeditor5-engine/src/model/model.js | 2 +- .../tests/controller/datacontroller.js | 3 +-- .../ckeditor5-engine/tests/dev-utils/model.js | 6 ++--- .../ckeditor5-engine/tests/model/selection.js | 4 +-- .../tests/image/insertimagecommand.js | 3 +-- packages/ckeditor5-image/tests/image/utils.js | 2 +- .../tests/imageupload/imageuploadediting.js | 2 +- .../tests/imageupload/uploadimagecommand.js | 2 +- packages/ckeditor5-link/tests/linkcommand.js | 6 ++--- .../tests/insertmediacommand.js | 3 +-- .../tests/pagebreakcommand.js | 6 ++--- .../ckeditor5-paragraph/tests/paragraph.js | 6 ++--- packages/ckeditor5-table/src/tableediting.js | 4 +-- .../tests/converters/upcasttable.js | 15 ++++++++--- .../tests/widgettoolbarrepository.js | 6 ++--- 21 files changed, 63 insertions(+), 62 deletions(-) diff --git a/packages/ckeditor5-block-quote/tests/blockquotecommand.js b/packages/ckeditor5-block-quote/tests/blockquotecommand.js index f0fc25c5fe3..fe1c464ede5 100644 --- a/packages/ckeditor5-block-quote/tests/blockquotecommand.js +++ b/packages/ckeditor5-block-quote/tests/blockquotecommand.js @@ -31,10 +31,10 @@ describe( 'BlockQuoteCommand', () => { model.schema.extend( 'widget', { allowIn: '$root', + allowChildren: '$text', isLimit: true, isObject: true } ); - model.schema.extend( '$text', { allowIn: 'widget' } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'paragraph', view: 'p' } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'heading', view: 'h' } ); diff --git a/packages/ckeditor5-ckfinder/tests/ckfindercommand.js b/packages/ckeditor5-ckfinder/tests/ckfindercommand.js index 93d9ac959e5..5bd26e776bc 100644 --- a/packages/ckeditor5-ckfinder/tests/ckfindercommand.js +++ b/packages/ckeditor5-ckfinder/tests/ckfindercommand.js @@ -59,9 +59,10 @@ describe( 'CKFinderCommand', () => { } ); it( 'should be true where only image is allowed', () => { - model.schema.register( 'block', { inheritAllFrom: '$block' } ); - model.schema.extend( 'paragraph', { allowIn: 'block' } ); - model.schema.extend( 'image', { allowIn: 'block' } ); + model.schema.register( 'block', { + inheritAllFrom: '$block', + allowChildren: [ 'paragraph', 'image' ] + } ); // Block link attribute. model.schema.addAttributeCheck( ( ctx, attributeName ) => ( attributeName !== 'linkHref' ) ); @@ -74,8 +75,10 @@ describe( 'CKFinderCommand', () => { } ); it( 'should be true where only link is allowed', () => { - model.schema.register( 'block', { inheritAllFrom: '$block' } ); - model.schema.extend( 'paragraph', { allowIn: 'block' } ); + model.schema.register( 'block', { + inheritAllFrom: '$block', + allowChildren: 'paragraph' + } ); // Block image in block. model.schema.addChildCheck( ( context, childDefinition ) => { @@ -92,8 +95,10 @@ describe( 'CKFinderCommand', () => { } ); it( 'should be false where link & image are not allowed', () => { - model.schema.register( 'block', { inheritAllFrom: '$block' } ); - model.schema.extend( 'paragraph', { allowIn: 'block' } ); + model.schema.register( 'block', { + inheritAllFrom: '$block', + allowChildren: 'paragraph' + } ); // Block link attribute - image is not allowed in 'block'. model.schema.addAttributeCheck( ( ctx, attributeName ) => ( attributeName !== 'linkHref' ) ); @@ -368,8 +373,10 @@ describe( 'CKFinderCommand', () => { } ); it( 'should show warning notification if image cannot be inserted', done => { - model.schema.register( 'block', { inheritAllFrom: '$block' } ); - model.schema.extend( 'paragraph', { allowIn: 'block' } ); + model.schema.register( 'block', { + inheritAllFrom: '$block', + allowChildren: 'paragraph' + } ); // Block image in block. model.schema.addChildCheck( ( context, childDefinition ) => { @@ -403,9 +410,9 @@ describe( 'CKFinderCommand', () => { it( 'should not insert image nor crash when image could not be inserted', () => { model.schema.register( 'other', { allowIn: '$root', + allowChildren: 'other', isLimit: true } ); - model.schema.extend( '$text', { allowIn: 'other' } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'other', view: 'p' } ); diff --git a/packages/ckeditor5-code-block/src/codeblockediting.js b/packages/ckeditor5-code-block/src/codeblockediting.js index 563cafae081..a71f93dd247 100644 --- a/packages/ckeditor5-code-block/src/codeblockediting.js +++ b/packages/ckeditor5-code-block/src/codeblockediting.js @@ -113,14 +113,11 @@ export default class CodeBlockEditing extends Plugin { schema.register( 'codeBlock', { allowWhere: '$block', + allowChildren: '$text', isBlock: true, allowAttributes: [ 'language' ] } ); - schema.extend( '$text', { - allowIn: 'codeBlock' - } ); - // Disallow all attributes on $text inside `codeBlock`. schema.addAttributeCheck( context => { if ( context.endsWith( 'codeBlock $text' ) ) { diff --git a/packages/ckeditor5-code-block/tests/codeblockediting.js b/packages/ckeditor5-code-block/tests/codeblockediting.js index c80a93250f8..dc616f988c8 100644 --- a/packages/ckeditor5-code-block/tests/codeblockediting.js +++ b/packages/ckeditor5-code-block/tests/codeblockediting.js @@ -246,8 +246,11 @@ describe( 'CodeBlockEditing', () => { } ); it( 'should execute enter command when pressing enter in an element nested inside a codeBlock', () => { - model.schema.register( 'codeBlockSub', { allowIn: 'codeBlock', isInline: true } ); - model.schema.extend( '$text', { allowIn: 'codeBlockSub' } ); + model.schema.register( 'codeBlockSub', { + allowIn: 'codeBlock', + allowChildren: '$text', + isInline: true + } ); editor.conversion.elementToElement( { model: 'codeBlockSub', view: 'codeBlockSub' } ); const enterCommand = editor.commands.get( 'enter' ); diff --git a/packages/ckeditor5-editor-balloon/tests/ballooneditor.js b/packages/ckeditor5-editor-balloon/tests/ballooneditor.js index 9077b4362ac..01b48a78e03 100644 --- a/packages/ckeditor5-editor-balloon/tests/ballooneditor.js +++ b/packages/ckeditor5-editor-balloon/tests/ballooneditor.js @@ -330,9 +330,10 @@ describe( 'BalloonEditor', () => { const schema = editor.model.schema; - schema.register( 'heading' ); - schema.extend( 'heading', { allowIn: '$root' } ); - schema.extend( '$text', { allowIn: 'heading' } ); + schema.register( 'heading', { + allowIn: '$root', + allowChildren: '$text' + } ); editor.conversion.for( 'upcast' ).elementToElement( { model: 'heading', view: 'heading' } ); editor.conversion.for( 'dataDowncast' ).elementToElement( { model: 'heading', view: 'heading' } ); diff --git a/packages/ckeditor5-editor-inline/tests/inlineeditor.js b/packages/ckeditor5-editor-inline/tests/inlineeditor.js index ae32a429a66..f0b0ca746a2 100644 --- a/packages/ckeditor5-editor-inline/tests/inlineeditor.js +++ b/packages/ckeditor5-editor-inline/tests/inlineeditor.js @@ -340,9 +340,10 @@ describe( 'InlineEditor', () => { const schema = editor.model.schema; - schema.register( 'heading' ); - schema.extend( 'heading', { allowIn: '$root' } ); - schema.extend( '$text', { allowIn: 'heading' } ); + schema.register( 'heading', { + allowIn: '$root', + allowChildren: '$text' + } ); editor.conversion.for( 'upcast' ).elementToElement( { model: 'heading', view: 'heading' } ); editor.conversion.for( 'dataDowncast' ).elementToElement( { model: 'heading', view: 'heading' } ); diff --git a/packages/ckeditor5-engine/src/model/model.js b/packages/ckeditor5-engine/src/model/model.js index 637273ca404..86c29f39743 100644 --- a/packages/ckeditor5-engine/src/model/model.js +++ b/packages/ckeditor5-engine/src/model/model.js @@ -106,9 +106,9 @@ export default class Model { } ); this.schema.register( '$clipboardHolder', { allowContentOf: '$root', + allowChildren: '$text', isLimit: true } ); - this.schema.extend( '$text', { allowIn: '$clipboardHolder' } ); // An element needed by the `upcastElementToMarker` converter. // This element temporarily represents a marker boundary during the conversion process and is removed diff --git a/packages/ckeditor5-engine/tests/controller/datacontroller.js b/packages/ckeditor5-engine/tests/controller/datacontroller.js index 9ba1ccea34e..3dd3192f1a4 100644 --- a/packages/ckeditor5-engine/tests/controller/datacontroller.js +++ b/packages/ckeditor5-engine/tests/controller/datacontroller.js @@ -160,8 +160,7 @@ describe( 'DataController', () => { it( 'should accept parsing context', () => { modelDocument.createRoot( 'inlineRoot', 'inlineRoot' ); - schema.register( 'inlineRoot' ); - schema.extend( '$text', { allowIn: 'inlineRoot' } ); + schema.register( 'inlineRoot', { allowChildren: '$text' } ); const viewFragment = new ViewDocumentFragment( viewDocument, [ parseView( 'foo' ) ] ); diff --git a/packages/ckeditor5-engine/tests/dev-utils/model.js b/packages/ckeditor5-engine/tests/dev-utils/model.js index e0e7bfb1385..64c950b966d 100644 --- a/packages/ckeditor5-engine/tests/dev-utils/model.js +++ b/packages/ckeditor5-engine/tests/dev-utils/model.js @@ -209,8 +209,7 @@ describe( 'model test utils', () => { it( 'should work in a special root', () => { const model = new Model(); - model.schema.register( 'textOnly' ); - model.schema.extend( '$text', { allowIn: 'textOnly' } ); + model.schema.register( 'textOnly', { allowChildren: '$text' } ); model.document.createRoot( 'textOnly', 'textOnly' ); setData( model, 'a[b]c', { rootName: 'textOnly' } ); @@ -575,8 +574,7 @@ describe( 'model test utils', () => { it( 'converts data in the specified context', () => { const model = new Model(); - model.schema.register( 'foo' ); - model.schema.extend( '$text', { allowIn: 'foo' } ); + model.schema.register( 'foo', { allowChildren: '$text' } ); expect( () => { parse( 'text', model.schema, { context: [ 'foo' ] } ); diff --git a/packages/ckeditor5-engine/tests/model/selection.js b/packages/ckeditor5-engine/tests/model/selection.js index f1f5a4f3b53..e31e298f688 100644 --- a/packages/ckeditor5-engine/tests/model/selection.js +++ b/packages/ckeditor5-engine/tests/model/selection.js @@ -953,9 +953,9 @@ describe( 'Selection', () => { model.schema.extend( '$block', { allowIn: 'blockquote' } ); model.schema.register( 'image', { - allowIn: [ '$root', '$block' ] + allowIn: [ '$root', '$block' ], + allowChildren: '$text' } ); - model.schema.extend( '$text', { allowIn: 'image' } ); // Special block which can contain another blocks. model.schema.register( 'nestedBlock', { inheritAllFrom: '$block' } ); diff --git a/packages/ckeditor5-image/tests/image/insertimagecommand.js b/packages/ckeditor5-image/tests/image/insertimagecommand.js index 00aa71ac0e1..862c726bfab 100644 --- a/packages/ckeditor5-image/tests/image/insertimagecommand.js +++ b/packages/ckeditor5-image/tests/image/insertimagecommand.js @@ -56,8 +56,7 @@ describe( 'InsertImageCommand', () => { } ); it( 'should be true when the selection directly in a block', () => { - model.schema.register( 'block', { inheritAllFrom: '$block' } ); - model.schema.extend( '$text', { allowIn: 'block' } ); + model.schema.register( 'block', { inheritAllFrom: '$block', allowChildren: '$text' } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'block', view: 'block' } ); setModelData( model, 'foo[]' ); diff --git a/packages/ckeditor5-image/tests/image/utils.js b/packages/ckeditor5-image/tests/image/utils.js index 44872aef962..71d6fc60f11 100644 --- a/packages/ckeditor5-image/tests/image/utils.js +++ b/packages/ckeditor5-image/tests/image/utils.js @@ -256,9 +256,9 @@ describe( 'image widget utils', () => { it( 'should not insert image nor crash when image could not be inserted', () => { model.schema.register( 'other', { allowIn: '$root', + allowChildren: '$text', isLimit: true } ); - model.schema.extend( '$text', { allowIn: 'other' } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'other', view: 'p' } ); diff --git a/packages/ckeditor5-image/tests/imageupload/imageuploadediting.js b/packages/ckeditor5-image/tests/imageupload/imageuploadediting.js index 3ac7ecfe572..2d9da9a5865 100644 --- a/packages/ckeditor5-image/tests/imageupload/imageuploadediting.js +++ b/packages/ckeditor5-image/tests/imageupload/imageuploadediting.js @@ -299,9 +299,9 @@ describe( 'ImageUploadEditing', () => { it( 'should not insert image nor crash when pasted image could not be inserted', () => { model.schema.register( 'other', { allowIn: '$root', + allowChildren: '$text', isLimit: true } ); - model.schema.extend( '$text', { allowIn: 'other' } ); editor.conversion.elementToElement( { model: 'other', view: 'p' } ); diff --git a/packages/ckeditor5-image/tests/imageupload/uploadimagecommand.js b/packages/ckeditor5-image/tests/imageupload/uploadimagecommand.js index 6f24f1d6f07..cb124c6fc95 100644 --- a/packages/ckeditor5-image/tests/imageupload/uploadimagecommand.js +++ b/packages/ckeditor5-image/tests/imageupload/uploadimagecommand.js @@ -166,9 +166,9 @@ describe( 'UploadImageCommand', () => { model.schema.register( 'other', { allowIn: '$root', + allowChildren: '$text', isLimit: true } ); - model.schema.extend( '$text', { allowIn: 'other' } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'other', view: 'p' } ); diff --git a/packages/ckeditor5-link/tests/linkcommand.js b/packages/ckeditor5-link/tests/linkcommand.js index 2250d29433c..ca707e563f5 100644 --- a/packages/ckeditor5-link/tests/linkcommand.js +++ b/packages/ckeditor5-link/tests/linkcommand.js @@ -316,8 +316,7 @@ describe( 'LinkCommand', () => { it( 'should set `linkHref` attribute to allowed elements and omit disallowed', () => { model.schema.register( 'image', { isBlock: true, allowWhere: '$text' } ); - model.schema.register( 'caption', { allowIn: 'image' } ); - model.schema.extend( '$text', { allowIn: 'caption' } ); + model.schema.register( 'caption', { allowIn: 'image', allowChildren: '$text' } ); setData( model, '

f[ooxxxba]r

' ); @@ -334,8 +333,7 @@ describe( 'LinkCommand', () => { it( 'should set `linkHref` attribute to allowed elements and omit their children even if they accept the attribute', () => { model.schema.register( 'image', { isBlock: true, allowWhere: '$text', allowAttributes: [ 'linkHref' ] } ); - model.schema.register( 'caption', { allowIn: 'image' } ); - model.schema.extend( '$text', { allowIn: 'caption' } ); + model.schema.register( 'caption', { allowIn: 'image', allowChildren: '$text' } ); setData( model, '

f[ooxxxba]r

' ); diff --git a/packages/ckeditor5-media-embed/tests/insertmediacommand.js b/packages/ckeditor5-media-embed/tests/insertmediacommand.js index bcdc2f4f20c..101ae41a4c3 100644 --- a/packages/ckeditor5-media-embed/tests/insertmediacommand.js +++ b/packages/ckeditor5-media-embed/tests/insertmediacommand.js @@ -73,8 +73,7 @@ describe( 'MediaEmbedCommand', () => { } ); it( 'should be true when the selection directly in a block', () => { - model.schema.register( 'block', { inheritAllFrom: '$block' } ); - model.schema.extend( '$text', { allowIn: 'block' } ); + model.schema.register( 'block', { inheritAllFrom: '$block', allowChildren: '$text' } ); setData( model, 'foo[]' ); expect( command.isEnabled ).to.be.true; diff --git a/packages/ckeditor5-page-break/tests/pagebreakcommand.js b/packages/ckeditor5-page-break/tests/pagebreakcommand.js index 582e279e6b3..56dd16ee25e 100644 --- a/packages/ckeditor5-page-break/tests/pagebreakcommand.js +++ b/packages/ckeditor5-page-break/tests/pagebreakcommand.js @@ -60,8 +60,7 @@ describe( 'PageBreakCommand', () => { } ); it( 'should be true when the selection directly in a block', () => { - model.schema.register( 'block', { inheritAllFrom: '$block' } ); - model.schema.extend( '$text', { allowIn: 'block' } ); + model.schema.register( 'block', { inheritAllFrom: '$block', allowChildren: '$text' } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'block', view: 'block' } ); setModelData( model, 'foo[]' ); @@ -94,8 +93,7 @@ describe( 'PageBreakCommand', () => { } ); it( 'should be false when schema disallows page break', () => { - model.schema.register( 'block', { inheritAllFrom: '$block' } ); - model.schema.extend( 'paragraph', { allowIn: 'block' } ); + model.schema.register( 'block', { inheritAllFrom: '$block', allowChildren: 'paragraph' } ); // Block page break in block. model.schema.addChildCheck( ( context, childDefinition ) => { if ( childDefinition.name === 'pageBreak' && context.last.name === 'block' ) { diff --git a/packages/ckeditor5-paragraph/tests/paragraph.js b/packages/ckeditor5-paragraph/tests/paragraph.js index 08b2dbdedcc..adb40e5c829 100644 --- a/packages/ckeditor5-paragraph/tests/paragraph.js +++ b/packages/ckeditor5-paragraph/tests/paragraph.js @@ -76,8 +76,7 @@ describe( 'Paragraph feature', () => { } ); it( 'should autoparagraph any inline element', () => { - editor.model.schema.register( 'inline', { allowWhere: '$text' } ); - editor.model.schema.extend( '$text', { allowIn: 'inline' } ); + editor.model.schema.register( 'inline', { allowWhere: '$text', allowChildren: '$text' } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'inline', view: 'span' } ); editor.conversion.for( 'upcast' ).elementToElement( { model: 'inline', view: 'span' } ); @@ -89,8 +88,7 @@ describe( 'Paragraph feature', () => { } ); it( 'should autoparagraph any inline element with children', () => { - editor.model.schema.register( 'inline', { allowWhere: '$text' } ); - editor.model.schema.extend( '$text', { allowIn: 'inline' } ); + editor.model.schema.register( 'inline', { allowWhere: '$text', allowChildren: '$text' } ); editor.conversion.for( 'downcast' ).elementToElement( { model: 'inline', view: 'span' } ); editor.conversion.for( 'upcast' ).elementToElement( { model: 'inline', view: 'span' } ); diff --git a/packages/ckeditor5-table/src/tableediting.js b/packages/ckeditor5-table/src/tableediting.js index e339be6b584..9b06b3bade3 100644 --- a/packages/ckeditor5-table/src/tableediting.js +++ b/packages/ckeditor5-table/src/tableediting.js @@ -76,14 +76,12 @@ export default class TableEditing extends Plugin { schema.register( 'tableCell', { allowIn: 'tableRow', + allowChildren: '$block', allowAttributes: [ 'colspan', 'rowspan' ], isLimit: true, isSelectable: true } ); - // Allow all $block content inside a table cell. - schema.extend( '$block', { allowIn: 'tableCell' } ); - // Table conversion. conversion.for( 'upcast' ).add( upcastTable() ); diff --git a/packages/ckeditor5-table/tests/converters/upcasttable.js b/packages/ckeditor5-table/tests/converters/upcasttable.js index eeebdc58e0a..35a4e017f5f 100644 --- a/packages/ckeditor5-table/tests/converters/upcasttable.js +++ b/packages/ckeditor5-table/tests/converters/upcasttable.js @@ -570,8 +570,11 @@ describe( 'upcastTable()', () => { describe( 'inline contents', () => { it( 'should upcast inline element inside a table cell', () => { - model.schema.register( 'inline', { allowWhere: '$text', isInline: true } ); - model.schema.extend( '$text', { allowIn: 'inline' } ); + model.schema.register( 'inline', { + allowWhere: '$text', + allowChildren: '$text', + isInline: true + } ); editor.conversion.elementToElement( { model: 'inline', view: 'span' } ); editor.setData( @@ -590,8 +593,12 @@ describe( 'upcastTable()', () => { } ); it( 'should upcast inline object inside a table cell', () => { - model.schema.register( 'inline', { allowWhere: '$text', isInline: true, isObject: true } ); - model.schema.extend( '$text', { allowIn: 'inline' } ); + model.schema.register( 'inline', { + allowWhere: '$text', + allowChildren: '$text', + isInline: true, + isObject: true + } ); editor.conversion.elementToElement( { model: 'inline', view: 'span' } ); editor.setData( diff --git a/packages/ckeditor5-widget/tests/widgettoolbarrepository.js b/packages/ckeditor5-widget/tests/widgettoolbarrepository.js index cc62a0247d4..3984c48dd1f 100644 --- a/packages/ckeditor5-widget/tests/widgettoolbarrepository.js +++ b/packages/ckeditor5-widget/tests/widgettoolbarrepository.js @@ -732,12 +732,10 @@ class FakeWidget extends Plugin { schema.register( 'fake-widget', { isObject: true, isBlock: true, - allowWhere: '$block' + allowWhere: '$block', + allowChildren: [ '$text', 'paragraph' ] } ); - schema.extend( '$text', { allowIn: 'fake-widget' } ); - schema.extend( 'paragraph', { allowIn: 'fake-widget' } ); - const conversion = editor.conversion; conversion.for( 'dataDowncast' ).elementToElement( { From 2568ed857b5bfa62e18bd2f1981a8e4dc3f52876 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 14 Apr 2021 14:51:09 +0200 Subject: [PATCH 06/16] Added info about allowChildren to compiled schema item definition. --- packages/ckeditor5-engine/src/model/schema.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ckeditor5-engine/src/model/schema.js b/packages/ckeditor5-engine/src/model/schema.js index 0ddc531b0ad..723ff234232 100644 --- a/packages/ckeditor5-engine/src/model/schema.js +++ b/packages/ckeditor5-engine/src/model/schema.js @@ -1295,6 +1295,7 @@ mix( Schema, ObservableMixin ); * * The `name` property, * * The `is*` properties, * * The `allowIn` array, + * * The `allowChildren` array, * * The `allowAttributes` array. * * @typedef {Object} module:engine/model/schema~SchemaCompiledItemDefinition From 273eedefe6c88d7eaea01a9ebaee2a3e44d33a2a Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 14 Apr 2021 15:53:01 +0200 Subject: [PATCH 07/16] Updated schema guide. --- .../docs/framework/guides/deep-dive/schema.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md b/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md index 01c38f4ceef..4274d4cd5d8 100644 --- a/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md +++ b/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md @@ -17,34 +17,38 @@ Elements and attributes are checked by features separately by using the {@link m ## Defining allowed structures -When a feature introduces a model element, it should register it in the schema. Besides defining that such an element may exist in the model, the feature also needs to define where this element can be placed: +When a feature introduces a model element, it should register it in the schema. Besides defining that such an element may exist in the model, the feature also needs to define where this element can be placed. This information is provided by `{@link module:engine/model/schema~SchemaItemDefinition#allowIn allowIn}` and `{@link module:engine/model/schema~SchemaItemDefinition#allowChildren allowChildren}` properties of the `{@link module:engine/model/schema~SchemaItemDefinition SchemaItemDefinition}`: ```js schema.register( 'myElement', { - allowIn: '$root' + allowIn: '$root', + allowChildren: '$text' } ); ``` -This lets the schema know that `` can be a child of `<$root>`. The `$root` element is one of the generic nodes defined by the editing framework. By default, the editor names the main root element a `<$root>`, so the above definition allows `` in the main editor element. +This lets the schema know that `` can be a child of `<$root>` and that the `<$text>` element can be a child of `myElement`. The `$root` and `$text` elements are one of the generic nodes defined by the editing framework. By default, the editor names the main root element a `<$root>`, so the above definition allows `` in the main editor element. `<$text>` element on the other hand tells that the `` can include text nodes. In other words, this would be correct: ```xml <$root> - + <$text>foobar ``` While this would be incorrect: -```js +```xml <$root> + <$text>foobar ``` +Both `{@link module:engine/model/schema~SchemaItemDefinition#allowIn allowIn}` and `{@link module:engine/model/schema~SchemaItemDefinition#allowChildren allowChildren}` properties can be also inherited from other `SchemaItemDefinition` items. See `{@link module:engine/model/schema~SchemaItemDefinition SchemaItemDefinition}` API documentation for more details. + ## Defining additional semantics In addition to setting allowed structures, the schema can also define additional traits of model elements. By using the `is*` properties, a feature author may declare how a certain element should be treated by other features and by the engine. From f5f620314ef1fa6c5aee37aaa23d4804e67f6f9c Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 14 Apr 2021 16:04:55 +0200 Subject: [PATCH 08/16] Fixed incorrectly refactored unit test. --- packages/ckeditor5-ckfinder/tests/ckfindercommand.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ckeditor5-ckfinder/tests/ckfindercommand.js b/packages/ckeditor5-ckfinder/tests/ckfindercommand.js index 5bd26e776bc..d6f77dc6fd9 100644 --- a/packages/ckeditor5-ckfinder/tests/ckfindercommand.js +++ b/packages/ckeditor5-ckfinder/tests/ckfindercommand.js @@ -410,7 +410,7 @@ describe( 'CKFinderCommand', () => { it( 'should not insert image nor crash when image could not be inserted', () => { model.schema.register( 'other', { allowIn: '$root', - allowChildren: 'other', + allowChildren: '$text', isLimit: true } ); From a0972e2ebbac1b89f826422aa9bfe8e10f840b1e Mon Sep 17 00:00:00 2001 From: Kuba Niegowski Date: Thu, 15 Apr 2021 15:11:44 +0200 Subject: [PATCH 09/16] Adjusted changes after merge. --- packages/ckeditor5-engine/src/model/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ckeditor5-engine/src/model/model.js b/packages/ckeditor5-engine/src/model/model.js index 89634c7e59b..6c24b3921d8 100644 --- a/packages/ckeditor5-engine/src/model/model.js +++ b/packages/ckeditor5-engine/src/model/model.js @@ -115,9 +115,9 @@ export default class Model { this.schema.register( '$documentFragment', { allowContentOf: '$root', + allowChildren: '$text', isLimit: true } ); - this.schema.extend( '$text', { allowIn: '$documentFragment' } ); // An element needed by the `upcastElementToMarker` converter. // This element temporarily represents a marker boundary during the conversion process and is removed From 3a5ed04c237889c6dbcb8224ba8a69cd1d179785 Mon Sep 17 00:00:00 2001 From: Kuba Niegowski Date: Thu, 15 Apr 2021 16:50:15 +0200 Subject: [PATCH 10/16] Simplifications in the schema guide. --- .../docs/framework/guides/deep-dive/schema.md | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md b/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md index 4274d4cd5d8..ad86a4c329b 100644 --- a/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md +++ b/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md @@ -17,22 +17,21 @@ Elements and attributes are checked by features separately by using the {@link m ## Defining allowed structures -When a feature introduces a model element, it should register it in the schema. Besides defining that such an element may exist in the model, the feature also needs to define where this element can be placed. This information is provided by `{@link module:engine/model/schema~SchemaItemDefinition#allowIn allowIn}` and `{@link module:engine/model/schema~SchemaItemDefinition#allowChildren allowChildren}` properties of the `{@link module:engine/model/schema~SchemaItemDefinition SchemaItemDefinition}`: +When a feature introduces a model element, it should register it in the schema. Besides defining that such an element may exist in the model, the feature also needs to define where this element can be placed. This information is provided by {@link module:engine/model/schema~SchemaItemDefinition#allowIn} property of the {@link module:engine/model/schema~SchemaItemDefinition}: ```js schema.register( 'myElement', { - allowIn: '$root', - allowChildren: '$text' + allowIn: '$root' } ); ``` -This lets the schema know that `` can be a child of `<$root>` and that the `<$text>` element can be a child of `myElement`. The `$root` and `$text` elements are one of the generic nodes defined by the editing framework. By default, the editor names the main root element a `<$root>`, so the above definition allows `` in the main editor element. `<$text>` element on the other hand tells that the `` can include text nodes. +This lets the schema know that `` can be a child of `<$root>`. The `$root` element is one of the generic nodes defined by the editing framework. By default, the editor names the main root element a `<$root>`, so the above definition allows `` in the main editor element. In other words, this would be correct: ```xml <$root> - <$text>foobar + ``` @@ -41,13 +40,35 @@ While this would be incorrect: ```xml <$root> - <$text>foobar ``` -Both `{@link module:engine/model/schema~SchemaItemDefinition#allowIn allowIn}` and `{@link module:engine/model/schema~SchemaItemDefinition#allowChildren allowChildren}` properties can be also inherited from other `SchemaItemDefinition` items. See `{@link module:engine/model/schema~SchemaItemDefinition SchemaItemDefinition}` API documentation for more details. +To declare what nodes could be inside the registered element, the {@link module:engine/model/schema~SchemaItemDefinition#allowChildren} property could be used: + +```js +schema.register( 'myElement', { + allowIn: '$root', + allowChildren: '$text' +} ); +``` + +To allow the following structure: + +```xml +<$root> + + foobar + + +``` + +Both `{@link module:engine/model/schema~SchemaItemDefinition#allowIn}` and `{@link module:engine/model/schema~SchemaItemDefinition#allowChildren}` properties can be also inherited from other `SchemaItemDefinition` items. + + + You can read more about the format of the item definition in {@link module:engine/model/schema~SchemaItemDefinition}. + ## Defining additional semantics From 03316a7c17e05037e4f954f0e8092e4152090029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20Bogda=C5=84ski?= Date: Fri, 16 Apr 2021 07:50:12 +0200 Subject: [PATCH 11/16] Keep allowChildren reference when cleaning up. Co-authored-by: Kuba Niegowski <1232187+niegowski@users.noreply.github.com> --- packages/ckeditor5-engine/src/model/schema.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ckeditor5-engine/src/model/schema.js b/packages/ckeditor5-engine/src/model/schema.js index 13dfaea36aa..a112b2eabb6 100644 --- a/packages/ckeditor5-engine/src/model/schema.js +++ b/packages/ckeditor5-engine/src/model/schema.js @@ -1617,7 +1617,7 @@ function compileAllowChildren( compiledDefinitions, itemName ) { // allowIn already includes correct items, reset allowChildren // to avoid duplicates later when cleaning up compilation results. - item.allowChildren = []; + item.allowChildren.length = 0; } function compileAllowContentOf( compiledDefinitions, itemName ) { From dca70d696ea367f79246b63ef43e9059d5456683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20Bogda=C5=84ski?= Date: Fri, 16 Apr 2021 07:50:39 +0200 Subject: [PATCH 12/16] Comment update. Co-authored-by: Kuba Niegowski <1232187+niegowski@users.noreply.github.com> --- packages/ckeditor5-engine/src/model/schema.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ckeditor5-engine/src/model/schema.js b/packages/ckeditor5-engine/src/model/schema.js index a112b2eabb6..36cfd96768e 100644 --- a/packages/ckeditor5-engine/src/model/schema.js +++ b/packages/ckeditor5-engine/src/model/schema.js @@ -1615,7 +1615,7 @@ function compileAllowChildren( compiledDefinitions, itemName ) { allowedChildren.allowIn.push( itemName ); } - // allowIn already includes correct items, reset allowChildren + // The allowIn property already includes correct items, reset the allowChildren property // to avoid duplicates later when cleaning up compilation results. item.allowChildren.length = 0; } From 5c366518bc01b3a2b0baeb437b1e492c9381ca0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20Bogda=C5=84ski?= Date: Fri, 16 Apr 2021 07:50:56 +0200 Subject: [PATCH 13/16] Refactoring. Co-authored-by: Kuba Niegowski <1232187+niegowski@users.noreply.github.com> --- packages/ckeditor5-engine/src/model/schema.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/ckeditor5-engine/src/model/schema.js b/packages/ckeditor5-engine/src/model/schema.js index 36cfd96768e..21e7f215845 100644 --- a/packages/ckeditor5-engine/src/model/schema.js +++ b/packages/ckeditor5-engine/src/model/schema.js @@ -1697,9 +1697,10 @@ function cleanUpAllowIn( compiledDefinitions, itemName ) { function cleanUpAllowChildren( compiledDefinitions, itemName ) { const itemRule = compiledDefinitions[ itemName ]; - for ( const allowItemName of itemRule.allowIn ) { - const allowedItem = compiledDefinitions[ allowItemName ]; - allowedItem.allowChildren.push( itemName ); + for ( const allowedParentItemName of itemRule.allowIn ) { + const allowedParentItem = compiledDefinitions[ allowedParentItemName ]; + + allowedParentItem.allowChildren.push( itemName ); } } From 004198237c011043b77f352b3829533cad37ec63 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 16 Apr 2021 07:54:02 +0200 Subject: [PATCH 14/16] Renaming. --- packages/ckeditor5-engine/src/model/schema.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ckeditor5-engine/src/model/schema.js b/packages/ckeditor5-engine/src/model/schema.js index 21e7f215845..aba7b8dff84 100644 --- a/packages/ckeditor5-engine/src/model/schema.js +++ b/packages/ckeditor5-engine/src/model/schema.js @@ -902,7 +902,7 @@ export default class Schema { for ( const itemName of itemNames ) { cleanUpAllowIn( compiledDefinitions, itemName ); - cleanUpAllowChildren( compiledDefinitions, itemName ); + restoreAllowChildren( compiledDefinitions, itemName ); cleanUpAllowAttributes( compiledDefinitions, itemName ); } @@ -1616,7 +1616,7 @@ function compileAllowChildren( compiledDefinitions, itemName ) { } // The allowIn property already includes correct items, reset the allowChildren property - // to avoid duplicates later when cleaning up compilation results. + // to avoid duplicates later when restoring compilation results. item.allowChildren.length = 0; } @@ -1694,7 +1694,7 @@ function cleanUpAllowIn( compiledDefinitions, itemName ) { } // Restore allowChildren items based on allowIn. -function cleanUpAllowChildren( compiledDefinitions, itemName ) { +function restoreAllowChildren( compiledDefinitions, itemName ) { const itemRule = compiledDefinitions[ itemName ]; for ( const allowedParentItemName of itemRule.allowIn ) { From 75f1a308cfe9f66b16f778172db0416cedb9cd26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20Bogda=C5=84ski?= Date: Fri, 16 Apr 2021 07:56:06 +0200 Subject: [PATCH 15/16] Guide documentation update. Co-authored-by: Bartek Biedrzycki <68123541+godai78@users.noreply.github.com> --- .../docs/framework/guides/deep-dive/schema.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md b/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md index ad86a4c329b..e199c088e3a 100644 --- a/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md +++ b/packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md @@ -17,7 +17,7 @@ Elements and attributes are checked by features separately by using the {@link m ## Defining allowed structures -When a feature introduces a model element, it should register it in the schema. Besides defining that such an element may exist in the model, the feature also needs to define where this element can be placed. This information is provided by {@link module:engine/model/schema~SchemaItemDefinition#allowIn} property of the {@link module:engine/model/schema~SchemaItemDefinition}: +When a feature introduces a model element, it should register it in the schema. Besides defining that such an element may exist in the model, the feature also needs to define where this element can be placed. This information is provided by the {@link module:engine/model/schema~SchemaItemDefinition#allowIn} property of the {@link module:engine/model/schema~SchemaItemDefinition}: ```js schema.register( 'myElement', { @@ -45,7 +45,7 @@ While this would be incorrect: ``` -To declare what nodes could be inside the registered element, the {@link module:engine/model/schema~SchemaItemDefinition#allowChildren} property could be used: +To declare which nodes could be inside the registered element, the {@link module:engine/model/schema~SchemaItemDefinition#allowChildren} property could be used: ```js schema.register( 'myElement', { @@ -64,7 +64,7 @@ To allow the following structure: ``` -Both `{@link module:engine/model/schema~SchemaItemDefinition#allowIn}` and `{@link module:engine/model/schema~SchemaItemDefinition#allowChildren}` properties can be also inherited from other `SchemaItemDefinition` items. +Both the `{@link module:engine/model/schema~SchemaItemDefinition#allowIn}` and `{@link module:engine/model/schema~SchemaItemDefinition#allowChildren}` properties can be also inherited from other `SchemaItemDefinition` items. You can read more about the format of the item definition in {@link module:engine/model/schema~SchemaItemDefinition}. From d33378fb6c479eac16ad0dadb525cccae49917ca Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 16 Apr 2021 08:15:29 +0200 Subject: [PATCH 16/16] Renaming again for better name. --- packages/ckeditor5-engine/src/model/schema.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ckeditor5-engine/src/model/schema.js b/packages/ckeditor5-engine/src/model/schema.js index aba7b8dff84..93ce8d380d4 100644 --- a/packages/ckeditor5-engine/src/model/schema.js +++ b/packages/ckeditor5-engine/src/model/schema.js @@ -902,7 +902,7 @@ export default class Schema { for ( const itemName of itemNames ) { cleanUpAllowIn( compiledDefinitions, itemName ); - restoreAllowChildren( compiledDefinitions, itemName ); + setupAllowChildren( compiledDefinitions, itemName ); cleanUpAllowAttributes( compiledDefinitions, itemName ); } @@ -1616,7 +1616,7 @@ function compileAllowChildren( compiledDefinitions, itemName ) { } // The allowIn property already includes correct items, reset the allowChildren property - // to avoid duplicates later when restoring compilation results. + // to avoid duplicates later when setting up compilation results. item.allowChildren.length = 0; } @@ -1693,8 +1693,8 @@ function cleanUpAllowIn( compiledDefinitions, itemName ) { itemRule.allowIn = Array.from( new Set( existingItems ) ); } -// Restore allowChildren items based on allowIn. -function restoreAllowChildren( compiledDefinitions, itemName ) { +// Setup allowChildren items based on allowIn. +function setupAllowChildren( compiledDefinitions, itemName ) { const itemRule = compiledDefinitions[ itemName ]; for ( const allowedParentItemName of itemRule.allowIn ) {