浏览代码

Added UnwrapDelta.

Szymon Cofalik 10 年之前
父节点
当前提交
8151594106

+ 2 - 1
packages/ckeditor5-engine/src/treemodel/batch.js

@@ -18,7 +18,8 @@ CKEDITOR.define( [
 	'treemodel/delta/attributedelta',
 	'treemodel/delta/splitdelta',
 	'treemodel/delta/mergedelta',
-	'treemodel/delta/wrapdelta'
+	'treemodel/delta/wrapdelta',
+	'treemodel/delta/unwrapdelta'
 ], ( Batch ) => {
 	return Batch;
 } );

+ 65 - 0
packages/ckeditor5-engine/src/treemodel/delta/unwrapdelta.js

@@ -0,0 +1,65 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+CKEDITOR.define( [
+	'treemodel/delta/delta',
+	'treemodel/delta/register',
+	'treemodel/position',
+	'treemodel/element',
+	'treemodel/operation/removeoperation',
+	'treemodel/operation/moveoperation',
+	'ckeditorerror'
+], ( Delta, register, Position, Element, RemoveOperation, MoveOperation, CKEditorError ) => {
+	/**
+	 * To provide specific OT behavior and better collisions solving, {@link treeModel.Batch#merge} method
+	 * uses the `UnwrapDelta` class which inherits from the `Delta` class and may overwrite some methods.
+	 *
+	 * @class treeModel.delta.UnwrapDelta
+	 */
+	class UnwrapDelta extends Delta {}
+
+	/**
+	 * Unwraps specified element, that is moves all it's children before it and then removes it. Throws
+	 * error if you try to unwrap an element that does not have a parent.
+	 *
+	 * @chainable
+	 * @method unwrap
+	 * @memberOf treeModel.Batch
+	 * @param {treeModel.Element} position Element to unwrap.
+	 */
+	register( 'unwrap', function( element ) {
+		if ( element.parent === null ) {
+			/**
+			 * Trying to unwrap an element that has no parent.
+			 *
+			 * @error batch-unwrap-element-no-parent
+			 */
+			throw new CKEditorError(
+				'batch-unwrap-element-no-parent: Trying to unwrap an element that has no parent.' );
+		}
+
+		const delta = new UnwrapDelta();
+
+		let sourcePosition = Position.createFromParentAndOffset( element, 0 );
+
+		const move = new MoveOperation( sourcePosition, element.getChildCount(), Position.createBefore( element ), this.doc.version );
+		this.doc.applyOperation( move );
+		delta.addOperation( move );
+
+		// Computing new position because we moved some nodes before `element`.
+		// If we would cache `Position.createBefore( element )` we remove wrong node.
+		const remove = new RemoveOperation( Position.createBefore( element ), 1, this.doc.version );
+		this.doc.applyOperation( remove );
+		delta.addOperation( remove );
+
+		this.addDelta( delta );
+
+		return this;
+	} );
+
+	return UnwrapDelta;
+} );

+ 67 - 0
packages/ckeditor5-engine/tests/treemodel/delta/unwrapdelta.js

@@ -0,0 +1,67 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* bender-tags: treemodel, delta */
+
+/* bender-include: ../../_tools/tools.js */
+
+'use strict';
+
+const modules = bender.amd.require(
+	'treemodel/document',
+	'treemodel/position',
+	'treemodel/range',
+	'treemodel/element',
+	'ckeditorerror'
+);
+
+describe( 'Batch', () => {
+	let Document, Position, Element, CKEditorError;
+
+	let doc, root, p;
+
+	before( () => {
+		Document = modules[ 'treemodel/document' ];
+		Position = modules[ 'treemodel/position' ];
+		Element = modules[ 'treemodel/element' ];
+		CKEditorError = modules.ckeditorerror;
+	} );
+
+	beforeEach( () => {
+		doc = new Document();
+		root = doc.createRoot( 'root' );
+
+		p = new Element( 'p', [], 'xyz' );
+		root.insertChildren( 0, [ 'a', p, 'b' ] );
+	} );
+
+	describe( 'unwrap', () => {
+		it( 'should unwrap given element', () => {
+			doc.batch().unwrap( p );
+
+			expect( root.getChildCount() ).to.equal( 5 );
+			expect( root.getChild( 0 ).character ).to.equal( 'a' );
+			expect( root.getChild( 1 ).character ).to.equal( 'x' );
+			expect( root.getChild( 2 ).character ).to.equal( 'y' );
+			expect( root.getChild( 3 ).character ).to.equal( 'z' );
+			expect( root.getChild( 4 ).character ).to.equal( 'b' );
+		} );
+
+		it( 'should throw if element to unwrap has no parent', () => {
+			let element = new Element( 'p' );
+
+			expect( () => {
+				doc.batch().unwrap( element );
+			} ).to.throw( CKEditorError, /^batch-unwrap-element-no-parent/ );
+		} );
+
+		it( 'should be chainable', () => {
+			const batch = doc.batch();
+
+			const chain = batch.unwrap( p );
+			expect( chain ).to.equal( batch );
+		} );
+	} );
+} );