I have the following userscript I run on Greasemonkey/Tampermonkey.
I run it on facebook
which serves some of the webpages from backend, in bootstrapping, and some others on the fly, in front-end, via HRO, just as a Single Page Application (SPA) would.
// ==UserScript==
// @name facebook
// @namespace nms
// @include http://*.facebook/*
// @include https://*.facebook/*
// @version 1
// @grant none
// ==/UserScript==
setTimeout( () => {
// generalStuff:
document.querySelectorAll(' #left_nav_section_nodes, .fbChatSidebar ').forEach( (e)=> {
e.style.visibility = "hidden";
});
}, 1000);
If I run this script on console, even in HRO based webpages, it runs fine, but when runned from Greasemoneky/Tampermonkey it won't run in these particular webpages.
How could I make the script to work without problem on SPA-like webpages as well?
I have the following userscript I run on Greasemonkey/Tampermonkey.
I run it on facebook.
which serves some of the webpages from backend, in bootstrapping, and some others on the fly, in front-end, via HRO, just as a Single Page Application (SPA) would.
// ==UserScript==
// @name facebook
// @namespace nms
// @include http://*.facebook./*
// @include https://*.facebook./*
// @version 1
// @grant none
// ==/UserScript==
setTimeout( () => {
// generalStuff:
document.querySelectorAll(' #left_nav_section_nodes, .fbChatSidebar ').forEach( (e)=> {
e.style.visibility = "hidden";
});
}, 1000);
If I run this script on console, even in HRO based webpages, it runs fine, but when runned from Greasemoneky/Tampermonkey it won't run in these particular webpages.
How could I make the script to work without problem on SPA-like webpages as well?
Share Improve this question asked Aug 1, 2017 at 0:09 sangokosangoko 3511 silver badge13 bronze badges4 Answers
Reset to default 6In such a case when setTimeout
, setInterval
, and event delegation doesn't work by themselves, it is possible to push a state that implements them into the memory, then replacing the existing state with it, so that the webpage's DOM content will change.
Here's a code used to replace data that was loaded with AJAX instead directly from PHP:
let utilityFunc = ()=> {
var run = (url)=> {
// insert your code here
};
var pS = window.history.pushState;
var rS = window.history.replaceState;
window.history.pushState = function(a, b, url) {
run(url);
pS.apply(this, arguments);
};
window.history.replaceState = function(a, b, url) {
run(url);
rS.apply(this, arguments);
};
utilityFunc();
That's what I understood from reading here.
From reading this documentation, this code would work for SPA changing the location:
// ==UserScript==
...
// @match https://subdomain.domain.tld/*
// @match http://subdomain.domain.tld/*
// @grant window.onurlchange
// ==/UserScript==
(function() {
'use strict';
if (window.onurlchange === null) {
window.addEventListener('urlchange', (info) => {
if (Object.values(info)[0].includes("/path/to/certainlocation")) {
// your code here
}
});
}
})();
Note this would not work if you visit the certain location directly, but that could easily be fixed, or you could create another userscript that only matches that certain location, eg:
// @match https://subdomain.domain.tld/path/to/certainlocation
// @match http://subdomain.domain.tld/path/to/certainlocation
For a similar use case, I used MutationObserver and checked node.baseURI
of each node in each mutation.addedNodes
.
(async function() {
'use strict';
const selector = '.quiz--answered';
const observer = new MutationObserver(mutations => {
if (!mutations.some(mutation => Array.from(mutation.addedNodes).some(node => node.baseURI.includes('/quiz/')))) {
return;
}
const elm = document.querySelector(selector);
if (elm) {
// work with elm
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
})();
I have stumbled upon this problem several times myself, I ended up writing a simple lib to deal with this. It allows me to run the script on URL changes, define the URLs with wildcards and wait for specific element if I want to. It's called spa-runner.
import { run } from "@banjoanton/spa-runner";
const handler = () => {
console.log("hello world!");
}
const config = {
urls: ["http://*.facebook./*"],
runAtStart: true,
};
const unsubscribe = run(handler, config);