Archive for the ‘Uncategorized’ Category

Decoupling Data and UI: PubSub

Wednesday, November 26th, 2008

This is a summary of my presentation today at the sf javascript meetup #4 on maintainable front end architecture in javascript. The presentation involves a demo app and a progressive construction of the model’s subscribe method, which contains the meat of the functionality and interesting javascript.

Demo app:

Demo of the PubSub library - an email client

Decoupling Data and UI in webapps with PubSub patterns

As web applications become more powerful, they grow in complexity. Front end programming patterns and best practices are becoming more and more important both for the community and for the industry.

If you decouple your application’s data and UI layers, you will be able to easily extend and develop one layer without affecting the other. A powerful pattern that allows for such decoupling is publication/subscription.

It turns out that javascript’s combination of functional programming and the ability to apply a scope at runtime makes it a wonderful language to write a PubSub library in. 25 lines of code is enough to create a highly versitile model with both dynamic scoping and currying/partial application. We’ll go through that code together in a moment.

If you look at the application code (not more than some 70 lines), then you notice that the UI and the data layers are completely independent - i.e. they don’t reference each other. All the message passing between the data and the UI are taken care of with code like this:

pubSubBroker.subscribe('email-open', gData, 'onRead');
pubSubBroker.subscribe('email-open', gUI, 'markEmail', true);
var email = {title:'Test email', id:1, body:'Test body'};
//This will call both gData.onRead(email) and gUI.markEmail(true, email);
pubSubBroker.publish('email-arrive', email);

The pubSubBroker creation and publish are both pretty straight forward:

// Our publication and subscription broker
function PubSubBroker() {
  var signals = arguments;
  this.subscribers = {};
  for (var i=0; i < signals.length; i++) {
    this.subscribers[signals[i]] = [];
  }
}

PubSubBroker.prototype.publish = function(signal) {
  var args = Array.prototype.slice.call(arguments, 1)
  for (var i=0; i < this.subscribers[signal].length; i++) {
    var handler = this.subscribers[signal][i];
    handler.apply(this, args);
  }
}

However, the subscribe method is the fun part. Let’s go through its creation step by step in order to understand how we get to the final, slightly non-trivial 7-line implementation. First, we just want the ability to subscribe to signals with a function handler:

PubSubBroker.prototype.subscribe = function(signal, handler){
  this.subscribers[signal].push(handler);
}

Then we add the ability of specifying the scope in which the handler will run on when a signal is published. Use handlerName rather than handler directly, and use call to run the handler in the given scope.

PubSubBroker.prototype.subscribe = function(signal, scope, handlerName){
  this.subscribers[signal].push(function(eventArguments){
    scope[handlerName].call((scope || window), eventArguments);
  });
}

The third version adds the ability to pass in a variable number of arguments to publish. Using apply rather than call allows for this.

PubSubBroker.prototype.subscribe = function(signal, scope, handlerName){
  this.subscribers[signal].push(function(){
    scope[handlerName].apply((scope || window), arguments);
  });
}

Finally, we make currying possible, which allows for partial application that can be super useful in many cases (let me know if you want a useful example and I’ll add it):

PubSubBroker.prototype.subscribe = function(signal, scope, handlerName){
  var curryArray = Array.prototype.slice.call(arguments, 3);
  this.subscribers[signal].push(function(){
    var normalizedArgs = Array.prototype.slice.call(arguments, 0);
    scope[handlerName].apply((scope || window), curryArray.concat(normalizedArgs));
  });
}

That’s it! If you want to play with the code, just download the zipfile with the demo application and pubsub code or check out the demo - it has links to the application file, pubsub broker file, as well as the progressive build of subscribe.

Ajaxlights. 3D web, JS editor, Web-born UI paradigms

Wednesday, November 19th, 2008

Awesome 3D rendering engine for the canvas tag by Peter Nederlof. Very impressive. Here’s a short screencast of it in action - note that this is a *web page* with *no flash*.

3D canvas demo3D canvas demo

Maxime Haineault has created a new UI for picking time - I can totally see this as a new web-born UI practice much like the Lightbox.

EtherPad has made it possible to collaborate on writing JavaScript code in the browser!

EthaPad collaborative javascript editing

Lightweight Javascript Event Handling Library

Friday, July 25th, 2008

A super-lightweight Event Handling javascript library:

// Author: Marcus.Westin@gmail.com, July 25th

function EventBroadcaster(signals) {
  this.events = {};
  for (var i=0; i < signals.length; i++) {
    this.events[signals[i]] = [];
  }
}

EventBroadcaster.prototype.subscribe = function(signal, args){
  if (!this.events[signal]) { throw ('EventBroadcaster.prototype.subscribe: event name not recognized: ' + signal); }
  if (!args.handler) { throw ('EventBroadcaster.prototype.subscribe: no handler given.')}
  args = args || {};
  function makeArray(arg) {
    return arg ? (arg instanceof Array ? arg : [arg]) : [];
  }
  this.events[signal].push({
    handler : function(handlerArgs){
      args.handler.apply((args.scope || window), makeArray(args.curry).concat(makeArray(handlerArgs)));
    },
    once : args.once
  });
}

EventBroadcaster.prototype.once = function(signal, args) {
  args = args || {};
  args.once = true;
  this.subscribe(signal, args);
}

EventBroadcaster.prototype.broadcast = function(signal, broadcastArgs) {
  if (!this.events[signal]) { throw ('EventBroadcaster.prototype.broadcast: event name not recognized: ' + signal); }
  var subscriptions = this.events[signal];
  for (var i=0; i < subscriptions.length; i++) {
    subscriptions[i].handler && subscriptions[i].handler(broadcastArgs);
    subscriptions[i].once && delete subscriptions[i];
  }
}


A Demo is available of a 50-lines mockup Email client interface using the event library for : Event handling is a great pattern for a system with many complex components than need to interact in a loosely coupled manner. For example, in an email UI where the user clicks on an unread email, at least two things have to happen:

  • The central view changes to the content of the email
  • The inbox “unread” count decreases by one

Intuitively, the unread email link could “tell” the central view to change as well as “tell” the inbox count to decrease. However, what if you want to add a third functionality, e.g.

  • notify the server that the email has been read

An alternative intuition says that as the email link has to notify more and more components of what happened, rather than running around to each one of them it could just do a general “Email X was activated!” and each component that cares could then act accordingly. This is how an event management system with Subscribe and Publish (PubSub) works, and allows for among other things a stepwise development process of complex UI’s.

Ajaxlights: In-Browser Javascript Caching, Sounds, and Cross Domain Brawls

Tuesday, July 8th, 2008

Inventive front end developers keep finding ways to push the capabilities of the browser. A recent favorite of mine, quipt, allows you to dynamically load javascript files and automatically cache them - get this - in the window.name attribute.

Some websites abuse sound, but this does not take away the fact that sounds can be an extremely useful UI component that is certainly under-utilized on the web. If you have a good use case, then let SoundManager2 take care of the heavy tech-lifting.

Follow-up on last week’s mention of “TCP sockets” in the browser: HTML 5 WebSockets.

Ajaxian report and comment roll on Microsoft’s paper about cross domain request insecurities.

If you ever need to sanitize HTML for href="javascript: ... ", don’t do it by blacklisting javascript: ! The Javascript Protocol Fuzzer is a good reason why. Check it out.

Ever wished your favorite webapp could be native to your OS? Do you use OS X? You’re in luck - check out Fluid. Freakin’ awesome.

Not Ajax related, but totally cool: a visualization of the birth and growth of Python over time.

Jot.com - Blogging by Speaking!

Monday, June 23rd, 2008

I am currently writing this blog post from my cellphone - not by writing, but by speaking. This will be transcribed by Jott.com, and automatically posted on my WordPress blog at blog.narcvs.com. Very impressive. Incredible work done by Jott.com.

listen

Powered by Jott

Update: As I’m not yet used to blogging oraly, I’ve done some grammatical edits.

Hello World!

Monday, April 14th, 2008

The time has come to host my own blog

Migration from marcuswestinblog.blogspot.com will happen soon - my feedburner will be redirected right after.

At the same time I’ll start developing narcvs.com, with the first project being a research UI for the google search API.

See you all in the sphere.