Push steps to history undo

When starting a collab implementation I want to initialize the history with a number of steps pushed into it’s undo buffer.

I am looking for something like a pushSteps(steps) method in the history module. This will fail if the undo history is not empty.

At the moment, closing and restarting a session creates an empty history and even though the steps may well be there on the database, the user cannot access them. Being able to (load and) push a certain amount of steps to the undo history gives the user the big advantage of being able to undo changes from previous sessions (or if so implemented , undo changes of other users as well).


You seem to have updated your message from proposing a config option to proposing a method – why? The former did sound like a better idea.

In a collab setting, this could get quite tricky – undoing other people’s changes is usually not what people want.

But a bigger problem is that steps simply don’t contain the information needed to invert them. I.e. if you have ‘delete between 10 and 20’, but you don’t have the original document, you can’t create a step that inverts that effect because you don’t have the old content between 10 and 20. We could require the user to pass an array of inverted steps, I guess. It’s somewhat confusing, interface wise, but it’d work. Would that solve your issue?

I changed the original post because it would only allow a predefined number of steps to add to undo.

I was thinking of allowing unlimited travel back in time up to the very beginning but without loading all the steps at once. So that when the undo history is empty, and the user then crtl+z I can block the editor with an hourglass, do an async call to get X previous steps and push them to the undo history.

I see your point about the missing information, I don’t know if passing an array of inverted steps will work for me, I am working on a Firebase solution so there’s no server to manufacture them ? (I am a bit confused about the concept of inverted steps and how they are created). Perhaps what I can do is keep checkpoints and pass the doc of the previous checkpoint and an array of steps since that doc.

Or is there a better way ? I feel this is a really strong feature worth working towards.

further if I understand correctly if I have a doc (checkpoint) and a series of steps from it I can covert it into an array of inverted steps which can then be provided as you suggested above ? that can work, though I don’t know how to do this conversion …

I’m not really interested in a way to manipulate the plugin state after initializing it – that seems too magical – but you could, if you wanted, reinitialize your state with different options when ctrl-z is pressed, and then run an undo on the new state.

Yes, a step’s invert method takes the document before the step as argument, to get the information necessary to create the inverse step. So if you have a snapshot and a set of steps, you can run through those steps again, and for each one, create an inverted version by passing it the previous document.

A question that remains is how such steps should be divided into events (i.e. how many of them are inverted for a single ctrl-z press).

ok great

Do you mean re initializing the state with a new history plugin (with the prev steps pushed in) ? that’ll work but I’m not sure how to initialize a state with a new history plugin which (except for the pushed old steps) is identical to the one it had before … will I have access to the prev history config options (depth & newGroupDelay) ?

As for dividing steps, this can simply be giving an array of arrays of steps with each internal array constituting a single undo. This will actually work very well for me as I already store the steps in ‘versions’ each containing multiple steps.

Another better thing I can do is to store all versions/steps older than the last checkpoint as inverted. In this case I only need one (last) checkpoint and pushing them to history is very easy.

Any thoughts ?

Wouldn’t you only use this when the history was empty to begin with?

I thought you were leaning towards allowing a new history config/init to receive past undo steps (rather than an existing history with an empty undo buffer).

In that scenario, every time undo is empty and I want go still further back, that is do an async get of past steps, I need a new history to initialize with those steps. This is why I was asking how will that be done (and why perhaps pushing past steps into an existing empty history may be better).

Or how do you envision it ? the point is to be able to repeat the process of adding past steps an empty history, every time filling X undos each one with it’s steps

Marijn, any more thoughts on this ? do you have any API in mind ?

I wanted to suggest a push method on history receiving an array of arrays of inverted steps with each internal array representing a single undo step to be added. This method will fail if the current undo buffer is not empty.