Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Introduced SchemaContext and simplified check method callbacks.
Browse files Browse the repository at this point in the history
  • Loading branch information
Reinmar committed Dec 29, 2017
1 parent d942567 commit c198be3
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 108 deletions.
80 changes: 61 additions & 19 deletions src/model/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ export default class Schema {
this.decorate( 'checkAttribute' );

this.on( 'checkAttribute', ( evt, args ) => {
args[ 0 ] = normalizeContext( args[ 0 ] );
args[ 0 ] = new SchemaContext( args[ 0 ] );
}, { priority: 'highest' } );

this.on( 'checkChild', ( evt, args ) => {
args[ 0 ] = normalizeContext( args[ 0 ] );
args[ 0 ] = new SchemaContext( args[ 0 ] );
}, { priority: 'highest' } );
}

Expand Down Expand Up @@ -125,7 +125,7 @@ export default class Schema {
* @param {String}
*/
checkAttribute( context, attributeName ) {
const rule = this.getRule( context[ context.length - 1 ] );
const rule = this.getRule( context.last );

if ( !rule ) {
return false;
Expand Down Expand Up @@ -218,7 +218,7 @@ export default class Schema {
}

_checkContextMatch( rule, context, contextItemIndex = context.length - 1 ) {
const contextItem = context[ contextItemIndex ];
const contextItem = context.getItem( contextItemIndex );

if ( rule.allowIn.includes( contextItem.name ) ) {
if ( contextItemIndex == 0 ) {
Expand All @@ -236,6 +236,50 @@ export default class Schema {

mix( Schema, ObservableMixin );

/**
* @private
*/
export class SchemaContext {
constructor( ctx ) {
if ( Array.isArray( ctx ) ) {
this._items = ctx.map( mapContextItem );
}
// Item or position (PS. It's ok that Position#getAncestors() doesn't accept params).
else {
this._items = ctx.getAncestors( { includeSelf: true } ).map( mapContextItem );
}
}

get length() {
return this._items.length;
}

get last() {
return this._items[ this._items.length - 1 ];
}

/**
* Returns an iterator that iterates over all context items
*
* @returns {Iterator.<TODO>}
*/
[ Symbol.iterator ]() {
return this._items[ Symbol.iterator ]();
}

getItem( index ) {
return this._items[ index ];
}

* getNames() {
yield* this._items.map( item => item.name );
}

matchEnd( query ) {
return Array.from( this.getNames() ).join( ' ' ).endsWith( query );
}
}

function compileBaseItemRule( sourceItemRules, itemName ) {
const itemRule = {
name: itemName,
Expand Down Expand Up @@ -384,32 +428,30 @@ function getAllowedChildren( compiledRules, itemName ) {
return getValues( compiledRules ).filter( rule => rule.allowIn.includes( itemRule.name ) );
}

function normalizeContext( ctx ) {
if ( Array.isArray( ctx ) ) {
return ctx.map( mapContextItem );
}
// Item or position (PS. It's ok that Position#getAncestors() doesn't accept params).
else {
return ctx.getAncestors( { includeSelf: true } ).map( mapContextItem );
}
function getValues( obj ) {
return Object.keys( obj ).map( key => obj[ key ] );
}

function mapContextItem( ctxItem ) {
if ( typeof ctxItem == 'string' ) {
return {
name: ctxItem,
* getAttributes() {}

* getAttributeKeys() {},

getAttribute() {}
};
} else {
return {
name: ctxItem.is( 'text' ) ? '$text' : ctxItem.name,
* getAttributes() {
yield* ctxItem.getAttributes();

* getAttributeKeys() {
yield* ctxItem.getAttributeKeys();
},

getAttribute( key ) {
return ctxItem.getAttribute( key );
}
};
}
}

function getValues( obj ) {
return Object.keys( obj ).map( key => obj[ key ] );
}
8 changes: 3 additions & 5 deletions tests/conversion/buildviewconverter.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,11 +496,11 @@ describe( 'View converter builder', () => {

// Disallow $root>div.
schema.on( 'checkChild', ( evt, args ) => {
const context = args[ 0 ];
const ctx = args[ 0 ];
const child = args[ 1 ];
const childRule = schema.getRule( child );

if ( childRule.name == 'div' && context[ context.length - 1 ].name == '$root' ) {
if ( childRule.name == 'div' && ctx.matchEnd( '$root' ) ) {
evt.stop();
evt.return = false;
}
Expand Down Expand Up @@ -529,11 +529,9 @@ describe( 'View converter builder', () => {
// // Disallow bold in paragraph>$text.
// schema.on( 'checkAttribute', ( evt, args ) => {
// const context = args[ 0 ];
// const ctxItem = context[ context.length - 1 ];
// const ctxParent = context[ context.length - 2 ];
// const attributeName = args[ 1 ];

// if ( ctxItem.name == '$text' && ctxParent.name == 'paragraph' && attributeName == 'bold' ) {
// if ( ctx.matchEnd( 'paragraph $text' ) && attributeName == 'bold' ) {
// evt.stop();
// evt.return = false;
// }
Expand Down
4 changes: 2 additions & 2 deletions tests/conversion/view-to-model-converters.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ describe( 'view-to-model-converters', () => {

it( 'should not convert text if it is wrong with schema', () => {
schema.on( 'checkChild', ( evt, args ) => {
const context = args[ 0 ];
const ctx = args[ 0 ];
const child = args[ 1 ];
const childRule = schema.getRule( child );

if ( childRule.name == '$text' && context[ context.length - 1 ].name == '$root' ) {
if ( childRule.name == '$text' && ctx.matchEnd( '$root' ) ) {
evt.stop();
evt.return = false;
}
Expand Down
Loading

0 comments on commit c198be3

Please sign in to comment.