Adding Awareness and Undo/Redo Support to the Realtime House of Quality App

After releasing the House of Quality App on my institute’s homepage and using it in a project with colleagues, I received feedback on what to improve. As the House of Quality we were building together had more than 40 customer attributes and over 20 engineering characteristics, it was very hard to navigate around all the cells while remembering which requirement we were working on currently. Hence the first improvements were some mouseover effects to mark the current row and column headers.

In the first version of my app, it was also very hard to follow collaborator’s changes; therefore one suggestion was to add some sort of visual hints on where exactly something was changed remotely. In the context of shared editing systems, this is called awareness. Thankfully the Google Drive Realtime API comes with some handy features that allow us to easily add awareness features: In the update event, the userId of the collaborator responsible for these edits is included. Through the Realtime API’s document object (not to be confused with the DOM document!) we can call getCollaborators() to get an array of collaborators. Now, the great part is that every user object has a predefined color that can be used to highlight the change in the DOM. In my case, I use the color for a simple highlighting effect included in jQuery UI: effect("highlight", {color: color}, 2000);.

In the following figure, you can see the highlights for the current cell (orange) and a freshly arrived change by a remote collaborator (green):

Awareness in the House of Quality App

To add awareness about current collaborators, I also added a small hideable box on the top-right of the screen to show a list of users having this document open together with their Google profile pic and awareness color.

While answering to user requests, I noticed Google updated the Realtime API. It now has Undo/Redo support for local operations. To use it, I first added undo/redo buttons to the top-left corner of my window. You can now simple add an event listener to the Realtime model to receive events when undo/redo becomes available or not: model.addEventListener(gapi.drive.realtime.EventType.UNDO_REDO_STATE_CHANGED, HouseOfQuality._onUndoRedoStateChanged);. The implementation of the listener is listed below:

HouseOfQuality._onUndoRedoStateChanged = function(e) {
    $("#btn_undo").button({
        disabled: !e.canUndo
    });

    $("#btn_redo").button({
        disabled: !e.canRedo
    });
};

Now, to undo, I linked the undo button to this simple piece of code:

if (HouseOfQuality.model.canUndo) {
HouseOfQuality.model.undo();
}

It’s as easy as that! Though – in the end it wasn’t as easy as shown here. Previously, if a user edited a cell, I immediately changed the respective DOM element before the model was changed and therefore a model changed event was fired. In the change listener, I called the isLocal() method to check whether the changes were already performed on the DOM or not. For undo/redo I had to replace this kind of immediate response to user actions with the model change/event loop. However, the (local) delay can neither be measured nor perceived.

Another issue I had was with multiple undo/redo operations upon a single „user-level“ edit. For example, when I added a new user requirement row, I created the custom object, populated it with some default data and then added it to the document model. For every operation, this entailed several undo operations. To fix this, I had to use a custom object initializer which already removed the number of undo operations. Another fine detail in Google’s Realtime API is that already for creating a custom object, an undo operation is injected. To avoid this behaviour, I simply combined creating the custom object as well as adding it to the app’s data model in a compound operation:

// begin compound operation, otherwise this results in two undo/redo operations
HouseOfQuality.model.beginCompoundOperation();
var product = HouseOfQuality.createProduct(uuid, "Product");
HouseOfQuality._products.push(product);
HouseOfQuality.model.endCompoundOperation();

Finally, I added the House of Quality App to the Chrome Web Store. Feel free to try it out. :)

Still, one interesting question is left: How would one develop an app like Google Docs or Sheets with the Realtime API? For any hints, write me. :)

Kommentare sind deaktiviert.