I don’t know how to describe the problem precisely, let me directly show an example:
Suppose there is a Doc, which is a folder, then
-
step 1, create a subDoc (a file)
-
step 2, write some characters in the file
-
step 3, write some characters in the file
Expected behavior, Since there are three steps, then by undo
3 times, the folder becomes empty again. By redo
3 times, we go back to current status.
Now an undoManager can only observe one doc, so for the case, at least two undoManagers should exist.
However, the problem is, a doc’s lifetime MUST be longer than its undoManager’s lifetime. That’s because the undoManager internally holds the doc.
So here is the problem, when the undo
is applied the 3rd time, the file disappears, which means the undoManager of the file is useless. When redo
is applied for the first time, a new file is created again, we cannot link the original undoManager to the new subDoc.
A possible workaround would be implementing a customized version of UndoManager, whose stack item is a map of subDoc uuid to DeleteSet. Therefore, the UndoManager
can track all the subDocs and maintain their history even when they are destroyed.
Do you have any better suggestions?
Sample NodeJS script:
(it does not work now, but I want to achieve something like that. At least another UndoManager of the subDoc should be created, but the lifecycle problem also needs to be solved)
const Y = require("yjs");
async function delay(waitMs) {
await new Promise((resolve) => {
setTimeout(resolve, waitMs);
});
}
const doc = new Y.Doc();
const root = doc.getMap();
const manager = new Y.UndoManager(root, {
captureTimeout: 50,
});
console.log(JSON.stringify(root.toJSON()));
await delay(100);
// ---------- User actions in 3 steps ----------
const subDoc = new Y.Doc();
root.set("subDoc", subDoc);
console.log(subDoc.guid);
console.log(JSON.stringify(root.toJSON()));
await delay(100);
const text = subDoc.getText("text");
text.insert(0, "abc");
console.log(JSON.stringify(root.toJSON()));
await delay(100);
text.insert(3, "def");
console.log(JSON.stringify(root.toJSON()));
await delay(100);
// ---------- Undo 3 times ----------
manager.undo();
console.log(JSON.stringify(root.toJSON()));
manager.undo();
console.log(JSON.stringify(root.toJSON()));
manager.undo();
console.log(JSON.stringify(root.toJSON()));
// ---------- Redo 3 times ----------
manager.redo();
console.log(root.get('subDoc').guid);
console.log(JSON.stringify(root.toJSON()));
manager.redo();
console.log(JSON.stringify(root.toJSON()));
manager.redo();
console.log(JSON.stringify(root.toJSON()));