I need to be notified when an element with class 'nav' is created as the document is loading. Googling I found MutationObservers and thought they would be perfect, but I can't seem to get it working.
// ==UserScript==
// @name ii-shortcuts
// @namespace https://github.com/RedHatter
// @include *
// @version 1
// @run-at document-start
// ==/UserScript==
var observer = new MutationObserver(function(mutations)
{
mutations.forEach(function(mutation)
{
if (mutation.target.getAttribute('class') == 'nav')
GM_log('nav creation');
});
});
observer.observe(document, {subtree: true, attributes: true, attributeFilter: ['class']});
I also tried.
// ==UserScript==
// @name ii-shortcuts
// @namespace https://github.com/RedHatter
// @include *
// @version 1
// @run-at document-start
// ==/UserScript==
var observer = new MutationObserver(function(mutations)
{
mutations.forEach(function(mutation)
{
if (mutation.addedNodes[0].getAttribute('class') == 'nav')
GM_log('nav creation');
});
});
observer.observe(document, {subtree: true, childList: true});
But in nether case was 'nav creation' log on page load. What am I missing?
Tampermonkey is used to run so-called userscripts (sometimes also called Greasemonkey scripts) on websites. Userscripts are small computer programs that change the layout of a page, add or remove new functionality and content, or automate actions.
GreaseMonkey is a Firefox extension that lets you run arbitrary Javascript code against selected web pages. What this means is that GreaseMonkey lets you change how other people's web pages look and how they function (but just in your own browser, of course).
Tampermonkey has it's own built-in editor. Just hit the Tampermonkey button and select Dashboard. To get a new script, hit the little + tab in the upper right. You'll get a nice template with an IIFE (Immediately Invoked Function Expression) that you should put all your code in to avoid global namespace pollution.
Several issues (big to small):
When the document is first, statically loaded; the events are childList
events, not attributes
events.
For example,
$("body").append ('<p id="foo" class="bar">Hiya!</p><p>blah</p>');
generates one childList
event, while a subsequent
$("#foo").attr ("class", "bar2");
generates an attributes
event.
The odds that mutation.addedNodes[0]
contains an element with class nav
are practically zero. This is almost always a text node.
You need to check the whole array, PLUS the target
.
Don't use getAttribute('class') == 'nav'
to check for classes. This will throw exceptions for nodes without the getAttribute
function and it will miss elements that have more than one class. EG: <p class="foo nav bar">...
Use classList.contains()
on appropriate node types.
Use a @grant
directive if you use any GM_
functions like GM_log()
. Use a grant anyway, to ensure that the sandbox stays on.
Avoid the use of // @include *
. Especially with timers and observers, this can bog down your browser and your machine.
This info is for Firefox. Chrome has big differences in how it implements Mutation observers. This kind of code will not work in Chrome before page load.
Putting it all together, the script becomes:
// ==UserScript==
// @name _ii-shortcuts
// @namespace https://github.com/RedHatter
// @include http://YOUR_SERVER.COM/YOUR_PATH/*
// @run-at document-start
// @version 1
// @grant GM_log
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
introduced in GM 1.0. It restores the sandbox.
*/
var MutationObserver = window.MutationObserver;
var myObserver = new MutationObserver (mutationHandler);
var obsConfig = {
childList: true, attributes: true,
subtree: true, attributeFilter: ['class']
};
myObserver.observe (document, obsConfig);
function mutationHandler (mutationRecords) {
mutationRecords.forEach ( function (mutation) {
if ( mutation.type == "childList"
&& typeof mutation.addedNodes == "object"
&& mutation.addedNodes.length
) {
for (var J = 0, L = mutation.addedNodes.length; J < L; ++J) {
checkForCSS_Class (mutation.addedNodes[J], "nav");
}
}
else if (mutation.type == "attributes") {
checkForCSS_Class (mutation.target, "nav");
}
} );
}
function checkForCSS_Class (node, className) {
//-- Only process element nodes
if (node.nodeType === 1) {
if (node.classList.contains (className) ) {
console.log (
'New node with class "' + className + '" = ', node
);
// YOUR CODE HERE
//GM_log ('nav creation');
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With