Capturing and Bubbling
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.)