I'd like to see this too, currently if you delete something, it's gone for good.
On the undo-redo note - I've been using immer for a project recently and adding in my own undo / redo functionality was trivial. It is a great library because it offers the ability to use "patches" (https://github.com/mweststrate/immer#patches) which are records of the individual pieces of your JSON tree that you have changed on your object.
The easy of use it brings to editing big JSON objects directly might be useful as a whole to this project, and the patches would be a great addition to allow complete control over undo / redo.
Behind the scenes they look something like this (you get both regular and inverse patches so you can go both ways):
// inverse
[
{
"op": "replace",
"path": ["profile"],
"value": {"name": "Veria", "age": 5}
},
{"op": "remove", "path": ["tags", 3]}
]
// regular
[
{"op": "replace", "path": ["profile"], "value": {"name": "Noa", "age": 6}},
{"op": "add", "path": ["tags", 3], "value": "kiddo"}
]
I actually think its the perfect data tool for something like a block editor. I understand not wanting to add dependencies, but this one could be worth looking at and its only 4.2kB gzipped.
Hi @lostpebble !
I was working on these features using "patches" too, thanks for pointing out the immer!
This also would be really good for the future collaborative mode
This also would be really good for the future collaborative mode
Yep exactly! That's part of the magic - only sending exactly the changes that are being made instead of the entire tree.
This could definitely kill two birds with one stone, undo / redo and collaborative modes.
I would definitely take more of a look at immer as whole too, it really has made my life 10x easier when working on my state library (https://github.com/lostpebble/pullstate) - in fact I made it a core mechanic - as it allows you to mutate your state objects directly and it can figure out when nothing has changed very easily (good for performance checks). Overall a brilliant library!
The problem I faced is we need to work with DOM state directly if we don't want to plugin developers care about that. It is a little inconsistent with the idea of working with the data as JS objects. Anyway will look at the immer, thanks!
Ah, okay. That is a little disappointing requirement, I was thinking that this was more of a "virtual" DOM as a whole - based completely off of the JSON object.
We will think of options how to implement this. I hope we will include it to the next major release
Great library guys! Without undo operations, it is hard to envision anyone using this for production apps.
If the DOM could somehow be reactive to the underlying JSON model, then one could fairly easily implement undo/redo and collaborative editing using a CRDT library such as AutoMerge.
Using CDRT, in my opinion, would give this library a huge leg up on the competition, which primarily use Operational Transformation (which from my understanding requires a server to ensure that operations are transformed in the correct order, as opposed to CDRT, which does not care about order of transactions).
Hi! Any info about this bug? Can't work without undo-redo =(
what is the current progress on the undo/redo feature?
how about the simple idea to keep change history and call Block.render(previousDATA)?
Method removes all Blocks and fills with new passed JSON data
Hey Guys, any news about this feature?
On the undo-redo note - I've been using immer for a project recently and adding in my own undo / redo functionality was trivial. It is a great library because it offers the ability to use "patches" (https://github.com/mweststrate/immer#patches) which are records of the individual pieces of your JSON tree that you have changed on your object.
The easy of use it brings to editing big JSON objects directly might be useful as a whole to this project, and the patches would be a great addition to allow complete control over undo / redo.
Behind the scenes they look something like this (you get both regular and inverse patches so you can go both ways):
// inverse [ { "op": "replace", "path": ["profile"], "value": {"name": "Veria", "age": 5} }, {"op": "remove", "path": ["tags", 3]} ] // regular [ {"op": "replace", "path": ["profile"], "value": {"name": "Noa", "age": 6}}, {"op": "add", "path": ["tags", 3], "value": "kiddo"} ]I actually think its the perfect data tool for something like a block editor. I understand not wanting to add dependencies, but this one could be worth looking at and its only 4.2kB gzipped.
@lostpebble Could you provide an example of your implementation?
another possible approach is let editor.js-core maintains an undo/redo stack, once ctrl-Z action triggered, each plugin's renderIfChanged method will be called, just like React's shouldComponentUpdate, then the renderIfChanged method will re-execute the render method.
what you guys think? @gohabereg @eduardomart @lostpebble @bbbford @just99
@gohabereg @neSpecc Is there any progress regarding this issue?
Everyone waiting for this feature ^^
This lib is awesome. It would be super awesome if it has this feature :D
What is happening about this matter?
it seems https://editorjs.io/blocks#render can be used to do this ?
馃憢馃憢馃憢 We have developed a plugin that can address this feature. We hope this may help :).
https://github.com/kommitters/editorjs-undo
The code is already open and published to NPM ... everyone is welcome to contribute 馃帺.
I forgot to mention ... Redo is also supported ;)
馃憢馃憢馃憢 We have developed a plugin that can address this feature. We hope this may help :).
https://github.com/kommitters/editorjs-undo
The code is already open and published to NPM ... everyone is welcome to contribute 馃帺.
that's awesome!
but i wonder if the history-stack should only store the diff part between each save data ? otherwise the history-stack will be huge if the article is large.
plus the undo and redo seems lost the caret state ?
that's awesome!
but i wonder if the history-stack should only store the diff part between each save data ? otherwise the history-stack will be huge if the article is large.
plus the undo and redo seems lost the caret state ?
@mydearxym The main issue with that approach is that the render method the API provides receives the whole object. We cannot render a specific piece of the blocks.
About the last part, what do you mean with 'caret state'? It would be awesome if you create an issue explaining us the problem.
Thanks!
@nicolasgaviria Firstly, thanks for contributing your plugin! It's really cool and I think our organisation will start using it!
However, like @mydearxym suggested, I too think that the history stack should only store the diffs, probably using a command pattern!
The main issue with that approach is that the render method the API provides receives the whole object. We cannot render a specific piece of the blocks.
That's a fair point, but couldn't the plugin compute the whole set of blocks that need to be passed to the editor by replaying the commands according to the user's actions?
I might (please don't hold me accountable :upside_down_face: ) start a fork of either your undo plugin or the editor itself to try implementing it with a command pattern.
I'd argue that it'd be better to have this feature natively in the editor core because, especially to end users but to developers as well, the editor looks like one big <input /> tag, and I think it's like 'expected behavior' to have the Undo / Redo feature because the browsers do implement it on <input /> tags.
I think that the way @nicolasgaviria 's plugin implements it using a DOM MutationObserver is better than using a diffing library simply because of bundle size considerations.
Anyway, those are my two cents, I'll report back if I do end up forking, or creating something else!
Most helpful comment
Everyone waiting for this feature ^^