Capturing and Bubbling

From GreaseSpot Wiki
Jump to: navigation, search

In Javascript, events bubble up and down the DOM heirarchy. In other words, every event (like a click, mouseover, etc.) is "visible" both on the directly related element, and all of its parents.

The practical upshot of this is that you can act on events all throughout the document with a single listener.

Catch Bubbling Events

By attaching an event listener to the document (or any other element), one can monitor all events that happen on all child and descendant nodes. Or, by doing:

document.addEventListener('click', clickHandler, true);

Then the clickHandler function will be called for every click on every element in the document, so:

function clickHandler(event) {
  GM_log("User clicked on element: " + event.target);
}

Will print a message to the log for every click in the document.

Note: The third parameter to addEventListener can be a bit mysterious. It is a result of the conflicting event propagation models initially used in early versions of Netscape and Internet Explorer. Authors should read the "Event Order" article linked in the see also section for a detailed explanation of its meaning and implications.

Monitoring Document Changes

This technique works for all Javascript event types, notably including the "DOM Mutation" events. As the name implies, these events are concerned with the DOM mutating, or changing. They are thus a powerful technique for monitoring pages that change (i.e. as a result of an AJAX call), and re-applying the script's enhancement to the new content in the page. So, for example:

document.addEventListener("DOMNodeInserted", nodeInsertedHandler, false);

function nodeInsertedHandler(event) {
  GM_log("element with id " + event.target.id + " has been added");
}

This script will be able to keep track of all the new nodes being inserted into the document. See the AutoLink script for a detailed example of this technique applied in a real script. Of special importance is the fact that this script is careful to not process its own modifications to the DOM, which would otherwise cause an infinite recursion. (Look for the nodeInserted function.)

See Also