Browse Source

Moar tests.

Piotrek Koszuliński 9 years ago
parent
commit
9668a798bd

+ 4 - 2
packages/ckeditor5-engine/src/treemodel/document.js

@@ -178,10 +178,12 @@ export default class Document {
 	 * Creates a new top-level root.
 	 *
 	 * @param {String|Symbol} rootName Unique root name.
-	 * @param {String} elementName Element name.
+	 * @param {String} [elementName='$root'] Element name. Defaults to `'$root'` which also have
+	 * some basic schema defined (`$block`s are allowed inside the `$root`). Make sure to define a proper
+	 * schema if you use a different name.
 	 * @returns {engine.treeModel.RootElement} Created root.
 	 */
-	createRoot( rootName, elementName ) {
+	createRoot( rootName, elementName = '$root' ) {
 		if ( this._roots.has( rootName ) ) {
 			/**
 			 * Root with specified name already exists.

+ 26 - 10
packages/ckeditor5-engine/src/treemodel/position.js

@@ -5,7 +5,7 @@
 
 'use strict';
 
-import RootElement from './rootelement.js';
+// import RootElement from './rootelement.js';
 import DocumentFragment from './documentfragment.js';
 import Element from './element.js';
 import last from '../../utils/lib/lodash/last.js';
@@ -22,11 +22,12 @@ export default class Position {
 	/**
 	 * Creates a position.
 	 *
-	 * @param {engine.treeModel.RootElement|engine.treeModel.DocumentFragment} root Root element for the position path.
+	 * @param {engine.treeModel.Element|engine.treeModel.DocumentFragment} root
+	 * Root of the position path. Element (most often a {@link engine.treeModel.RootElement}) or a document fragment.
 	 * @param {Array.<Number>} path Position path. See {@link engine.treeModel.Position#path} property for more information.
 	 */
 	constructor( root, path ) {
-		if ( !( root instanceof RootElement ) && !( root instanceof DocumentFragment ) ) {
+		if ( !( root instanceof Element ) && !( root instanceof DocumentFragment ) ) {
 			/**
 			 * Position root invalid.
 			 *
@@ -35,13 +36,6 @@ export default class Position {
 			throw new CKEditorError( 'position-root-invalid: Position root invalid.' );
 		}
 
-		/**
-		 * Root element for the position path.
-		 *
-		 * @member {engine.treeModel.RootElement|engine.treeModel.DocumentFragment} engine.treeModel.Position#root
-		 */
-		this.root = root;
-
 		if ( !( path instanceof Array ) || path.length === 0 ) {
 			/**
 			 * Position path must be an Array with at least one item.
@@ -52,6 +46,18 @@ export default class Position {
 			throw new CKEditorError( 'position-path-incorrect: Position path must be an Array with at least one item.', { path: path } );
 		}
 
+		// Normalize the root and path (if element was passed).
+		path = root.getPath().concat( path );
+		root = root.root;
+
+		/**
+		 * Root of the position path.
+		 *
+		 * @readonly
+		 * @member {engine.treeModel.Element|engine.treeModel.DocumentFragment} engine.treeModel.Position#root
+		 */
+		this.root = root;
+
 		/**
 		 * Position of the node it the tree. Must contain at least one item. For example:
 		 *
@@ -417,10 +423,20 @@ export default class Position {
 		}
 	}
 
+	/**
+	 * Whether position is at the beginning of its {@link engine.treeModel.Position#parent}.
+	 *
+	 * @returns {Boolean}
+	 */
 	isAtStart() {
 		return this.offset === 0;
 	}
 
+	/**
+	 * Whether position is at the end of its {@link engine.treeModel.Position#parent}.
+	 *
+	 * @returns {Boolean}
+	 */
 	isAtEnd() {
 		return this.offset == this.parent.getChildCount();
 	}

+ 3 - 1
packages/ckeditor5-engine/src/treemodel/schema.js

@@ -234,9 +234,11 @@ export class SchemaItem {
  *		editor.document.schema.allow( '$text', 'bold' );
  *
  * Note: items prefixed with `$` are special group of items. By default, `Schema` defines three special items:
+ *
  * * `$inline` represents all inline elements,
  * * `$text` is a sub-group of `$inline` and represents text nodes,
- * * `$block` represents block elements.
+ * * `$block` represents block elements,
+ * * `$root` represents default editing roots (those that allow only `$block`s inside them).
  *
  * When registering an item it's possible to tell that this item should inherit from some other existing item.
  * E.g. `p` can inherit from `$block`, so whenever given attribute is allowed on the `$block` it will automatically be

+ 8 - 1
packages/ckeditor5-engine/tests/treemodel/document/document.js

@@ -50,11 +50,18 @@ describe( 'Document', () => {
 
 	describe( 'createRoot', () => {
 		it( 'should create a new RootElement, add it to roots map and return it', () => {
-			let root = doc.createRoot( 'root', 'root' );
+			let root = doc.createRoot( 'root' );
 
 			expect( doc._roots.size ).to.equal( 2 );
 			expect( root ).to.be.instanceof( RootElement );
 			expect( root.getChildCount() ).to.equal( 0 );
+			expect( root ).to.have.property( 'name', '$root' );
+		} );
+
+		it( 'should create a new RootElement with the specified name', () => {
+			let root = doc.createRoot( 'root', 'foo' );
+
+			expect( root ).to.have.property( 'name', 'foo' );
 		} );
 
 		it( 'should throw an error when trying to create a second root with the same name', () => {

+ 45 - 5
packages/ckeditor5-engine/tests/treemodel/position.js

@@ -10,6 +10,7 @@
 import Document from '/ckeditor5/engine/treemodel/document.js';
 import DocumentFragment from '/ckeditor5/engine/treemodel/documentfragment.js';
 import Element from '/ckeditor5/engine/treemodel/element.js';
+import Text from '/ckeditor5/engine/treemodel/text.js';
 import Position from '/ckeditor5/engine/treemodel/position.js';
 import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
 import testUtils from '/tests/ckeditor5/_utils/utils.js';
@@ -64,9 +65,34 @@ describe( 'position', () => {
 		} );
 
 		it( 'should accept DocumentFragment as a root', () => {
-			expect( () => {
-				new Position( new DocumentFragment(), [ 0 ] );
-			} ).not.to.throw;
+			const frag = new DocumentFragment();
+			const pos = new Position( frag, [ 0 ] );
+
+			expect( pos ).to.have.property( 'root', frag );
+		} );
+
+		it( 'should accept detached Element as a root', () => {
+			const el = new Element( 'p' );
+			const pos = new Position( el, [ 0 ] );
+
+			expect( pos ).to.have.property( 'root', el );
+			expect( pos.path ).to.deep.equal( [ 0 ] );
+		} );
+
+		it( 'should normalize attached Element as a root', () => {
+			const pos = new Position( li1, [ 0, 2 ] );
+
+			expect( pos ).to.have.property( 'root', root );
+			expect( pos.isEqual( Position.createAt( li1, 0, 2 ) ) );
+		} );
+
+		it( 'should normalize Element from a detached branch as a root', () => {
+			const rootEl = new Element( 'p', null, [ new Element( 'a' ) ] );
+			const elA = rootEl.getChild( 0 );
+			const pos = new Position( elA, [ 0 ] );
+
+			expect( pos ).to.have.property( 'root', rootEl );
+			expect( pos.isEqual( Position.createAt( elA, 0 ) ) );
 		} );
 
 		it( 'should throw error if given path is incorrect', () => {
@@ -81,11 +107,11 @@ describe( 'position', () => {
 
 		it( 'should throw error if given root is invalid', () => {
 			expect( () => {
-				new Position();
+				new Position( new Text( 'a' ) );
 			} ).to.throw( CKEditorError, /position-root-invalid/ );
 
 			expect( () => {
-				new Position( new Element( 'p' ), [ 0 ] );
+				new Position();
 			} ).to.throw( CKEditorError, /position-root-invalid/ );
 		} );
 	} );
@@ -420,6 +446,20 @@ describe( 'position', () => {
 		} );
 	} );
 
+	describe( 'isAtStart', () => {
+		it( 'should return true if position is at the beginning of its parent', () => {
+			expect( new Position( root, [ 0 ] ).isAtStart() ).to.be.true;
+			expect( new Position( root, [ 1 ] ).isAtStart() ).to.be.false;
+		} );
+	} );
+
+	describe( 'isAtEnd', () => {
+		it( 'should return true if position is at the end of its parent', () => {
+			expect( new Position( root, [ root.getChildCount() ] ).isAtEnd() ).to.be.true;
+			expect( new Position( root, [ 0 ] ).isAtEnd() ).to.be.false;
+		} );
+	} );
+
 	describe( 'compareWith', () => {
 		it( 'should return SAME if positions are same', () => {
 			const position = new Position( root, [ 1, 2, 3 ] );

+ 9 - 3
packages/ckeditor5-engine/tests/treemodel/schema/schema.js

@@ -13,6 +13,9 @@ import Document from '/ckeditor5/engine/treemodel/document.js';
 import Element from '/ckeditor5/engine/treemodel/element.js';
 import Position from '/ckeditor5/engine/treemodel/position.js';
 import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
+import testUtils from '/tests/ckeditor5/_utils/utils.js';
+
+testUtils.createSinonSandbox();
 
 let schema;
 
@@ -22,14 +25,17 @@ beforeEach( () => {
 
 describe( 'constructor', () => {
 	it( 'should register base items: inline, block, root', () => {
-		sinon.spy( Schema.prototype, 'registerItem' );
+		testUtils.sinon.spy( Schema.prototype, 'registerItem' );
 
 		schema = new Schema();
 
-		expect( schema.registerItem.calledWithExactly( '$inline', null ) );
+		expect( schema.registerItem.calledWithExactly( '$root', null ) );
 		expect( schema.registerItem.calledWithExactly( '$block', null ) );
+		expect( schema.registerItem.calledWithExactly( '$inline', null ) );
+	} );
 
-		Schema.prototype.registerItem.restore();
+	it( 'should allow block in root', () => {
+		expect( schema.check( { name: '$block', inside: [ '$root' ] } ) ).to.be.true;
 	} );
 
 	it( 'should allow inline in block', () => {