浏览代码

Implemented the Composer.

Piotrek Koszuliński 9 年之前
父节点
当前提交
93d8b08774

+ 57 - 0
packages/ckeditor5-engine/src/treemodel/composer/composer.js

@@ -0,0 +1,57 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import utils from '../../../utils/utils.js';
+import EmitterMixin from '../../../utils/emittermixin.js';
+import deleteContents from './deletecontents.js';
+import modifySelection from './modifyselection.js';
+
+/**
+ * Set of frequently used tools to work with a document.
+ * The instance of composer is available in {@link engine.treeModel.Document#composer}.
+ *
+ * By default this class implements only a very basic version of those algorithms. However, all its methods can be extended
+ * by features by listening to related events. The default action of those events are implemented
+ * by functions available in the {@link engine.treeModel.composer} namespace, so they can be reused
+ * in the algorithms implemented by features.
+ *
+ * @member engine.treeModel.composer
+ * @mixes utils.EmitterMixin
+ */
+export default class Composer {
+	/**
+	 * Creates an instance of the composer.
+	 */
+	constructor() {
+		this.on( 'deleteContents', ( evt, data ) => deleteContents( data.batch, data.selection ) );
+		this.on( 'modifySelection', ( evt, data ) => modifySelection( data.selection, data.options ) );
+	}
+
+	/**
+	 * See {@link engine.treeModel.composer.deleteContents}.
+	 *
+	 * @fires engine.treeModel.composer.Composer#deleteContents
+	 * @param {engine.treeModel.Batch} batch Batch to which the deltas will be added.
+	 * @param {engine.treeModel.Selection} selection Selection of which the content should be deleted.
+	 */
+	deleteContents( batch, selection ) {
+		this.fire( 'deleteContents', { batch, selection } );
+	}
+
+	/**
+	 * See {@link engine.treeModel.composer.modifySelection}.
+	 *
+	 * @fires engine.treeModel.composer.Composer#modifySelection
+	 * @param {engine.treeModel.Selection} The selection to modify.
+	 * @param {Object} options See {@link engine.treeModel.composer.modifySelection}'s options.
+	 */
+	modifySelection( selection, options ) {
+		this.fire( 'modifySelection', { selection, options } );
+	}
+}
+
+utils.mix( Composer, EmitterMixin );

+ 80 - 0
packages/ckeditor5-engine/tests/composer/composer.js

@@ -0,0 +1,80 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Document from '/ckeditor5/engine/treemodel/document.js';
+import Composer from '/ckeditor5/engine/treemodel/composer/composer.js';
+import { setData, getData } from '/tests/engine/_utils/model.js';
+
+describe( 'Composer', () => {
+	let document, composer;
+
+	beforeEach( () => {
+		document = new Document();
+		document.createRoot( 'main', '$root' );
+
+		composer = new Composer();
+	} );
+
+	describe( 'constructor', () => {
+		it( 'attaches deleteContents default listener', () => {
+			setData( document, 'main', '<p><selection>foo</selection>bar</p>' );
+
+			const batch = document.batch();
+
+			composer.fire( 'deleteContents', { batch, selection: document.selection } );
+
+			expect( getData( document, 'main' ) ).to.equal( '<p>bar</p>' );
+			expect( batch.deltas ).to.not.be.empty;
+		} );
+
+		it( 'attaches modifySelection default listener', () => {
+			setData( document, 'main', '<p>foo<selection />bar</p>' );
+
+			composer.fire( 'modifySelection', {
+				selection: document.selection,
+				options: {
+					direction: 'BACKWARD'
+				}
+			} );
+
+			expect( getData( document, 'main', { selection: true } ) )
+				.to.equal( '<p>fo<selection backward>o</selection>bar</p>' );
+		} );
+	} );
+
+	describe( 'deleteContents', () => {
+		it( 'fires deleteContents event', () => {
+			const spy = sinon.spy();
+			const batch = document.batch();
+
+			composer.on( 'deleteContents', spy );
+
+			composer.deleteContents( batch, document.selection );
+
+			const data = spy.args[ 0 ][ 1 ];
+
+			expect( data.batch ).to.equal( batch );
+			expect( data.selection ).to.equal( document.selection );
+		} );
+	} );
+
+	describe( 'modifySelection', () => {
+		it( 'fires deleteContents event', () => {
+			const spy = sinon.spy();
+			const opts = { direction: 'backward' };
+
+			composer.on( 'modifySelection', spy );
+
+			composer.modifySelection( document.selection, opts );
+
+			const data = spy.args[ 0 ][ 1 ];
+
+			expect( data.selection ).to.equal( document.selection );
+			expect( data.options ).to.equal( opts );
+		} );
+	} );
+} );