javascriptundo-redomemento

Memento in Javascript


I'm looking for a JavaScript implementation of the memento pattern (GoF) to be used in CRUD forms. In its basic level it will be enough to undo changes on inputs, but it would be great to use it with standard JS frameworks like YUI or Ext, to undo & redo grid actions ( new row, delete row etc.).

Thanks


Solution

  • Since I'm not seeing any code examples, here is a quick 'n Dirty implementation of undo for an EXT form:

    var FormChangeHistory = function(){
        this.commands = [];
        this.index=-1;
    }
    
    FormChangeHistory.prototype.add = function(field, newValue, oldValue){
        //remove after current 
        if (this.index > -1 ) {
            this.commands = this.commands.slice(0,this.index+1)
        } else {
            this.commands = []
        }
        //add the new command
        this.commands.push({
            field:field,
            before:oldValue,
            after:newValue
        })
        ++this.index
    }
    
    FormChangeHistory.prototype.undo = function(){
        if (this.index == -1) return;
        var c = this.commands[this.index];
        c.field.setValue(c.before);
        --this.index
    }
    
    FormChangeHistory.prototype.redo = function(){
        if (this.index +1 == this.commands.length) return;
        ++this.index
        var c = this.commands[this.index];
        c.field.setValue(c.after);
    }
    
    Ext.onReady(function(){
        new Ext.Viewport({
            layout:"fit",
            items:[{    
                xtype:"form",
                id:"test_form",
                frame:true,
                changeHistory:new FormChangeHistory("test_form"),
                defaults:{
                    listeners:{
                        change:function( field, newValue, oldValue){
                            var form = Ext.getCmp("test_form")
                            form.changeHistory.add(field, newValue, oldValue)
                        }   
                    }
                },
                items:[{
                    fieldLabel:"type some stuff",
                    xtype:"textfield"
                },{
                    fieldLabel:"then click in here",
                    xtype:"textfield"
                }],
                buttons:[{
                    text:"Undo",
                    handler:function(){
                        var form = Ext.getCmp("test_form")
                        form.changeHistory.undo();
                    }
                },{
                    text:"Redo",
                    handler:function(){
                        var form = Ext.getCmp("test_form")
                        form.changeHistory.redo();
                    }
                }]
            }]
        })
    });
    

    Implementing this for an editable grid is a little trickier, but you should be able to make a GridChangeHistory that does the same thing and then call the add() function from EditorGrid's AfterEdit listener.

    The "before" and "after" properties could be callback functions which allow you undo/redo any kind of command, but that would require more work when calling add()