Przeglądaj źródła

Initial changes required by the enterBlock implementation.

Piotrek Koszuliński 9 lat temu
rodzic
commit
6fea23684c

+ 6 - 4
packages/ckeditor5-engine/src/treemodel/composer/composer.js

@@ -27,7 +27,7 @@ export default class Composer {
 	 * Creates an instance of the composer.
 	 * Creates an instance of the composer.
 	 */
 	 */
 	constructor() {
 	constructor() {
-		this.on( 'deleteContents', ( evt, data ) => deleteContents( data.batch, data.selection ) );
+		this.on( 'deleteContents', ( evt, data ) => deleteContents( data.batch, data.selection, data.options ) );
 		this.on( 'modifySelection', ( evt, data ) => modifySelection( data.selection, data.options ) );
 		this.on( 'modifySelection', ( evt, data ) => modifySelection( data.selection, data.options ) );
 	}
 	}
 
 
@@ -40,14 +40,15 @@ export default class Composer {
 	 * then that behavior should be implemented in the view's listener. At the same time, the table feature
 	 * then that behavior should be implemented in the view's listener. At the same time, the table feature
 	 * will need to modify this method's behavior too, e.g. to "delete contents and then collapse
 	 * will need to modify this method's behavior too, e.g. to "delete contents and then collapse
 	 * the selection inside the last selected cell" or "delete the row and collapse selection somewhere near".
 	 * the selection inside the last selected cell" or "delete the row and collapse selection somewhere near".
-	 * That needs to be done in order to ensure that other features which use `deleteContents()` work well with tables.
+	 * That needs to be done in order to ensure that other features which use `deleteContents()` will work well with tables.
 	 *
 	 *
 	 * @fires engine.treeModel.composer.Composer#deleteContents
 	 * @fires engine.treeModel.composer.Composer#deleteContents
 	 * @param {engine.treeModel.Batch} batch Batch to which deltas will be added.
 	 * @param {engine.treeModel.Batch} batch Batch to which deltas will be added.
 	 * @param {engine.treeModel.Selection} selection Selection of which the content should be deleted.
 	 * @param {engine.treeModel.Selection} selection Selection of which the content should be deleted.
+	 * @param {Object} options See {@link engine.treeModel.composer.deleteContents}'s options.
 	 */
 	 */
-	deleteContents( batch, selection ) {
-		this.fire( 'deleteContents', { batch, selection } );
+	deleteContents( batch, selection, options ) {
+		this.fire( 'deleteContents', { batch, selection, options } );
 	}
 	}
 
 
 	/**
 	/**
@@ -73,6 +74,7 @@ utils.mix( Composer, EmitterMixin );
  * @param {Object} data
  * @param {Object} data
  * @param {engine.treeModel.Batch} data.batch
  * @param {engine.treeModel.Batch} data.batch
  * @param {engine.treeModel.Selection} data.selection
  * @param {engine.treeModel.Selection} data.selection
+ * @param {Object} data.options See {@link engine.treeModel.composer.deleteContents}'s options.
  */
  */
 
 
 /**
 /**

+ 17 - 11
packages/ckeditor5-engine/src/treemodel/composer/deletecontents.js

@@ -15,8 +15,12 @@ import utils from '../../../utils/utils.js';
  * @method engine.treeModel.composer.deleteContents
  * @method engine.treeModel.composer.deleteContents
  * @param {engine.treeModel.Batch} batch Batch to which the deltas will be added.
  * @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.
  * @param {engine.treeModel.Selection} selection Selection of which the content should be deleted.
+ * @param {Object} [options]
+ * @param {Boolean} [options.merge=false] Merge elements after removing the contents of the selection.
+ * For example, `<h>x[x</h><p>y]y</p>` will become: `<h>x^y</h>` with the option enabled
+ * and: `<h>x^</h><p>y</p>` without it.
  */
  */
-export default function deleteContents( batch, selection ) {
+export default function deleteContents( batch, selection, options = {} ) {
 	if ( selection.isCollapsed ) {
 	if ( selection.isCollapsed ) {
 		return;
 		return;
 	}
 	}
@@ -35,16 +39,18 @@ export default function deleteContents( batch, selection ) {
 	// However, the algorithm supports also merging deeper structures (up to the depth of the shallower branch),
 	// However, the algorithm supports also merging deeper structures (up to the depth of the shallower branch),
 	// as it's hard to imagine what should actually be the default behavior. Usually, specific features will
 	// as it's hard to imagine what should actually be the default behavior. Usually, specific features will
 	// want to override that behavior anyway.
 	// want to override that behavior anyway.
-	const endPath = endPos.path;
-	const mergeEnd = Math.min( startPos.path.length - 1, endPath.length - 1 );
-	let mergeDepth = utils.compareArrays( startPos.path, endPath );
-
-	if ( typeof mergeDepth == 'number' ) {
-		for ( ; mergeDepth < mergeEnd; mergeDepth++ ) {
-			const mergePath = startPos.path.slice( 0, mergeDepth );
-			mergePath.push( startPos.path[ mergeDepth ] + 1 );
-
-			batch.merge( new Position( endPos.root, mergePath ) );
+	if ( options.merge ) {
+		const endPath = endPos.path;
+		const mergeEnd = Math.min( startPos.path.length - 1, endPath.length - 1 );
+		let mergeDepth = utils.compareArrays( startPos.path, endPath );
+
+		if ( typeof mergeDepth == 'number' ) {
+			for ( ; mergeDepth < mergeEnd; mergeDepth++ ) {
+				const mergePath = startPos.path.slice( 0, mergeDepth );
+				mergePath.push( startPos.path[ mergeDepth ] + 1 );
+
+				batch.merge( new Position( endPos.root, mergePath ) );
+			}
 		}
 		}
 	}
 	}
 
 

+ 0 - 5
packages/ckeditor5-engine/src/treemodel/delta/attributedelta.js

@@ -65,11 +65,6 @@ export default class AttributeDelta extends Delta {
 		return null;
 		return null;
 	}
 	}
 
 
-	/**
-	 * @see engine.treeModel.delta.Delta#_reverseDeltaClass
-	 * @private
-	 * @type {Object}
-	 */
 	get _reverseDeltaClass() {
 	get _reverseDeltaClass() {
 		return AttributeDelta;
 		return AttributeDelta;
 	}
 	}

+ 11 - 10
packages/ckeditor5-engine/src/treemodel/delta/basic-deltas.js

@@ -10,13 +10,14 @@
 // which would already have all default deltas registered.
 // which would already have all default deltas registered.
 
 
 // Import default suite of deltas so a feature have to include only Batch class file.
 // Import default suite of deltas so a feature have to include only Batch class file.
-import d1 from './insertdelta.js';
-import d2 from './weakinsertdelta.js';
-import d3 from './movedelta.js';
-import d4 from './removedelta.js';
-import d5 from './attributedelta.js';
-import d6 from './splitdelta.js';
-import d7 from './mergedelta.js';
-import d8 from './wrapdelta.js';
-import d9 from './unwrapdelta.js';
-/*jshint unused: false*/
+import d01 from './attributedelta.js';
+import d02 from './insertdelta.js';
+import d03 from './mergedelta.js';
+import d04 from './movedelta.js';
+import d05 from './removedelta.js';
+import d06 from './renamedelta.js';
+import d07 from './splitdelta.js';
+import d08 from './unwrapdelta.js';
+import d09 from './weakinsertdelta.js';
+import d10 from './wrapdelta.js';
+/*jshint unused: false*/

+ 1 - 1
packages/ckeditor5-engine/src/treemodel/delta/delta.js

@@ -57,7 +57,7 @@ export default class Delta {
 	 * A class that will be used when creating reversed delta.
 	 * A class that will be used when creating reversed delta.
 	 *
 	 *
 	 * @private
 	 * @private
-	 * @type {Object}
+	 * @type {Function}
 	 */
 	 */
 	get _reverseDeltaClass() {
 	get _reverseDeltaClass() {
 		return Delta;
 		return Delta;

+ 0 - 5
packages/ckeditor5-engine/src/treemodel/delta/insertdelta.js

@@ -46,11 +46,6 @@ export default class InsertDelta extends Delta {
 		return this.operations[ 0 ] || null;
 		return this.operations[ 0 ] || null;
 	}
 	}
 
 
-	/**
-	 * @see engine.treeModel.delta.Delta#_reverseDeltaClass
-	 * @private
-	 * @type {Object}
-	 */
 	get _reverseDeltaClass() {
 	get _reverseDeltaClass() {
 		return RemoveDelta;
 		return RemoveDelta;
 	}
 	}

+ 0 - 5
packages/ckeditor5-engine/src/treemodel/delta/mergedelta.js

@@ -44,11 +44,6 @@ export default class MergeDelta extends Delta {
 		return this.operations[ 1 ] || null;
 		return this.operations[ 1 ] || null;
 	}
 	}
 
 
-	/**
-	 * @see engine.treeModel.delta.Delta#_reverseDeltaClass
-	 * @protected
-	 * @type {Object}
-	 */
 	get _reverseDeltaClass() {
 	get _reverseDeltaClass() {
 		return SplitDelta;
 		return SplitDelta;
 	}
 	}

+ 0 - 5
packages/ckeditor5-engine/src/treemodel/delta/movedelta.js

@@ -61,11 +61,6 @@ export default class MoveDelta extends Delta {
 		return this.operations[ 0 ] || null;
 		return this.operations[ 0 ] || null;
 	}
 	}
 
 
-	/**
-	 * @see engine.treeModel.delta.Delta#_reverseDeltaClass
-	 * @private
-	 * @type {Object}
-	 */
 	get _reverseDeltaClass() {
 	get _reverseDeltaClass() {
 		return MoveDelta;
 		return MoveDelta;
 	}
 	}

+ 59 - 0
packages/ckeditor5-engine/src/treemodel/delta/renamedelta.js

@@ -0,0 +1,59 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Delta from './delta.js';
+import { register } from '../batch.js';
+import InsertOperation from '../operation/insertoperation.js';
+import RemoveOperation from '../operation/removeoperation.js';
+import MoveOperation from '../operation/moveoperation.js';
+import Element from '../element.js';
+import Position from '../position.js';
+
+/**
+ * To provide specific OT behavior and better collisions solving, the {@link engine.treeModel.Batch#rename Batch#rename} method
+ * uses the `RenameDelta` class which inherits from the `Delta` class and may overwrite some methods.
+ *
+ * @memberOf engine.treeModel.delta
+ */
+export default class RenameDelta extends Delta {
+	get _reverseDeltaClass() {
+		return RenameDelta;
+	}
+}
+
+function apply( batch, delta, operation ) {
+	delta.addOperation( operation );
+	batch.doc.applyOperation( operation );
+}
+
+/**
+ * Renames the given element.
+ *
+ * @chainable
+ * @method engine.treeModel.Batch#rename
+ * @param {String} newName New element name.
+ * @param {engine.treeModel.Element} element The element to rename.
+ */
+register( 'rename', function( newName, element ) {
+	const delta = new RenameDelta();
+	const newElement = new Element( newName );
+
+	apply(
+		this, delta,
+		new InsertOperation( Position.createAfter( element ), newElement, this.doc.version )
+	);
+
+	apply(
+		this, delta,
+		new MoveOperation( Position.createAt( element ), element.getChildCount(), Position.createAt( newElement ), this.doc.version )
+	);
+
+	apply(
+		this, delta,
+		new RemoveOperation( Position.createBefore( element ), 1, this.doc.version )
+	);
+} );

+ 0 - 5
packages/ckeditor5-engine/src/treemodel/delta/splitdelta.js

@@ -57,11 +57,6 @@ export default class SplitDelta extends Delta {
 		return this.operations[ 1 ] || null;
 		return this.operations[ 1 ] || null;
 	}
 	}
 
 
-	/**
-	 * @see engine.treeModel.delta.Delta#_reverseDeltaClass
-	 * @private
-	 * @type {Object}
-	 */
 	get _reverseDeltaClass() {
 	get _reverseDeltaClass() {
 		return MergeDelta;
 		return MergeDelta;
 	}
 	}

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

@@ -40,11 +40,6 @@ export default class UnwrapDelta extends Delta {
 		return this.operations[ 0 ] || null;
 		return this.operations[ 0 ] || null;
 	}
 	}
 
 
-	/**
-	 * @see engine.treeModel.delta.Delta#_reverseDeltaClass
-	 * @private
-	 * @type {Object}
-	 */
 	get _reverseDeltaClass() {
 	get _reverseDeltaClass() {
 		return WrapDelta;
 		return WrapDelta;
 	}
 	}

+ 0 - 5
packages/ckeditor5-engine/src/treemodel/delta/wrapdelta.js

@@ -65,11 +65,6 @@ export default class WrapDelta extends Delta {
 		return this.operations[ 1 ] || null;
 		return this.operations[ 1 ] || null;
 	}
 	}
 
 
-	/**
-	 * @see engine.treeModel.delta.Delta#_reverseDeltaClass
-	 * @private
-	 * @type {Object}
-	 */
 	get _reverseDeltaClass() {
 	get _reverseDeltaClass() {
 		return UnwrapDelta;
 		return UnwrapDelta;
 	}
 	}

+ 17 - 0
packages/ckeditor5-engine/src/treemodel/element.js

@@ -8,6 +8,7 @@
 import Node from './node.js';
 import Node from './node.js';
 import NodeList from './nodelist.js';
 import NodeList from './nodelist.js';
 import DocumentFragment from './documentfragment.js';
 import DocumentFragment from './documentfragment.js';
+import Range from './range.js';
 import utils from '../../utils/utils.js';
 import utils from '../../utils/utils.js';
 
 
 /**
 /**
@@ -67,6 +68,10 @@ export default class Element extends Node {
 		return this._children.length;
 		return this._children.length;
 	}
 	}
 
 
+	isEmpty() {
+		return this.getChildCount() === 0;
+	}
+
 	/**
 	/**
 	 * Gets index of the given child node.
 	 * Gets index of the given child node.
 	 *
 	 *
@@ -169,4 +174,16 @@ export default class Element extends Node {
 	clearAttributes() {
 	clearAttributes() {
 		this._attrs.clear();
 		this._attrs.clear();
 	}
 	}
+
+	getText() {
+		let text = '';
+
+		for ( let value of Range.createFromElement( this ) ) {
+			if ( value.type == 'TEXT' ) {
+				text += value.item.text;
+			}
+		}
+
+		return text;
+	}
 }
 }

+ 8 - 0
packages/ckeditor5-engine/src/treemodel/position.js

@@ -417,6 +417,14 @@ export default class Position {
 		}
 		}
 	}
 	}
 
 
+	isAtStart() {
+		return this.offset === 0;
+	}
+
+	isAtEnd() {
+		return this.offset == this.parent.getChildCount();
+	}
+
 	/**
 	/**
 	 * Creates position at the given location. The location can be specified as:
 	 * Creates position at the given location. The location can be specified as:
 	 *
 	 *

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

@@ -266,11 +266,12 @@ export default class Schema {
 		this._extensionChains = new Map();
 		this._extensionChains = new Map();
 
 
 		// Register some default abstract entities.
 		// Register some default abstract entities.
-		this.registerItem( '$inline' );
+		this.registerItem( '$root' );
 		this.registerItem( '$block' );
 		this.registerItem( '$block' );
+		this.registerItem( '$inline' );
 		this.registerItem( '$text', '$inline' );
 		this.registerItem( '$text', '$inline' );
 
 
-		// Allow inline elements inside block elements.
+		this.allow( { name: '$block', inside: '$root' } );
 		this.allow( { name: '$inline', inside: '$block' } );
 		this.allow( { name: '$inline', inside: '$block' } );
 	}
 	}