Keeping up with change

Greasemonkey is a great tool for changing a web page, just after it has been loaded. But this does not work for all those Ajaxified web 2.0 pages, where content is loaded on the fly.

There is a solution, though: just listen for DOM events which modify the page’s content. Keep up with the DOM changes so to say!

Background

In the days before Flickr was acquired by Yahoo, I made a Greasemonkey user script: Flickr – Link Original Image that inserts direct links to the original uploaded photos on top of thumbnails. This worked fine, by parsing the DOM just after page load and looking for every occurrence of photo thumbnails.

Now, after the recent relaunch of Flickr with dynamic Ajax loading, this script fails for those dynamically inserted thumbnails. Simply because they do not exist in the DOM when the page completes loading.

Solution

DOM level 2 specifies a couple of Mutation events. Now I register an event handler for the relevant events and take action whenever an image gets inserted, removed or moved around.

Code example

// Ajax: new image
document.addEventListener("DOMNodeInserted",
	function(evt) {
		ImgLinks.insertLinks(evt.target);
	}, true);
// Ajax: remove an image
document.addEventListener("DOMNodeRemoved",
	function(evt) {
		var list = evt.target.getElementsByTagName("img");
		for (var i = 0; i < list.length; i++) {
			ImgLinks.remove(list[i]);
		}	
	}, true);
// DOM manipulation, which can cause reflow
document.addEventListener("DOMAttrModified",
	function(evt) {
		ImgLinks.reshuffleSoon();
	}, true);
// catch window resize events
window.addEventListener("resize",
	function() { ImgLinks.reshuffle(); }, true);

In order to watch an Ajax page, you just have to keep up with the change, and go with the flow!