Using PostMessage() in a bookmarklet that automates actions like clicking

49 Views Asked by At

First, some context. I'm using a tool right now that works great for me except for one major issue which is that managing the order of operations on things is a nightmare. In order to change the priority of items, you have to click a context menu on each one and click a button that says "Move Up" or "Move Down". This means that adding a new item to a list of 15 operations requires me to click the menu for that operation, click "Move Up", wait for the page to reload, and then repeat the process 15 times until that item is at the top of the list now (or however many times it takes to get it to the proper position in the priority list).

To try and make these tasks easier, I created a JS bookmarklet for myself that basically asks for the number of moves needed and what direction and then opens new windows to click that button. It works great with one exception - I have that many browser windows/tabs open and need to close them all manually. So, I'm trying to work in a way to close these windows but only once the button has been clicked and the page has finished loading. Since I don't know how long it would take to reload the page, I can't just use a setTimeout() as that would either end up with me waiting a long time for these windows to close or they would close before the actual click() has completed the new page load.

The solution I've come up with thus far is to try and use PostMessage() to send back a message to the main window to close these but it's not working. How can I get the main window to close the "helper" windows but only after they're done doing their thing? Right now, my code closes the window immediately after the click.

Keep in mind that this is a bookmarklet because I do not own the platform we're using and can't edit any of the source code on the page.

var objectiveID = 0, numberOfSpaces = 0, directionToMove = 0;
var windowURL = window.location.href;
let otherWindow = [];

objectiveID = prompt("What is the objective ID that you want to move?");
numberOfSpaces = prompt("How many positions do you need to move?");
directionToMove = prompt("What direction do you need to move in? 1: Up, 2: Down");

let moveDir = (directionToMove == 1) ? 'up' : 'down';
let i = 0;

while (i < numberOfSpaces){
    otherWindow[numberOfSpaces] = window.open(windowURL, 'helperWindow' + numberOfSpaces);
    (function (otherWindow, numberOfSpaces) {
        window.addEventListener('message', function(event){
            if (event.data === 'close') {
                otherWindow[numberOfSpaces].close();
            }
        });
    })(otherWindow, numberOfSpaces);
    otherWindow[numberOfSpaces].addEventListener('load', function() {
        this.document.querySelector('#objective_type_' + objectiveID + '_action .objective-type__move-' + moveDir).click();
        this.window.opener.postMessage('close', '*');
    });
    if (numberOfSpaces !== 0) {
        numberOfSpaces--;
    }
}

I've tried moving the postMessage() to inside the click() function which doesn't work at all and the windows stay open (I think the context of "this" is wrong within there but my brain is too fried to tell why). I've also tried other methods instead of postMessage() but it seems like this is the only one that can work between windows.

Secondly, but not really important at all, I can only use this bookmarklet once on this page. I have to reload it or I get an error that variables have already been declared. I've never really worked with bookmarklets before so I'm curious... is there a way around that? How can you create a bookmarklet that's re-useable if it needs to declare variables?

0

There are 0 best solutions below