When working with events in Javascript, it is often easy to lose track of what events are subscribed where. This is particularly true if you are using a large number of events, which is typical in a modern interface employing progressive enhancement. Javascript libraries also add another degree of complexity to listeners from a technical point of view, while from a developers point of view they of course can make life much easier! But when things go wrong it can be difficult to trace down why this might be.
It is due to this I've put together a Javascript bookmarklet called Visual Event which visually shows the elements on a page that have events subscribed to them, what those events are and the function that the event would run when triggered. This is primarily intended to assist debugging, but it can also be very interesting and informative to see the subscribed events on other pages.
Using Visual Event on any web-page is extremely simple:
You can see a demo of this in action showing the events attached by my own DataTables jQuery plugin.
Visual Event is currently beta level software and as such there are a few important notes to make. This first of these is that Visual Event will not currently work in Internet Explorer. IE has it's own events model and I've concentrated initially on the W3C model. The second point is that only events added by libraries which Visual Event recognises will actually be shown (see later for why). The currently supported libraries are:
When using Visual Event you will notice that I've used colour coding and icons to represent different actions in a concise and easy to view manner. The background colours which show that an element has an event attached to it follow the mapping shown below.
Colour | Meaning |
---|---|
Blue | Mouse event |
Red | UI event (keys etc) |
Yellow | HTML event (select etc) |
Purple | Mouse + UI events |
Orange | UI + HTML events |
Green | Mouse + HTML events |
Black | Mouse + UI + HTML events |
The icons representing individual events also follow this colouring pattern, but also indicate what the attached event is pictorially. The follows the mapping shown below.
Icon | Event |
---|---|
click | |
dblclick | |
mousedown | |
mousemove | |
mouseout | |
mouseover | |
mouseup | |
change | |
focus | |
blur | |
select | |
submit | |
keydown | |
keypress | |
keyup | |
load | |
unload | |
custom / unknown |
It turns out that there is no standard method provided by the W3C recommended DOM interface to find out what event listeners are attached to a particular node. While this may appear to be an oversight, there was a proposal to include a property called 'eventListenerList' (reference) to the level 3 DOM specification, but this has unfortunately been removed in the latest drafts. As such we are forced to looked at the individual Javascript libraries, which typically maintain a cache of attached events (so they can later be removed and perform other useful abstractions).
In the current version of Visual Event I have included support for jQuery, YUI, MooTools, Prototype (many thanks to John Schulz for his advice in adding Prototype support) and JAK (with thanks to Michal Aichiner for providing an API function). I've investigated including information Dojo, however this library does not appear not to cache the information that is required by visual event. If anyone does know of a way - please get in touch!
I would strongly encourage developers who use some of the other libraries to get in touch with me, and submit a function which can be used by Visual Event to parse a specific library's cache. The following structure must be returned by the function:
// Return code from event cache parsing function [ { // Node which is in question "nNode": -, // The name of the library where the event comes from (e.g. 'YUI') "sSource": '', // Array of the listeners attached to this node "aListeners": [ { // Type of event (e.g. 'click') "sType": '', // String of the function to run (from Function.toString()) "sFunction": '', // Indicate if the event has been removed by the library - typically false "bRemoved": '' }, ... ] }, ... ]
Alternatively, you can make use of a global variable which Visual Event will recognise. This global variable is called VisualEvents which you can populate using either the structure given above, or the slightly simpler version below (ideal for putting into an event registration function) - or any combination of the two:
[ { // Node which is in question "nNode": -, // The name of the library where the event comes from (e.g. 'YUI') "sSource": '', // Type of event (e.g. 'click') "sType": '', // String of the function to run (from Function.toString()) "sFunction": '', // Indicate if the event has been removed by the library - typically false "bRemoved": '' }, ... ]
There is quite a lot which could be done with Visual Event in order to improve it and make it more useful for developers. The following is my current list (and in no particular order!):
IIf you have any other ideas, or if you are interested in helping me develop Visual Event further, please don't hesitate to get in touch!