widgets

January 17th, 2007

I’m a big fan of constructing self-contained ‘widgets’ rather than trying to preserve some semblence of state through a series of unconnected event handlers on different elements. For example, I recently needed to make a lightbox-esque ‘popup’ to show more information about a manufacturer for an ecommerce site.

One approach to doing this, and one I’ve used in similar situations in the past, would be to have something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script type="text/javascript">
function openInfoWindow(link) {
  var div_id = link.id.replace('link_','info_');
  $(div_id).show();
}
function closeInfoWindow(button) {
  var div_id = $(button).up('div').hide();
}
</script>
...
<a href="/manufactures/info/calvin_klein"
   onclick="openInfoWindow(this);" id="link_calvin_klein">
More Info</a>
<div style="display:none;" id="info_calvin_klein">
<input type="button" onclick="closeInfoWindow(this);" value="X" />
<!--etc.-->
</div>

This should be perfectly functional, but it’s clunky. Having the html onclick attributes is the first problem, one I solve using behaviour.js and prototype’s Event functions; for example, adding a class of ‘info_link’ to all the open links allows you to have:

1
2
3
4
5
6
7
8
var my_rules = {
  'a.info_link': function(link) {
    $(link).observe('click',function() {
      this.next('div').show();
    },false);
  }
}
Behaviour.register(my_rules);

But it’s still a bit too dispersed for my liking. What I ended up doing is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var myrules = {
  'a.info_link': function(link) {
    var widget = new InfoWindow(link,link.next('div'));
  }
}
var InfoWindow = Class.create();
InfoWindow.prototype = {
  initialize: function(opener,container) {
    this.container = $(container);

    this.opener.onclick = this.openWindow.bind(this);

    this.container.down('input').onclick = this.closeWindow.bind(this);
  },
  openWindow: function() {
    this.container.show();
  },
  closeWindow: function() {
    this.container.close();
  }
}

Now, this is more code but it’s all in one place and it’s still pretty simple and when, in a large application, you find yourself doing lots of similar things, every bit of clarity helps.

Leave a Reply