Google Wave: one ? transition at a time

Like Naaman, I was excited to hear about Google Wave. I signed up for the Sandbox access to hack on it. I signed up for ‘Wave Preview‘ to see a more stable version. Finally, once things ironed out, I decided to start building widgets.

Having worked on synchronous web interactions for sometime, I was happy to find the overall API to be pretty clean. The overall idea is simple. When you make a gadget that does something, have it submit that event as a change in state (they call it a delta). Quite simply, if you click a button and that button increments a shared counter. The OnClick handler for that button should call something like:

wave.getState().submitDelta({'count': value + 1});

Then you implement a function, lets call it onStateChange() which will check for the value of count and set the counter accordingly. Each delta makes a playback step, which in their own API words:

Work(s) harmoniously with the Wave playback mechanism

So, if somebody wants to playback the wave, they start at time 0 and drag the slider to time 20. The onStateChange handler will fire, and the counter will be set to whatever the value was at that point. Something like:

div.innerHTML = "The count is " + wave.getState().get('count');

Pretty neat right? Well not exactly. This works for a simple example. However, if your gadget does something more complex (such as load and unload flash objects), this will cause you some trouble if you aren’t careful. Lets take this example:

  1. I start a wave and add my gadget
  2. The gadget loads some flash
  3. I interact with the flash object
  4. The gadget loads a new piece of flash (overwriting the previous)
  5. I interact with the new flash object

If I play back this wave and jump from step 1 to step 3, I have to perform step 2 and then step 3. Some what similarly, if I jump from step 1 to step 5, I have to perform step 4 and then step 5. This is because if we just jump to step 5, there is no flash object loaded to interact with; the wave will be in an undefined state (and will make the JavaScript from step 5 quite unhappy as it references a null object).

The solution here is to make sure your wave.getState() object has all the information it needs to optimally reconstruct any arbitrary state. So, from our past example I’ll list the state as {key:value, ...} pairs:

  1. {}I start a wave and add my gadget
  2. {load: object1}The gadget loads some flash
  3. {load: object1, action: action1}I interact with the flash object
  4. {load: object2, action: null}The gadget loads a new piece of flash (overwriting the previous)
  5. {load: object2, action: action2}I interact with the new flash object

Each step now clearly contains everything it needs to rebuild the world, without running through all of history again. Also notice step 4 clears out any action that is not applicable to the newly loaded object. This will add some considerable code to your stateUpdated() function (especially since Flash loads asynchronously, you’ll have to wait for a series of callbacks to properly restore the state) but then you’ll get harmonious playback.

If you want to do something fancy like maintain a stack or a more so Turing-complete series of tapes, you’ll have to talk to @hackerjack60 if you can.

Leave a Reply

Your email address will not be published. Required fields are marked *