Преглед изворни кода

Added Schema#findAllowedParent method.

Oskar Wróbel пре 8 година
родитељ
комит
278203bbde

+ 33 - 0
packages/ckeditor5-engine/src/model/schema.js

@@ -674,6 +674,39 @@ export default class Schema {
 		return validRanges;
 	}
 
+	/**
+	 * Tries to find position ancestors that allows to insert given node.
+	 * It starts searching from the given position and goes node by node to the top of the model tree
+	 * as long as {@link module:engine/model/schema~Schema#isLimit limit element} or top-most ancestor won't be reached.
+	 *
+	 * @params {module:engine/model/node~Node} node Node for which allowed parent should be found.
+	 * @params {module:engine/model/position~Position} position Position from searching will start.
+	 * @params {Function<module:engine/model/element~Element>} [limitChecker] When function is defined and returns true
+	 * then stops searching and returns null as a search result. Function gets current parent as a parameter.
+	 * @returns {module:engine/model/element~Element|null} element Allowed parent or null if nothing was found.
+	 */
+	findAllowedParent( node, position, limitChecker ) {
+		let parent = position.parent;
+
+		while ( parent ) {
+			if ( this.checkChild( parent, node ) ) {
+				return parent;
+			}
+
+			if ( this.isLimit( parent ) ) {
+				return null;
+			}
+
+			if ( typeof limitChecker == 'function' && limitChecker( parent ) ) {
+				return null;
+			}
+
+			parent = parent.parent;
+		}
+
+		return null;
+	}
+
 	/**
 	 * Removes attributes disallowed by the schema.
 	 *

+ 67 - 0
packages/ckeditor5-engine/tests/model/schema.js

@@ -1137,6 +1137,73 @@ describe( 'Schema', () => {
 		} );
 	} );
 
+	describe( 'findAllowedParent', () => {
+		beforeEach( () => {
+			schema.register( '$root' );
+			schema.register( 'blockQuote', {
+				allowIn: '$root'
+			} );
+			schema.register( 'paragraph', {
+				allowIn: 'blockQuote'
+			} );
+			schema.register( '$text', {
+				allowIn: 'paragraph'
+			} );
+		} );
+
+		it( 'should return position ancestor that allows to insert given note to it', () => {
+			const node = new Element( 'paragraph' );
+
+			const allowedParent = schema.findAllowedParent( node, Position.createAt( r1bQp ) );
+
+			expect( allowedParent ).to.equal( r1bQ );
+		} );
+
+		it( 'should return position ancestor that allows to insert given note to it when position is already i such an element', () => {
+			const node = new Text( 'text' );
+
+			const parent = schema.findAllowedParent( node, Position.createAt( r1bQp ) );
+
+			expect( parent ).to.equal( r1bQp );
+		} );
+
+		it( 'should return null when limit element will be reached before allowed parent', () => {
+			schema.extend( 'blockQuote', {
+				isLimit: true
+			} );
+			schema.register( 'div', {
+				allowIn: '$root'
+			} );
+			const node = new Element( 'div' );
+
+			const parent = schema.findAllowedParent( node, Position.createAt( r1bQp ) );
+
+			expect( parent ).to.null;
+		} );
+
+		it( 'should return null when there is no allowed ancestor for given position', () => {
+			const node = new Element( 'section' );
+
+			const parent = schema.findAllowedParent( node, Position.createAt( r1bQp ) );
+
+			expect( parent ).to.null;
+		} );
+
+		it( 'should use custom limit checker nad return null if returns true', () => {
+			// $root is allowed ancestor for blockQuote.
+			const node = new Element( 'blockQuote' );
+
+			const parent = schema.findAllowedParent(
+				node,
+				Position.createAt( r1bQp ),
+				// However lest stop searching when blockQuote is reached.
+				element => element.name == 'blockQuote'
+			);
+
+			expect( parent ).to.null;
+		} );
+	} );
+
 	describe( 'removeDisallowedAttributes()', () => {
 		let model, doc, root;