Hi. I’m trying to figure out the best way to “group” transactions for undo/redo. Right now, our app is setup to add a node, and add a bottom ornament after we do some processing (like, 50ms later).
Out of the box, undo undoes the ornament, then undoes the node addition. What I’d like to do is treat those as a single “undo” action.
At the moment, I have a model change listener that does the following…
if (
e.isTransactionFinished &&
!this.diagram.undoManager.isUndoingRedoing &&
!/^(.*)\.[0-9]+$/.test(e.object.name)
) {
// Update transaction to match <name>.<timestamp>
e.object.name = [e.object.name, ".", Date.now()].join("");
}
Then, when undoing or redoing, I basically extract the timestamp and undo or redo until the difference between two transaction timestamps exceeds a threshold (200ms) or there is nothing to undo/redo.
I think this approach could work in most cases, but it feels pretty hacky. I was wondering if there are any examples/thoughts as to a less fragile way of approaching this?
I suppose one could merge two consecutive Transactions by moving the Transaction.changes list of the second Transaction into the first one’s changes list, and then deleting the second Transaction. But there are probably some read-only-ness considerations that prevent that from being straight-forward.
A more serious consideration is what could happen if another transaction (or multiple ones) happen between the addition of the node and the ornamentation modification. Maybe there could be two node additions and then two ornamentation modifications, and their orders might be different. I don’t have an answer for you there. In general one really wants to keep all of the changes in the same order in which they occurred. Maybe it would be safe to change that order, but it’s potentially dangerous.
In our application, there’s definitely the ability to drag multiple nodes at a time onto a graph, so we’d likely add both nodes, then add both ornaments.
Conceptually, it seems like that is one “action” to the user, in which case, I would expect the undo to undo all 4 transactions.
Presumably you would implement all of the node additions at one time, and all of the ornamentation at one time (i.e. one server response).
In version 3.1 there will be an undocumented way for programmers to modify the UndoManager.history and Transaction.changes. 3.1 beta will be starting soon.