Categories
Uncategorized

Greasemonkey Hacks

I’ve just gotten a copy of Greasemonkey Hacks and I’m working my way through it. The book itself is great. It’s a really good introduction to greasemonkey and what you can do with it. Eventually, I’m hoping to may my bank usable in firefox.

The only quibble that I have is the code samples. Many of them (and they appears to be the ones written by Mark Pilgrim, the author) are really difficult to read, because they idioms are wrong. For example, nearly every for loop I have seen looks like this:

  for (var i = arTableRows.length - 1; i > = 0; i--) {
    ...
  }

Which is walking through the rows of a table, backwards. Why backwards? I have no idea. I would expect it to look more like this:

  for (var i = 0; i < arTableRows.length; i++) {
    ...
  }

Aside from a marginal efficiency gain (which smacks of micro-optimisation), I don’t see what the benefit is.

And “arTableRows” is another quibble with the code. It’s filled with hungarian notation. Great if you work at Microsoft, but unreadable to the rest of the world.

Categories
Uncategorized

Subclassing with Prototype

I really like Ajax.InPlaceEditor from script.aculo.us. But it doesn’t quite do what I need. Nonetheless, bending it to my will ought to be fairly simple if I can just override a method or two.

This involved getting very familiar with Prototype’s Class.create and Object.extend.

After spending a while looking at the source for those two, my big book of JavaScript, and google, I was still flummoxed. Until I scrolled down a bit in controls.js (where Ajax.InPlaceEditor) lives. I saw this example of inheritance:

  Ajax.InPlaceCollectionEditor = Class.create();
  Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
  Object.extend(Ajax.InPlaceCollectionEditor.prototype, { ... });

That is:

  1. Create a new class (or constructor function to be accurate).
  2. Copy all the template functions from the source class into the destination class.
  3. Start adding our own functions into the class.

This is a good start! But there’s a tricky problem that I need to overcome: I wanted to override the constructor and run some code after the base class constructor. There’s no easy way to do this, because there is no link between the new class and the inherited one after you have called Object.extend(). So, you just have to be very explicit about exactly what you want to do. This is what I ended up with:

  var MyInPlaceEditor = Class.create();
  Object.extend(MyInPlaceEditor.prototype, Ajax.InPlaceEditor.prototype)
  Object.extend(MyInPlaceEditor.prototype, {
      initialize: function(element, url, options) {
          Ajax.InPlaceEditor.prototype.initialize.apply(this, arguments);
          // Don't respond to events on the main element of interest.
          // Only listen to events on the externalControl.
          Event.stopObserving(this.element, 'click', this.onclickListener);
          Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
          Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
      }
  });

It’s that line at the start of initialize() that’s the interesting one. It grabs the initialize() from Ajax.InPlaceEditor, and then uses apply() to call it using the new MyInPlaceEditor object as this. So it gets treated like it’s part of MyInPlaceEditor, even though it’s really defined in Ajax.InPlaceEditor.

So now I’m in a position to start overriding the other bits that I care about.