Bookmarklet to open window to URL, wait for load, close window

Viewed 852

Disclaimer: I don't actually expect this is possible due to security issues, but before I give up entirely I had to ask: Is it possible, using a Javascript bookmarklet, to open a window to a URL and have it auto close after that content has loaded?

My usage is to temporarily disable Pi-hole using it's API. The current code I have works on a simple timeout, but I'd like to have it ensure the page loaded before closing the window.

Here's my (expanded) code at the moment:

(() => {
    t = prompt('Disable time (seconds)',30);
    if (t) {
        w = window.open(`http://___IP___/admin/api.php?disable=${t}&auth=___APIKEY___`,'pi-disable','left=20,top=20,width=300,height=200');
        setTimeout(() => w.close(), 1000);
    }
})()

In case it's not obvious, I don't control the URL output so I can't add script there to have it close, otherwise this would be a non-issue. And for reference, the output is just a JSON string: {"status":"disabled"}

Just for kicks, I tried using fetch() or adding an iframe, but as expected those presented other issues (Mixed Content, CORS policy, etc).

1 Answers

I don't think this is possible with a bookmarklet, because it can only run its code on the one page you press the bookmarklet button on. If you open a window to a new domain, the bookmarklet won't be able to affect it or watch it load.

You could have another bookmarklet that you press when the new window opens, but that kind of defeats the point of automation

You could, however, do this with a userscript, which can run automatically when a page is opened. When the API site is opened, have the userscript watch for page load, then post a message telling your bookmarklet that the page is finished loading, and can be closed. Something along the lines of:

(() => {
    const t = prompt('Disable time (seconds)',30);
    if (!t) return;
    const w = window.open(`http://___IP___/admin/api.php?disable=${t}&auth=___APIKEY___`,'pi-disable','left=20,top=20,width=300,height=200');
    window.addEventListener('message', (messageEvent) => {
        if (messageEvent.data === 'api page loaded') w.close();
    });
})()

and, with a userscript manager like Tampermonkey:

// ==UserScript==
// @name         Watch for API pageload
// @match        http://___IP___/*
// @grant        none
// ==/UserScript==

window.addEventListener('DOMContentLoaded', () => {
  window.opener.postMessage('api page loaded', '*');
});
Related