Search code examples
javascriptgreasemonkeytampermonkeyuserscripts

How to make a Userscript redo all the actions in subsequent webpage navigations of the same URL?


I have a UserScript like the below:

document.querySelector('[title="Select: This option"]').checked = true
document.querySelector('[title="Click to continue"]').click()

After the 'click to continue', the browser moves to the next page but the URL stays the same. I want to make the UserScript perform again all its actions in all subsequent pages that of course match the @match URL. For now, this does not seem to happen but I am not sure if it is because the UserScript is not re-initiated or because the first line fails (i.e. to click "Select: This option").

How can I do that?

I suppose setting up a timer to loop would be an option but is there anything neater? If the problem is that the first line fails because the element is not present in the next page, is there a way to make the UserScript just skip to the next action?

For now, this does not seem to happen but I am not sure if it is because the UserScript is not re-initiated or because the first line fails (i.e. to click "Select: This option").


Solution

  • wOxxOm is right: MutationObserver is the correct, modern, way to implement this solution. However, it is a little tricky to implement.

    If you seek a quick 'n dirty "proof-of-concept" approach, you can try something like this:

    // ==UserScript==
    // @name         Check 'n Click
    // @namespace    http://myuniquens.com
    // @version      0.01
    // @match        https://urdomaingoeshere.com/*
    // @icon         https://www.google.com/s2/favicons?sz=64&domain=auvik.com
    // @grant        none
    // ==/UserScript==
    
    (async function() {
        'use strict';
        const $ = document.querySelector.bind(document);
    
        loop-n-watch();
    
        async function loop-n-watch(){
            log_me_console(); //Not required, just to provide some feedback
    
            if ( $('[title="Select: This option"]') ){
                if ( !$('[title="Select: This option"]').checked ){
                    $('[title="Select: This option"]').checked = true;
                    await sleep(500);
                    $('[title="Click to continue"]').click();
                }
            }
            setTimeout( () => { loop-n-watch() },1000);
        }
        function sleep(ms){
            return new Promise(function (resolve, reject) {
                setTimeout(()=>{
                    resolve();
                },ms);
            })
        }
        function log_me_console(){
            //This adds a console log each loop to reassure it is running
            console.logCopy = console.log.bind(console);
    
            console.log = function(data){
                var timestamp = `[ ${Date.now()} ] `;
                this.logCopy(timestamp, data);
            };
    
            console.log('log_me_console()')
        }
    })();
    
    

    The above script will loop forever, and every second it will check for that element and check the checkbox, wait half-a-second, and click the button.

    The call to log_me_console() just displays a console log with an updating timestamp to reassure you that it is running.

    This code will work on a standard web page... but if the page is watching for genuine user interactions only, you might also need to manually dispatch the appropriate events, as in this example:

    https://stackoverflow.com/a/77936551