Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

T/undo 2 #499

Merged
merged 15 commits into from
Jun 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/datacontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ export default class DataController {
const modelRoot = this.model.getRoot( rootName );

this.model.enqueueChanges( () => {
this.model.batch()
// Initial batch should be ignored by features like undo, etc.
this.model.batch( 'transparent' )
.remove( ModelRange.createFromElement( modelRoot ) )
.insert( ModelPosition.createAt( modelRoot, 0 ), this.parse( data ) );
} );
Expand Down
38 changes: 31 additions & 7 deletions src/model/batch.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,51 @@ export default class Batch {
* Creates Batch instance. Not recommended to use directly, use {@link engine.model.Document#batch} instead.
*
* @param {engine.model.Document} doc Document which this Batch changes.
* @param {'transparent'|'default'} [type='default'] Type of the batch.
*/
constructor( doc ) {
constructor( doc, type = 'default' ) {
/**
* Document which this Batch changes.
* Document which this batch changes.
*
* @member {engine.model.Document} engine.model.Batch#doc
* @readonly
* @member {engine.model.Document} engine.model.Batch#doc
*/
this.doc = doc;

/**
* Array of deltas which compose Batch.
* Array of deltas which compose this batch.
*
* @member {Array.<engine.model.delta.Delta>} engine.model.Batch#deltas
* @readonly
* @member {Array.<engine.model.delta.Delta>} engine.model.Batch#deltas
*/
this.deltas = [];

/**
* Type of the batch.
*
* Can be one of the following values:
* * `'default'` - all "normal" batches, most commonly used type.
* * `'transparent'` - batch that should be ignored by other features, i.e. initial batch or collaborative editing changes.
*
* @readonly
* @member {'transparent'|'default'} engine.model.Batch#type
*/
this.type = type;
}

/**
* Returns this batch base version, which is equal to the base version of first delta in the batch.
* If there are no deltas in the batch, it returns `null`.
*
* @readonly
* @type {Number|null}
*/
get baseVersion() {
return this.deltas.length > 0 ? this.deltas[ 0 ].baseVersion : null;
}

/**
* Adds delta to the Batch instance. All modification methods (insert, remove, split, etc.) use this method
* Adds delta to the batch instance. All modification methods (insert, remove, split, etc.) use this method
* to add created deltas.
*
* @param {engine.model.delta.Delta} delta Delta to add.
Expand All @@ -81,7 +105,7 @@ export default class Batch {
}

/**
* Function to register Batch methods. To make code scalable Batch do not have modification
* Function to register batch methods. To make code scalable Batch do not have modification
* methods built in. They can be registered using this method.
*
* This method checks if there is no naming collision and throws `batch-register-taken` if the method name
Expand Down
11 changes: 10 additions & 1 deletion src/model/delta/basic-transformations.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,19 @@ addTransformationCase( UnwrapDelta, SplitDelta, ( a, b, isStrong ) => {
// If incoming unwrap delta tries to unwrap node that got split we should unwrap the original node and the split copy.
// This can be achieved either by reverting split and applying unwrap to singular node, or creating additional unwrap delta.
if ( compareArrays( a.position.path, b.position.getParentPath() ) === 'SAME' ) {
return [
const transformed = [
b.getReversed(),
a.clone()
];

// It's a kind of magic-magic-magic-maaaaagiiic!
transformed[ 1 ].operations[ 1 ].targetPosition.path[ 0 ]++;
// But seriously, we have to fix RemoveOperation in the second delta because reversed UnwrapDelta creates
// MergeDelta which also has RemoveOperation. Those two operations cannot point to the same "holder" element
// in the graveyard, so we fix it by hand. This is the only case where it happens in "special" transformation
// cases, and it won't happen for "default" transformation apart of RemoveDelta, where it is okay.

return transformed;
}

return defaultTransform( a, b, isStrong );
Expand Down
14 changes: 10 additions & 4 deletions src/model/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,12 @@ export default class Document {
/**
* Document's history.
*
* **Note:** Be aware that deltas applied to the stored deltas might be removed or changed.
*
* @readonly
* @member {engine.model.History} engine.model.Document#history
*/
this.history = new History();
this.history = new History( this );
}

/**
Expand Down Expand Up @@ -159,7 +161,10 @@ export default class Document {

this.version++;

this.history.addOperation( operation );
if ( operation.delta ) {
// Right now I can't imagine operations without deltas, but let's be safe.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can hide an error this way. Silent exit is never a good solution. If you want to be save throw error.

this.history.addDelta( operation.delta );
}

const batch = operation.delta && operation.delta.batch;

Expand All @@ -172,10 +177,11 @@ export default class Document {
/**
* Creates a {@link engine.model.Batch} instance which allows to change the document.
*
* @param {String} [type] Batch type. See {@link engine.model.Batch#type}.
* @returns {engine.model.Batch} Batch instance.
*/
batch() {
return new Batch( this );
batch( type ) {
return new Batch( this, type );
}

/**
Expand Down
Loading