I want to add a undo/redo
function in my script. I have looked around and see some suggestions, most of them recommended to use command pattern
.
The function must work over one page - after a reload of the page the function must able to redo/undo
the last things.
I don't know how command pattern works, I think about to create a object, to store the a name of the function, the old and the new value - but I'm not sure if this is a efficient way to do this or not.
Maybe somebody could give me a small example how the code for a undo/redo
function should look.
If “UNDO” string is encountered, pop the top element from Undo stack and push it to Redo stack. If “REDO” string is encountered, pop the top element of Redo stack and push it into the Undo stack.
If there is no such a mark, it means you need to add it into your quick access toolbar. Click the rightmost arrow in the quick access toolbar, and choose the Undo item, then you will successfully add it into the quick access toolbar.
To redo something we have undone, we need to press the keyboard's shortcut key Ctrl + Y. Alternately. We can also press the F4 function key; however, we first need to press the Fn or F-Lock key to activate the function keys.
The undo function is used to reverse a mistake, such as deleting the wrong word in a sentence. The redo function restores any actions that were previously undone using an undo. Some people may refer to this feature as a reverse undo.
There's 2 common ways of implementing undo/redo:
Before an action is applied, you take a snapshot of the current state and save it into an array. That snapshot is the Memento.
If the user wants to undo, you simply pop
the last memento and apply it. The program returns to the state it was before the last action was applied.
This pattern is memory intensive; each memento is relatively large since it captures the whole current state.
But it's also the easiest to implement since you don't need to explicitly code all cases and their inverse actions that you need to in the Command Pattern (see below).
const mementos = []
const input = document.querySelector('input')
function saveMemento() {
mementos.push(input.value)
}
function undo() {
const lastMemento = mementos.pop()
input.value = lastMemento ? lastMemento : input.value
}
<h4> Type some characters and hit Undo </h4>
<input onkeydown="saveMemento()" value="Hello World"/>
<button onclick="undo()">Undo</button>
For each action the user takes, you also save a corresponding inverse action/command. For example, each time you add character in a textbox, you save the inverse function; which is to delete the character at that position.
If the user wants to undo, you pop the last inverse action/command and apply it.
const commands = []
const input = document.querySelector('input')
function saveCommand(e) {
commands.push({
// the action is also saved for implementing redo, which
// is not implemented in this example.
action: { type: 'add', key: e.key, index: input.selectionStart },
inverse: { type: 'remove', index: input.selectionStart }
})
}
function undo() {
let value = input.value.split('')
const lastCommand = commands.pop()
if (!lastCommand) return
switch (lastCommand.inverse.type) {
case 'remove':
value.splice(lastCommand.inverse.index, 1)
break;
}
input.value = value.join('')
}
<h4> Type some characters and hit Undo </h4>
<input onkeydown="saveCommand(event)" value="Hello World"/>
<button onclick="undo()">Undo</button>
The snippets I've written only work when adding characters, then hitting undo to return to the state before the characters were added so they are an oversimplification on how you should implement this.
Nevertheless I think they demonstrate the core concepts of both patterns.
FWIW I'm using UndoManager in my projects as a stack for my commands.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With