Exploring Firefox Event Objects without Debugging

For such a powerful tool, Firefox/Mozilla's event objects aren't very well documented. I still haven't found one definitive, concise source of all the docs I need. Mozilla is so huge, "definitive and concise" is most likely a contradiction in terms. So when I need to get to the bottom of how something like this works, given a choice between consulting half a dozen animal books, googling, lxr'ing the source, or exploring a live object, I often opt for that last choice.

You can install Firebug or Komodo's JavaScript debugger, set a breakpoint on a handler, hit it, and then explore the event object, but when you have a set of different kinds of widgets and events you need to understand, this can get to be too time-consuming.

Here's a quick method that uses Ted Mielczarek's Extension Developer Extension, available at http://ted.mielczarek.org/code/mozilla/extensiondev/.

I'll use the HTML sample file we ship with Komodo's sample project.

It currently calls a function called "livehack" in this handler:

<input type="text" id="name" value="Komodo Rules!" onkeyup="livehack();"/>

I changed "livehack()" to "livehack(event)", so the function gets the built-in event object.

Around line 73, I changed the start of this function:

function livehack() {
    /* un-comment the code below to update the page as you type
      to un-comment a block in Komodo, select the block and hit Ctrl+SHIFT+3
    */
    ...

to this:

var gLiveHackEvent = null;
function livehack(event) {
    gLiveHackEvent = event; // save the event in that global

Save the file, reload it in Firefox, and press a key in the input field.

Now bring up the Extension Developer extension, select the JavaScript shell, and bring up the appropriate tab by clicking on "enumerateWindows()", and then clicking on the URL that corresponds to the HTML file you're working on. In my case that was "file:///C:/Users/ericp/AppData/Roaming/ActiveState/KomodoIDE/4.13/samples/html_sample.html". (Yes, I'm running this on Vista. So it should work anywhere). The purpose of the change is to save the temporary event object in a global, so I can explore it at a more convenient time. Which for humans is usually long after the event handler has done its work and expired.

The JavaScript shell is a bit of a bare-bones environment -- it doesn't have a visible prompt, and doesn't handle multi-line input very well. But it does do tab completion. So you can now explore your event object like so:

> 

gLiveHackEvent

[object KeyboardEvent]

> 

gLiveHackEvent.<tab>190 matches. Press tab again to see them all

> 

props(gLiveHackEvent)

Methods of prototype: initKeyEvent
Fields of prototype: DOM_VK_0, DOM_VK_1, ...
Methods of prototype of prototype of prototype: getPreventDefault, initUIEvent
Fields of prototype of prototype of prototype: SCROLL_PAGE_DOWN, ...
Methods of prototype of prototype of prototype of prototype: initEvent, 
             preventBubble, preventCapture, preventDefault, stopPropagation
Fields of prototype of prototype of prototype of prototype: ABORT, ALT_MASK, ...

> 

gLiveHackEvent.charCode

0

> 

gLiveHackEvent.keyCode

32

> 

gLiveHackEvent.currentTarget

null

> 

gLiveHackEvent.originalTarget

[object HTMLInputElement]

> 

gLiveHackEvent.originalTarget.id

name

But wait, there's more! gLiveHackEvent is a live variable. Press other keys in that field, and the event object's keyCode will reflect the new values.

The same technique works with event handlers for mouse events as well, of course. I used it in Komodo today to quickly discover that when you process onclick and onkeypress events over a XUL tree widget, the tree's treechildren element processes the mouse click, but the parent tree element processes the key presses.