Here is a gist of a modified undo-plugin with a series of workarounds to make it work.
I'm not submitting this as a pull-request because it's a dirty workaround, there should be a little more thought to make Aloha cooperate better with the undo-plugin.
The method aevent.getSnapshotContent is not as up-to-date as it should, as a result the diff_match_patch plugin always finds differences and generates changes after an undo or redo.
The undo operation keeps toggling the last edit.
Our solution was to ignore this method and assign an oldContent property to the current editable.
Sometimes snapshots are taken just before the undo or redo operations, making it difficult to create proper undo / redo buttons that are aware of the current stack position.
It should be possible to catch changes more accurately.
Our solution was to extract the snapshot logic from the smart-content-change listener to an exposed method (takeStapshot) of the undo plugin and use it whenever possible, mostly after DOM insertions from our plugins.
It would be nice to have an API to manipulate content in an editable. The current GENTICS.Utils.Dom is completely decoupled from the editor, as it should, but there could be a simpler layer between Aloha and these helpers.
This API could transparently trigger events to allow the undo plugin to take snapshots.
Also, the smart-content-change event could rely less on timeouts and delimiters and more on this API.
The undo / redo commands are associated with the active editable. This is a problem when there are nested editables like blocks with editable regions.
The following workflow may explain better the issue:
- insert a nested editable
- type some text in the new editable
- undoing the text works
- undoing the nested editable insert works
- redoing the insert works
- redoing the text doesn't work because the stack command is associated with an editable whose DOM obj is dettached from the document, the action has no effect
Our solution was to always find a "root editable", which is the current or outer-most editable wrapping other editables. As long as it is attached to the document, it can hold other editables modifications.
The getContents method of an editor uses the makeClean methods of plugins for custom sanitization of content.
The table plugin makeClean method operates on the actual editable element instead of sanitizing the cloned content. This forces editing controls and the block behaviour to be removed, using table.deactivate and mahaloBlock.
To avoid this, it relies on the editor activation / deactivation after undo or redo operations to re-apply the editing controls on the original editable, but the block behaviour is lost.
This re-activation seems to be there just to cover the table plugin editing behaviour.
Our solution was to listen to table-activated events and installing the appropriate block behaviour.
Block behaviour are not automatically restored after an undo or redo.
The better solution we found was to read settings and reinstall blocks. There could be an exposed method for this as it is used on editable creation.