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

Undo Feature. #1

Merged
merged 13 commits into from
May 13, 2016
Merged

Undo Feature. #1

merged 13 commits into from
May 13, 2016

Conversation

scofalik
Copy link
Contributor

@scofalik scofalik commented Mar 18, 2016

Undo Feature. Fixes ckeditor/ckeditor5#2683.

}
}

this.fire( 'undo', undoBatch );
Copy link

Choose a reason for hiding this comment

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

Because redo is also an UndoCommand the event should be called reverted. It is strange that redo command fire undo event.

@pjasiun
Copy link

pjasiun commented Mar 30, 2016

Beside these small changes mentioned above, two biggest missing parts are: selection handling and UI. If you do not want to handle them as a part of this ticket please create follow-ups. On the other hand selection may change undo so much that there is no point in considering undo without selection.

@fredck
Copy link

fredck commented Mar 30, 2016

there is no point in considering undo without selection

Agree... selection is in fact one of the essential things related to undo.

@scofalik
Copy link
Contributor Author

scofalik commented May 4, 2016

I've implemented selection handling. It should work really well / perfect with non-selective undo where batches are not divided by other batches or when mixed delta is not conflicting with deltas from undone batch.

I did expanded implementation of range transformation so I expect that the selection should work okay in selective undo or mixed conflicting deltas too, but just don't expect wonders.

This comment is more suitable for ckeditor5-engine repo because that's where the magic happens, but I wanted to sum up the work here aswell.

Changes that are needed for this branch to work are on ckeditor5-engine branch t/389.

} );
} );

describe( '_doExecute', () => {
Copy link

Choose a reason for hiding this comment

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

There should not be tests for private class. If you want to test this method you should change it to "protected".

Copy link
Contributor Author

@scofalik scofalik May 4, 2016

Choose a reason for hiding this comment

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

In fact, what should be done is:

  • _doExecute should be private as it is called by _execute
  • _execute should be tested.

I'll change it.

@scofalik
Copy link
Contributor Author

scofalik commented May 4, 2016

I added selection direction restoring. I've changed tests so they test protected _execute method instead of private _doExecute. I also removed a test for addBatch method as all it tested was private members.

I hope it is okay to merge now.

batch,
{
ranges: Array.from( this.editor.document.selection.getRanges() ),
isBackward: this.editor.document.selection.isBackward
Copy link

Choose a reason for hiding this comment

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

Still: why now selection.clone()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've already written why in one of comments (it got outdated and hidden). Selection uses LiveRanges and would get transformed if we saved Selection. This, and other reasons.

@Reinmar
Copy link
Member

Reinmar commented May 9, 2016

BTW. which issue is this PR closing?

@scofalik
Copy link
Contributor Author

scofalik commented May 9, 2016

#3

} );

// Whenever batch is reverted by undo command, add it to redo history.
this._undoCommand.listenTo( this._redoCommand, 'revert', ( evt, batch ) => {
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't be the feature listening? In 99% of situation we should be using listenTo() on this, because the class which adds a listener is interested in removing it while it's gone.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right. I probably thought that this solution looks cool but it will be better if feature is listening.

@Reinmar
Copy link
Member

Reinmar commented May 11, 2016

I'm missing some more integrational tests, like:

  1. Use composer to change the doc (perhaps create couple undo steps at once).
  2. Check commands' states.
  3. Undo and see that the data and selection are correct.

Those tests should be written with our test utils, so they are easy to read.

Having some low level tests is fine, but in a long run they will be hard to maintain, read and extend. That's when the easy-to-write and easy-to-read higher level tests are useful. I'd add some now (in a separate test file most likely) to have easier start in the future and easier review now.

@scofalik
Copy link
Contributor Author

scofalik commented May 12, 2016

I could create some integrational tests using model test utils and see if model is fine but right now composer only has deleteContents so I'd have to create batches by hand anyway, just like in UndoCommand tests. I would just not have to add them to UndoCommand instance. Same with selection, I'd have to manually set it.

I looked at utils/src/diff.js and utils/src/difftochanges.js and those maybe could be used to automatically generate batches. Or, if we would be able to diff to model trees, we could use setData tool.

@Reinmar
Copy link
Member

Reinmar commented May 12, 2016

Doing changes is one part of a test. Second is setting data and checking the output. Currently you're building a document by creating lots of deltas, then do some operations (or even not – some tests starts with undo._execute()) and then some checks. This is fine (I guess), but it's not something that you can read and extend quickly.

By doing simple:

setData( doc, '<p>foo[bar]</p>' );
doc.composer.deleteContents( doc.batch(), doc.selection ); // You can also use some deltas.
expect( getData( doc ) ).to.equal( '<p>foo[]</p>' );

You will be able to quickly generate more test cases which underneath do quite similar things as you did with the low level API.

E.g. let's imagine that we find a bug in a very specific case in the future. The first thing to do will be to code a test for it exactly like I showed. So we'll be definitely adding those. I'd just like to have some already, so I can verify on couple of cases that the undo performs as expected. I'm not able to do this quickly based on the existing tests.

@scofalik
Copy link
Contributor Author

I've added integration tests. Unfortunately, some of them fail, but not directly because of undo algorithms. I've commented them. I will create followup ticket for them in ckeditor5-engine.

@scofalik
Copy link
Contributor Author

I also fixed other issues you pointed out.

@scofalik
Copy link
Contributor Author

I commented out tests that failed and created followup issue in ckeditor5-engine

@Reinmar
Copy link
Member

Reinmar commented May 13, 2016

I reported https://github.com/ckeditor/ckeditor5-undo/issues/6 for the ignored tests.

if ( !batch ) {
batchIndex = this._batchStack.length - 1;
} else {
for ( let i = 0; i < this._batchStack.length; i++ ) {
Copy link
Member

Choose a reason for hiding this comment

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

@Reinmar
Copy link
Member

Reinmar commented May 13, 2016

…ions. Tests: Fixed the way how feature is initialized and made sure to use beforeEach().
@scofalik
Copy link
Contributor Author

scofalik commented May 13, 2016

It needed a change in ckeidtor5-engine that I had only locally. Already fixed by ckeditor/ckeditor5-engine#414

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create Undo feature.
5 participants