Command

Command is an implementation of the command pattern, in which objects are used to represent actions. A command object typically has an execute() method that runs its action, and sometimes will have an undo() method if it can be reversed.

// In the browser
JS.require('JS.Command', function(Command) { ... });

// In CommonJS
var Command = require('jsclass/src/command').Command;

Creating commands

Here’s your basic ‘Hello world’ command:

var helloWorld = new Command({
    execute: function() {
        alert('Hello world!');
    }
});

helloWorld.execute()
// -> alerts "Hello world!"

If your action can be reversed and you want to implement an ‘undo’ function in your code, you need to tell the command how to reverse itself:

var incrementCounter = new Command({
    execute: function() {
        someCounter += 1;
    },
    undo: function() {
        someCounter -= 1;
    }
});

var someCounter = 0;
incrementCounter.execute();
incrementCounter.execute();
incrementCounter.undo();

// someCounter is now == 1

Creating your own command classes

You’ll often want to subclass Command to provide your own types of command. For example, you might want to create a type of command that drew a circle at random on a canvas element:

var DrawCircleCommand = new Class(Command, {
    initialize: function(ctx) {

        var x = Math.random() * 400,
            y = Math.random() * 300,
            r = Math.random() * 50;

        this.callSuper({
            execute: function() {
                ctx.fillStyle = 'rgb(255,0,0)';
                ctx.beginPath();
                ctx.arc(x, y, r, 0, 2*Math.PI, true);
                ctx.fill();
            }
        });
    }
});

var ctx = myCanvas.getContext('2d');
var randomCircle = new DrawCircleCommand(ctx);

randomCircle.execute();

Note the general pattern here: we create a subclass of Command. This new subclass accepts a drawing context to instantiate it (ctx), chooses some random drawing points, then uses this.callSuper to pass some command properties up to the Command initialize() method. Note that the random numbers are generated once, rather than every time the command is executed: each new DrawCircleCommand does something different, but an individual DrawCircleCommand instance ought to do the same thing every time it is executed.

Important: do not overwrite the execute() or undo() methods in a Command sublcass. They contain hooks for talking to command stacks and must not be modified. Always use callSuper() as shown above to set up your commands. Do not do this:

var BrokenCommand = new Class(Command, {
    execute: function() {
        doSomething();
    },
    undo: function() {
        undoSomething();
    }
});

This command will not work properly if you try to hook it up to a command stack as described below.

Command.Stack

If you have actions that can be undone and you want to store the command history so you can step back and forth through it later, we have a class called Command.Stack. To use it, just create one and give it a name:

var counterStack = new Command.Stack();

You can then create commands that will automatically add themselves to this stack whenever they are executed, using the stack option:

var incrementCounter = new Command({
    execute: function() {
        someCounter += 1;
    },
    undo: function() {
        someCounter -= 1;
    },
    stack: counterStack
});

Now, whenever incrementCounter is executed, it gets added to the stack counterStack. You can use the stack’s undo() and redo() methods to step back and forth through the command history:

var someCounter = 0;

incrementCounter.execute();   // someCounter == 1
incrementCounter.execute();   // someCounter == 2
incrementCounter.execute();   // someCounter == 3

counterStack.undo();          // someCounter == 2
counterStack.redo();          // someCounter == 3
counterStack.undo();          // someCounter == 2
counterStack.undo();          // someCounter == 1

Of course, this is more useful when you have lots of different types of commands that can all be undone, and you want to provide a means of stepping through the command stack.

Command stacks have a couple of other methods you ough to be aware of:

stepTo() lets you revert to any point in the stack’s command history by number. stepTo(0) undoes the whole stack, and commands are numbered sequentially from 1 upwards.

push() lets you push a command onto the stack yourself—this is the method Command uses internally if you tell a command to associate itself with a stack. When you push a command onto the stack, it is added at whichever point in the stack you happen to be, and any previously undone commands after this point are discarded. For example:

someCounter = 0;
counterStack.clear();         // 0 commands in stack

incrementCounter.execute();   // 1 command
incrementCounter.execute();   // 2 commands
incrementCounter.execute();   // 3 commands
incrementCounter.execute();   // 4 commands
                              // someCounter == 4

counterStack.stepTo(2);       // still 4 commands in stack
                              // stack pointer is after 2nd command
                              // someCounter == 2

incrementCounter.execute();   // stack truncated
                              // contains 3 commands
                              // pointer at end of stack
                              // someCounter == 3

Redo from start

Some commands cannot easily be undone, but you’d still like to store them in a stack. One example is the circle-drawing command shown above: it’s hard to ‘unpaint’ a circle because you don’t know what filled its space before it was there. In some situations it’s easier to implement ‘undo’ by having a stack redo itself from the start up to a given point. If you pass a redo command when creating a stack, the stack will assume you want a redo-from-start stack and will automatically call your redo command to wipe the slate clean before running its history again.

As an example, here’s a program that allows you to draw random squares on a canvas. Hooking this up to a GUI is trivial with this code in place:

// Canvas information
var canvas = document.getElementById('canvas'),
    ctx    = canvas.getContext('2d'),
    W      = 400,
    H      = 300;

// Command for clearing the drawing area
var clearCanvas = new Command({
    execute: function() {
        ctx.fillStyle = 'rgb(255,255,255)';
        ctx.fillRect(0, 0, W, H);
    }
});

// A redo-from-start stack
var drawingStack = new Command.Stack({redo: clearCanvas});

// Command for drawing a random square
var DrawSquareCommand = new Class(Command, {
    initialize: function(ctx) {

        var x = Math.random() * W,
            y = Math.random() * H,
            r = Math.random() * 30;

        this.callSuper({
            execute: function() {
                ctx.fillStyle = 'rgb(0,0,255)';
                ctx.fillRect(x, y, r, r);
            },
            stack: drawingStack
        });

        this.name = 'Draw square at ' + x + ', ' + y;
    }
});

To undo a step, the drawing stack clears the canvas and then re-runs all its commands up to the required step. Notice how the drawing command includes the line stack: drawingStack to make sure it is remembered by the stack. To draw a square at random, you’d just do this:

new DrawSquareCommand(ctx).execute();

That could easily be hooked up to an interface button, as could a snippet of code for calling drawingStack.undo().

The advantage of coding the application like this is that you can add as many different types of drawing command as you like without complicating the mechanism for undoing them – you just get all your commands to notify a single command stack and use that stack to revert changes.

Notice how the command gives itself a name property inside its initialize() method – this will allow us to represent the command in the GUI in the next example.

length and pointer

All stacks have a length property that tells you how many commands they contain at any point in time. This property only changes when a new command is push()-ed onto the stack – an undo() or redo() does not change the stack length. What does change is the stack’s pointer – this number tells you what point in the stack the most recently executed command is. For example:

var stack = new Command.Stack();
var command = new Command({
    execute: function() { ... }
});

// stack.length == 0
// stack.pointer == 0

stack.push(command);
stack.push(command);
stack.push(command);

// stack.length == 3
// stack.pointer == 3

stack.undo();
stack.undo();

// stack.length == 3
// stack.pointer == 1

stack.push(command);

// stack gets truncated
// stack.length == 2
// stack.pointer == 2

They’re Observable and Enumerable

Command.Stack mixes in the Observable and Enumerable modules. This means you can implement a Photoshop-style action history with barely any code at all by observing the stack:

<ul id="drawHistory"></ul>

<script>
    drawingStack.subscribe(function(stack) {
        var list = document.getElementById('drawHistory'), str = '';
        stack.forEach(function(command, i) {
            var color = (i >= stack.pointer) ? '#999' : '#000';
            str += '<li style="color: ' + color + ';">' + command.name + '</li>';
        });
        list.innerHTML = str;
    });
</script>

This creates a list that updates itself in response to stack changes. Your subscribe callback is passed a reference to the stack whenever the stack executes a new command or undoes/redoes a command. Stacks have a pointer property that tells you what point in the stack the most recent command is. So you can work out whether each command has been undone or not, and assign a greyed-out color to commands after the current pointer position. Your forEach callback is passed each command in the stack in turn, along with its position in the stack (beginning at 0).