Explorar o código

Changed: merge CompressedHistory and History into one class History.

Szymon Cofalik %!s(int64=9) %!d(string=hai) anos
pai
achega
80aadc113b

+ 0 - 150
packages/ckeditor5-engine/src/model/compressedhistory.js

@@ -1,150 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import History from './history.js';
-
-/**
- * `CompressedHistory` keeps deltas applied to the {@link engine.model.Document document} in their transformed state. Deltas
- * stored in `CompressedHistory` might get updated, split into more deltas or removed as other deltas are applied to the document.
- * Modifying the original deltas history results in a compressed version of history and makes some scripts faster and easier to implement.
- *
- * **Note:** deltas kept in `CompressedHistory` should be used only to transform deltas. Do not use `CompressedHistory` to get original
- * delta (especially basing on its {@link engine.model.delta.Delta#baseVersion baseVersion}). Do not trust base versions of deltas
- * returned by `CompressedHistory`. After transforming your delta by deltas from `CompressedHistory`, fix its base version accordingly.
- *
- * @see engine.model.History
- * @memberOf engine.model
- */
-export default class CompressedHistory extends History {
-	constructor() {
-		super();
-
-		/**
-		 * Stores base versions of deltas which has been marked as inactive.
-		 *
-		 * @private
-		 * @member {Array.<Number>} engine.model.CompressedHistory#_inactiveBaseVersions
-		 */
-		this._inactiveBaseVersions = [];
-	}
-
-	/**
-	 * Returns one or more deltas from compressed history that bases on given `baseVersion`. Most often it will be just
-	 * one delta, but if that delta got updated by multiple deltas, all of those updated deltas will be returned.
-	 *
-	 * @see engine.model.CompressedHistory#updateDelta
-	 * @param {Number} baseVersion Base version of the delta to retrieve.
-	 * @returns {Array.<engine.model.delta.Delta>|null} Delta with given base version or null if no such delta is in history.
-	 */
-	getDelta( baseVersion ) {
-		let index = this._historyPoints.get( baseVersion );
-
-		if ( index === undefined ) {
-			return null;
-		}
-
-		const deltas = [];
-
-		for ( index; index < this._deltas.length; index++ ) {
-			const delta = this._deltas[ index ];
-
-			if ( delta.baseVersion != baseVersion ) {
-				break;
-			}
-
-			deltas.push( delta );
-		}
-
-		return deltas.length === 0 ? null : deltas;
-	}
-
-	/**
-	 * Removes delta from the history. This happens i.e., when a delta is undone by another delta. Both undone delta and
-	 * undoing delta should be removed so they won't have an impact on transforming other deltas.
-	 *
-	 * **Note:** using this method does not change the state of {@link engine.model.Document model}. It just affects
-	 * the state of `CompressedHistory`.
-	 *
-	 * **Note:** when some deltas are removed, deltas between them should probably get updated. See
-	 * {@link engine.model.CompressedHistory#updateDelta}.
-	 *
-	 * **Note:** if delta with `baseVersion` got {@link engine.model.CompressedHistory#updateDelta updated} by multiple
-	 * deltas, all updated deltas will be removed.
-	 *
-	 * @param {Number} baseVersion Base version of a delta to be removed.
-	 */
-	removeDelta( baseVersion ) {
-		this.updateDelta( baseVersion, [] );
-		this._inactiveBaseVersions.push( baseVersion );
-	}
-
-	/**
-	 * Substitutes delta from compressed history by one or more given deltas.
-	 *
-	 * **Note:** if delta with `baseVersion` was already updated by multiple deltas, all updated deltas will be removed
-	 * and new deltas will be inserted at their position.
-	 *
-	 * **Note:** delta marked as reversed won't get updated.
-	 *
-	 * @param {Number} baseVersion Base version of a delta to update.
-	 * @param {Iterable.<engine.model.delta.Delta>} updatedDeltas Deltas to be inserted in place of updated delta.
-	 */
-	updateDelta( baseVersion, updatedDeltas ) {
-		if ( this._inactiveBaseVersions.indexOf( baseVersion ) != -1 ) {
-			return;
-		}
-
-		const deltas = this.getDelta( baseVersion );
-
-		// If there are no deltas, stop executing function as there is nothing to mark.
-		if ( deltas === null ) {
-			return;
-		}
-
-		// Make sure that every updated delta has correct `baseVersion`.
-		// This is crucial for algorithms in `CompressedHistory` and algorithms using `CompressedHistory`.
-		for ( let delta of updatedDeltas ) {
-			delta.baseVersion = baseVersion;
-		}
-
-		// Put updated deltas in place of old deltas.
-		this._deltas.splice( this._getIndex( baseVersion ), deltas.length, ...updatedDeltas );
-
-		// Update history points.
-		this._updateHistoryPointsAfter( baseVersion, updatedDeltas.length - deltas.length );
-	}
-
-	/**
-	 * Returns base versions of deltas which has been marked as reversed, in given base versions range.
-	 *
-	 * @param {Number} [from=0] Start of base versions range to check.
-	 * @param {Number} [to=Number.POSITIVE_INFINITY] End of base versions range to check.
-	 * @returns {Iterator.<Number>} Base versions of deltas marked as reversed.
-	 */
-	*getInactiveBaseVersions( from = 0, to = Number.POSITIVE_INFINITY ) {
-		for ( let baseVersion of this._inactiveBaseVersions ) {
-			if ( baseVersion >= from && baseVersion < to ) {
-				yield baseVersion;
-			}
-		}
-	}
-
-	/**
-	 * Updates {@link engine.model.History#_historyPoints} structure.
-	 *
-	 * @private
-	 * @param {Number} baseVersion Base version of delta after which history points should be updated.
-	 * @param {Number} changeBy By how much change history points. Can be a negative value.
-	 */
-	_updateHistoryPointsAfter( baseVersion, changeBy ) {
-		for ( let key of this._historyPoints.keys() ) {
-			if ( key > baseVersion ) {
-				this._historyPoints.set( key, this._historyPoints.get( key ) + changeBy );
-			}
-		}
-	}
-}

+ 4 - 5
packages/ckeditor5-engine/src/model/document.js

@@ -11,7 +11,7 @@ import transformations from './delta/basic-transformations.js'; // jshint ignore
 
 
 import RootElement from './rootelement.js';
 import RootElement from './rootelement.js';
 import Batch from './batch.js';
 import Batch from './batch.js';
-import CompressedHistory from './compressedhistory.js';
+import History from './history.js';
 import Selection from './selection.js';
 import Selection from './selection.js';
 import EmitterMixin from '../../utils/emittermixin.js';
 import EmitterMixin from '../../utils/emittermixin.js';
 import CKEditorError from '../../utils/ckeditorerror.js';
 import CKEditorError from '../../utils/ckeditorerror.js';
@@ -108,13 +108,12 @@ export default class Document {
 		/**
 		/**
 		 * Document's history.
 		 * Document's history.
 		 *
 		 *
-		 * This is a compressed document history. It means that stored deltas might be removed or different
-		 * than originally applied deltas.
+		 * **Note:** Be aware that deltas applied to the stored deltas might be removed or changed.
 		 *
 		 *
 		 * @readonly
 		 * @readonly
-		 * @member {engine.model.CompressedHistory} engine.model.Document#history
+		 * @member {engine.model.History} engine.model.Document#history
 		 */
 		 */
-		this.history = new CompressedHistory( this );
+		this.history = new History( this );
 	}
 	}
 
 
 	/**
 	/**

+ 85 - 7
packages/ckeditor5-engine/src/model/history.js

@@ -8,11 +8,14 @@
 import CKEditorError from '../../utils/ckeditorerror.js';
 import CKEditorError from '../../utils/ckeditorerror.js';
 
 
 /**
 /**
- * `History` keeps the track of all the deltas applied to the {@link engine.model.Document document}. `History` can be
- * seen as "add-only" structure. You can read and add deltas, but can't modify them. Use this version of history to
- * retrieve applied deltas as they were, in the original form.
+ * `History` keeps the track of all the deltas applied to the {@link engine.model.Document document}. Deltas stored in
+ * `History` might get updated, split into more deltas or even removed. This is used mostly to compress history, instead
+ * of keeping all deltas in a state in which they were applied.
+ *
+ * **Note:** deltas kept in `History` should be used only to transform deltas. It's not advised to use `History` to get
+ * original delta basing on it's {@link engine.model.delta.Delta#baseVersion baseVersion}. Also, after transforming a
+ * delta by deltas from `History`, fix it's base version accordingly (set to {@link engine.model.Document#version}.
  *
  *
- * @see engine.model.CompressedHistory
  * @memberOf engine.model
  * @memberOf engine.model
  */
  */
 export default class History {
 export default class History {
@@ -88,15 +91,90 @@ export default class History {
 	}
 	}
 
 
 	/**
 	/**
-	 * Returns a delta from the history that has given {@link engine.model.delta.Delta#baseVersion}.
+	 * Returns one or more deltas from history that bases on given `baseVersion`. Most often it will be just
+	 * one delta, but if that delta got updated by multiple deltas, all of those updated deltas will be returned.
 	 *
 	 *
+	 * @see engine.model.History#updateDelta
 	 * @param {Number} baseVersion Base version of the delta to retrieve.
 	 * @param {Number} baseVersion Base version of the delta to retrieve.
-	 * @returns {engine.model.delta.Delta|null} Delta with given base version or null if no such delta is in history.
+	 * @returns {Array.<engine.model.delta.Delta>|null} Delta with given base version or null if no such delta is in history.
 	 */
 	 */
 	getDelta( baseVersion ) {
 	getDelta( baseVersion ) {
 		let index = this._historyPoints.get( baseVersion );
 		let index = this._historyPoints.get( baseVersion );
 
 
-		return this._deltas[ index ] || null;
+		if ( index === undefined ) {
+			return null;
+		}
+
+		const deltas = [];
+
+		for ( index; index < this._deltas.length; index++ ) {
+			const delta = this._deltas[ index ];
+
+			if ( delta.baseVersion != baseVersion ) {
+				break;
+			}
+
+			deltas.push( delta );
+		}
+
+		return deltas.length === 0 ? null : deltas;
+	}
+
+	/**
+	 * Removes delta from the history. This happens i.e., when a delta is undone by another delta. Both undone delta and
+	 * undoing delta should be removed so they won't have an impact on transforming other deltas.
+	 *
+	 * **Note:** using this method does not change the state of {@link engine.model.Document model}. It just affects
+	 * the state of `History`.
+	 *
+	 * **Note:** when some deltas are removed, deltas between them should probably get updated. See
+	 * {@link engine.model.History#updateDelta}.
+	 *
+	 * **Note:** if delta with `baseVersion` got {@link engine.model.History#updateDelta updated} by multiple
+	 * deltas, all updated deltas will be removed.
+	 *
+	 * @param {Number} baseVersion Base version of a delta to be removed.
+	 */
+	removeDelta( baseVersion ) {
+		this.updateDelta( baseVersion, [] );
+	}
+
+	/**
+	 * Substitutes delta in history by one or more given deltas.
+	 *
+	 * **Note:** if delta with `baseVersion` was already updated by multiple deltas, all updated deltas will be removed
+	 * and new deltas will be inserted at their position.
+	 *
+	 * **Note:** delta marked as reversed won't get updated.
+	 *
+	 * @param {Number} baseVersion Base version of a delta to update.
+	 * @param {Iterable.<engine.model.delta.Delta>} updatedDeltas Deltas to be inserted in place of updated delta.
+	 */
+	updateDelta( baseVersion, updatedDeltas ) {
+		const deltas = this.getDelta( baseVersion );
+
+		// If there are no deltas, stop executing function as there is nothing to update.
+		if ( deltas === null ) {
+			return;
+		}
+
+		// Make sure that every updated delta has correct `baseVersion`.
+		// This is crucial for algorithms in `History` and algorithms using `History`.
+		for ( let delta of updatedDeltas ) {
+			delta.baseVersion = baseVersion;
+		}
+
+		// Put updated deltas in place of old deltas.
+		this._deltas.splice( this._getIndex( baseVersion ), deltas.length, ...updatedDeltas );
+
+		// Update history points.
+		const changeBy = updatedDeltas.length - deltas.length;
+
+		for ( let key of this._historyPoints.keys() ) {
+			if ( key > baseVersion ) {
+				this._historyPoints.set( key, this._historyPoints.get( key ) + changeBy );
+			}
+		}
 	}
 	}
 
 
 	/**
 	/**

+ 0 - 170
packages/ckeditor5-engine/tests/model/compressedhistory.js

@@ -1,170 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import CompressedHistory from '/ckeditor5/engine/model/compressedhistory.js';
-import Delta from '/ckeditor5/engine/model/delta/delta.js';
-import Operation from '/ckeditor5/engine/model/operation/operation.js';
-
-describe( 'CompressedHistory', () => {
-	let history;
-
-	beforeEach( () => {
-		history = new CompressedHistory();
-	} );
-
-	describe( 'updateDelta', () => {
-		it( 'should substitute delta from history by given deltas', () => {
-			history.addDelta( getDelta( 0 ) );
-
-			const deltas = getDeltaSet();
-			history.updateDelta( 0, deltas );
-
-			const historyDeltas = Array.from( history.getDeltas() );
-			expect( historyDeltas ).to.deep.equal( deltas );
-		} );
-
-		it( 'should substitute all updated deltas by new deltas', () => {
-			history.addDelta( getDelta( 0 ) );
-
-			// Change original single delta to three deltas generated by `getDeltaSet`.
-			// All those deltas should now be seen under base version 0.
-			history.updateDelta( 0, getDeltaSet() );
-
-			const deltas = getDeltaSet();
-			// Change all three deltas from base version 0 to new set of deltas.
-			history.updateDelta( 0, deltas );
-
-			const historyDeltas = Array.from( history.getDeltas() );
-			expect( historyDeltas ).to.deep.equal( deltas );
-		} );
-
-		it( 'should do nothing if deltas for given base version has not been found in history', () => {
-			history.addDelta( getDelta( 0 ) );
-			history.removeDelta( 0 );
-
-			const deltas = getDeltaSet();
-
-			history.updateDelta( 0, deltas );
-
-			expect( Array.from( history.getDeltas() ).length ).to.equal( 0 );
-		} );
-	} );
-
-	describe( 'removeDelta', () => {
-		it( 'should remove deltas that do not have graveyard related operations', () => {
-			for ( let delta of getDeltaSet() ) {
-				history.addDelta( delta );
-			}
-
-			history.removeDelta( 3 );
-
-			const deltas = Array.from( history.getDeltas() );
-			expect( deltas.length ).to.equal( 2 );
-		} );
-
-		it( 'should remove multiple updated deltas', () => {
-			let delta = getDelta( 0 );
-			history.addDelta( delta );
-
-			let updatedDeltas = getDeltaSet( 0 );
-
-			history.updateDelta( 0, updatedDeltas );
-			history.removeDelta( 0 );
-
-			const deltas = Array.from( history.getDeltas() );
-			expect( deltas.length ).to.equal( 0 );
-		} );
-
-		it( 'should do nothing if deltas for given base version has not been found in history', () => {
-			const deltas = getDeltaSet();
-
-			for ( let delta of deltas ) {
-				history.addDelta( delta );
-			}
-
-			history.removeDelta( 12 );
-
-			expect( Array.from( history.getDeltas() ) ).to.deep.equal( deltas );
-		} );
-	} );
-
-	describe( 'getDelta', () => {
-		it( 'should return array with one delta with given base version', () => {
-			let delta = getDelta( 0 );
-			history.addDelta( delta );
-
-			const historyDelta = history.getDelta( 0 );
-			expect( historyDelta ).to.deep.equal( [ delta ] );
-		} );
-
-		it( 'should return array with all updated deltas of delta with given base version', () => {
-			let delta = getDelta( 0 );
-			history.addDelta( delta );
-
-			let deltas = getDeltaSet();
-			history.updateDelta( 0, deltas );
-
-			const historyDelta = history.getDelta( 0 );
-			expect( historyDelta ).to.deep.equal( deltas );
-		} );
-
-		it( 'should return null if delta has not been found in history', () => {
-			expect( history.getDelta( -1 ) ).to.be.null;
-			expect( history.getDelta( 2 ) ).to.be.null;
-			expect( history.getDelta( 20 ) ).to.be.null;
-		} );
-
-		it( 'should return null if delta has been removed by removeDelta', () => {
-			let delta = getDelta( 0 );
-			history.addDelta( delta );
-			history.removeDelta( 0 );
-
-			expect( history.getDelta( 0 ) ).to.be.null;
-		} );
-	} );
-
-	describe( 'getInactiveBaseVersions', () => {
-		it( 'should return inactive base versions from given base versions range', () => {
-			for ( let delta of getDeltaSet() ) {
-				history.addDelta( delta );
-			}
-
-			history.removeDelta( 3 );
-			history.removeDelta( 6 );
-
-			expect( Array.from( history.getInactiveBaseVersions() ) ).to.deep.equal( [ 3, 6 ] );
-			expect( Array.from( history.getInactiveBaseVersions( 0 ) ) ).to.deep.equal( [ 3, 6 ] );
-			expect( Array.from( history.getInactiveBaseVersions( 3 ) ) ).to.deep.equal( [ 3, 6 ] );
-			expect( Array.from( history.getInactiveBaseVersions( 0, 3 ) ) ).to.deep.equal( [] );
-			expect( Array.from( history.getInactiveBaseVersions( 0, 4 ) ) ).to.deep.equal( [ 3 ] );
-			expect( Array.from( history.getInactiveBaseVersions( 0, 6 ) ) ).to.deep.equal( [ 3 ] );
-			expect( Array.from( history.getInactiveBaseVersions( 4 ) ) ).to.deep.equal( [ 6 ] );
-			expect( Array.from( history.getInactiveBaseVersions( 6 ) ) ).to.deep.equal( [ 6 ] );
-			expect( Array.from( history.getInactiveBaseVersions( 9 ) ) ).to.deep.equal( [] );
-		} );
-	} );
-} );
-
-function getDeltaSet() {
-	const deltas = [];
-
-	deltas.push( getDelta( 0 ) );
-	deltas.push( getDelta( 3 ) );
-	deltas.push( getDelta( 6 ) );
-
-	return deltas;
-}
-
-function getDelta( baseVersion ) {
-	const delta = new Delta();
-
-	for ( let i = 0; i < 3; i++ ) {
-		delta.addOperation( new Operation( i + baseVersion ) );
-	}
-
-	return delta;
-}

+ 100 - 9
packages/ckeditor5-engine/tests/model/history.js

@@ -68,6 +68,41 @@ describe( 'History', () => {
 		} );
 		} );
 	} );
 	} );
 
 
+	describe( 'getDelta', () => {
+		it( 'should return array with one delta with given base version', () => {
+			let delta = getDelta( 0 );
+			history.addDelta( delta );
+
+			const historyDelta = history.getDelta( 0 );
+			expect( historyDelta ).to.deep.equal( [ delta ] );
+		} );
+
+		it( 'should return array with all updated deltas of delta with given base version', () => {
+			let delta = getDelta( 0 );
+			history.addDelta( delta );
+
+			let deltas = getDeltaSet();
+			history.updateDelta( 0, deltas );
+
+			const historyDelta = history.getDelta( 0 );
+			expect( historyDelta ).to.deep.equal( deltas );
+		} );
+
+		it( 'should return null if delta has not been found in history', () => {
+			expect( history.getDelta( -1 ) ).to.be.null;
+			expect( history.getDelta( 2 ) ).to.be.null;
+			expect( history.getDelta( 20 ) ).to.be.null;
+		} );
+
+		it( 'should return null if delta has been removed by removeDelta', () => {
+			let delta = getDelta( 0 );
+			history.addDelta( delta );
+			history.removeDelta( 0 );
+
+			expect( history.getDelta( 0 ) ).to.be.null;
+		} );
+	} );
+
 	describe( 'getDeltas', () => {
 	describe( 'getDeltas', () => {
 		let deltas;
 		let deltas;
 
 
@@ -101,23 +136,79 @@ describe( 'History', () => {
 		} );
 		} );
 	} );
 	} );
 
 
-	describe( 'getDelta', () => {
-		beforeEach( () => {
+	describe( 'updateDelta', () => {
+		it( 'should substitute delta from history by given deltas', () => {
+			history.addDelta( getDelta( 0 ) );
+
+			const deltas = getDeltaSet();
+			history.updateDelta( 0, deltas );
+
+			const historyDeltas = Array.from( history.getDeltas() );
+			expect( historyDeltas ).to.deep.equal( deltas );
+		} );
+
+		it( 'should substitute all updated deltas by new deltas', () => {
+			history.addDelta( getDelta( 0 ) );
+
+			// Change original single delta to three deltas generated by `getDeltaSet`.
+			// All those deltas should now be seen under base version 0.
+			history.updateDelta( 0, getDeltaSet() );
+
+			const deltas = getDeltaSet();
+			// Change all three deltas from base version 0 to new set of deltas.
+			history.updateDelta( 0, deltas );
+
+			const historyDeltas = Array.from( history.getDeltas() );
+			expect( historyDeltas ).to.deep.equal( deltas );
+		} );
+
+		it( 'should do nothing if deltas for given base version has not been found in history', () => {
+			history.addDelta( getDelta( 0 ) );
+			history.removeDelta( 0 );
+
+			const deltas = getDeltaSet();
+
+			history.updateDelta( 0, deltas );
+
+			expect( Array.from( history.getDeltas() ).length ).to.equal( 0 );
+		} );
+	} );
+
+	describe( 'removeDelta', () => {
+		it( 'should remove deltas that do not have graveyard related operations', () => {
 			for ( let delta of getDeltaSet() ) {
 			for ( let delta of getDeltaSet() ) {
 				history.addDelta( delta );
 				history.addDelta( delta );
 			}
 			}
+
+			history.removeDelta( 3 );
+
+			const deltas = Array.from( history.getDeltas() );
+			expect( deltas.length ).to.equal( 2 );
 		} );
 		} );
 
 
-		it( 'should return delta from history that has given base version', () => {
-			let delta = history.getDelta( 3 );
+		it( 'should remove multiple updated deltas', () => {
+			let delta = getDelta( 0 );
+			history.addDelta( delta );
+
+			let updatedDeltas = getDeltaSet( 0 );
+
+			history.updateDelta( 0, updatedDeltas );
+			history.removeDelta( 0 );
 
 
-			expect( delta.baseVersion ).to.equal( 3 );
+			const deltas = Array.from( history.getDeltas() );
+			expect( deltas.length ).to.equal( 0 );
 		} );
 		} );
 
 
-		it( 'should return null if delta has not been found in history', () => {
-			expect( history.getDelta( -1 ) ).to.be.null;
-			expect( history.getDelta( 2 ) ).to.be.null;
-			expect( history.getDelta( 20 ) ).to.be.null;
+		it( 'should do nothing if deltas for given base version has not been found in history', () => {
+			const deltas = getDeltaSet();
+
+			for ( let delta of deltas ) {
+				history.addDelta( delta );
+			}
+
+			history.removeDelta( 12 );
+
+			expect( Array.from( history.getDeltas() ) ).to.deep.equal( deltas );
 		} );
 		} );
 	} );
 	} );
 } );
 } );