I'm working on a Chrome extension that affects (among other things) GIF images on a page. I'm struggling to get it working for new images added dynamically after the initial page load. Here's what I've added to my content script in an attempt to handle this stuff:
function processGif(newTag) {
console.log(newTag.src);
}
var observer = new MutationObserver(function(mutations, obs) {
for(var i=0; i<mutations.length; ++i) {
for(var j=0; j<mutations[i].addedNodes.length; ++j) {
var newTag = mutations[i].addedNodes[j];
if(newTag.tagName == "IMG" && /.gif$/i.test(newTag.src)) {
processGif(newTag);
}
}
}
});
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
For testing purposes, I've reduced the processGif
function to nothing more than a console.log
of the tag's src
attribute.
Most of the time it works great and successfully catches all the initial images created as the DOM is initially built when the page is first loaded. But on pages like Google+, the MutationObserver doesn't seem to catch any of the dynamically loaded posts as you scroll down. I've been using Koushik Dutta's public page for testing purposes—the guy loves posting gifs. If you try to paste the above code into the console and scroll down, you should be able to confirm that none of the dynamically loaded images are being detected.
Why can't I see these dynamically added img
tags, and what do I need to do to handle images added dynamically like this?
I think I worked out what's happening. The addedNodes
list you get through the observer is not actually a list of each and every node that has been added to the DOM, but only the topmost one when several are added at once.
Taking this into account, you just have to process each added node and all its children as well. So the observer callback needs to be modified to look something like the following.
observer = new MutationObserver(function(mutations, obs) {
for(var i=0; i<mutations.length; ++i) {
for(var j=0; j<mutations[i].addedNodes.length; ++j) {
var newTag = mutations[i].addedNodes[j];
if (newTag.querySelectorAll) {
Array.prototype.forEach.call(
newTag.querySelectorAll('img[src*=".gif"]'),
processGif);
}
}
}
});