1

I'm writing a Greasemonkey script to automatically delete my notifications from a site, based on words I enter into a search box.

The delete "button" is basically a link, so I'm trying to open the first link in a new tab. Then, after it loads enough, open the rest of the links, one by one, in that same tab.

I figured out how to get the links I needed and how to loop and manipulate them. I was able to grab the first delete-link and open it in a new tab. I added an event listener to make sure the page was loaded before going to the next link.
I finally made that work so added my search box and button. Then I had to figure out how to wrap the whole thing in the event listener again.

So, I now have the whole thing working, except only the last link loads.
All links are going to my waitFor function so they should open, so it seems the event listener isn't working so it goes through the loop too fast and only the last link loads.

How do I make this script not continue the loop until the previous loaded page is fully loaded?

Complete code except for box and button creation:

var mytable = document.getElementById ('content').getElementsByTagName ('table')[0]
var myrows = mytable.rows

//function openLinkInTab () {
//mywin2.close ();
//}

var mywin2;
mywin2 = window.open ("http://www.aywas.com/message/notices/test/", "my_win2");
var links;

var waitFor = function (i) {
    links = myrows[i].cells[1].getElementsByTagName ("a");
    mywin2 = window.open (links[0].href, "my_win2");
}

var delnotifs = function () {
    var matching;
    var toRemove;
    toRemove = document.getElementById ('find').value;
    alert (toRemove)
    for (i = 0; i < 10; i++) {

        matching = myrows[i].cells[0].innerHTML;

        if (matching.indexOf (toRemove) > 0) {
            mywin2.addEventListener ('load', waitFor (i), false);
        }
    }
}

searchButton.addEventListener ('click', delnotifs, true);

So, why isn't it waiting for `mywin2.addEventListener('load', waitFor(i), false);`? I have a feeling it's something extremely simple that I'm missing here, but I just can't see it.

I also tried mywin2.addEventListener('load', function(){waitFor(i)}, false); and it still does the same thing, so it's not a problem of being a call instead of a pointer.

Swapping mywin2.addEventListener('load', waitFor(i), false); for if (mywin2.document.readyState === "complete") { waitFor(i)} doesn't work either.

And while I'm at it... every time I see code looping through a list like this it uses

for(i=1;i < myrows.length;i++)

Which was skipping the first link in the list since arrays start at zero. So my question is, if I switch 'i' to zero, and the loop only goes while 'i' is < length, doesn't that mean it won't go through the whole list? Shouldn't it be

for(i=0;i != myrows.length;i++)  
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Kat Cox
  • 3,469
  • 2
  • 17
  • 29
  • The `i=1` for-loop is because for many tables, the first row (row 0), is for column headers, and usually can't contain what you are looking for. While `for(i=0;i != myrows.length;i++)` will work in many cases, it is what is called "Time bomb code". If you use it, there **will** come a time when your index overruns the array and then "Eyes melt. Skin explodes. Everybody dead". – Brock Adams Jul 25 '13 at 02:27
  • @BrockAdams Yeah - array out of bounds is an pain in the butt... unfortunately, in the table I'm working with the first row isn't table headers (I don't think... because when I was just alerting the rows and was using i=1 it wasn't showing the first row), so considering I haven't played with arrays much in any language, I can't figure out whether that means I have to -1 from the length (because 0+43 isn't the same as 1+43) or whether I need to != it. – Kat Cox Jul 25 '13 at 07:55
  • @BrockAdams Thanks for the edit... guess I don't need the sob story in there since I got an answer lol... and you thought that code was messy - I cleaned it up before I posted it (you should see my code when I'm working on it lol) I actually TRY to make my posts on here clear and concise, but with ADHD that's really difficult for me, so thanks for fixing it for me! – Kat Cox Jul 25 '13 at 07:59
  • You're welcome! We're mostly tech types here. That means we like questions that get to the point without a lot of baggage. Also, you get more people to read if you break up "walls of text". – Brock Adams Jul 25 '13 at 08:27

2 Answers2

1

When you open a popup (or tab) with window.open, the load event only fires once -- even if you "open" a new URL with the same window handle.

To get the load listener to fire every time, you must close the window after each URL, and open a new one for the next URL.

Because popups are asynchronous and you want to load these links sequentially, don't use a for() loop for that. Use the popup load status to "chain" the links.

Here is the code to do that. It pushes the links onto an array, and then uses the load event to grab and open the next link. You can see the code in action at jsFiddle. :

var searchButton    = document.getElementById ('gmPopUpBtn');
var mytable         = document.getElementById ('content').getElementsByTagName ('table')[0];
var myrows          = mytable.rows;
var linksToOpen     = [];
var mywin2          = null;

function delnotifs () {
    var toRemove    = document.getElementById ('find').value;

    for (var J = 0, L = myrows.length;  J < L;  J++) {
        var matching = myrows[J].cells[0].innerHTML;

        if (matching.indexOf (toRemove) > 0) {
            var links = myrows[J].cells[1].getElementsByTagName ("a");
            linksToOpen.push (links[0].href); //-- Add URL to list
        }
    }
    openLinksInSequence ();
};

function openLinksInSequence () {
    if (mywin2) {
        mywin2.close ();
        mywin2      = null;
    }

    if (linksToOpen.length) {
        var link    = linksToOpen.shift ();
        mywin2      = window.open (link, "my_win2");

        mywin2.addEventListener ('load', openLinksInSequence, false);
    }
}
searchButton.addEventListener ('click', delnotifs, true);
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • Thank you, great answer as always! And pure javascript too... I was really afraid I'd end up being forced to use jquery for this project lol. --- But... but... but... FB Wall manager manages to reuse tabs... although the tab does go to about:blank between links... I wonder what his trick is? Can you change the handle of a window? Hmmmmm... I ever get facebook working on dialup I'll have to ask him how he does it. Anyways, your answer looks like it'll work well - although if a user doesn't set firefox to allow scripts to close tabs couldn't this lead to a LOT of tabs ending up open? – Kat Cox Jul 25 '13 at 07:48
  • So I guess 'push' must write the value to the end of the array? – Kat Cox Jul 25 '13 at 08:02
  • What you are doing is opening *popups*. It only looks like a tab because you gave it no dimensions. If a script can open a popup at all, then it can close that popup too. That is not a problem. As for keeping the popup open, that's possible but a lot more work, for no real gain. Open a new question for that. ... ... [Link for javascript push()](http://www.w3schools.com/jsref/jsref_push.asp). – Brock Adams Jul 25 '13 at 08:04
  • So it's different from GM_OpenInTab then? Or would those be popups too? – Kat Cox Jul 25 '13 at 08:12
  • I *think* `GM_OpenInTab()` uses a different mechanism and isn't blocked by the normal browser settings. It's recently changed and I haven't checked out that part of GM's code in a while. Per the doc, the `load` event should operate the same, however. That means closing the window after every link. – Brock Adams Jul 25 '13 at 08:21
  • One more question then I gotta sleep... is there a way to limit your code to only process a certain number of matches? I want to do a small test first and if it deletes them all I won't have anything left to test on... lol! – Kat Cox Jul 25 '13 at 08:37
  • Change `L = myrows.length;` to `L = Math.min (myrows.length, 3);`, for example. – Brock Adams Jul 25 '13 at 08:49
  • I must've been tired... that's almost a 'duh' except I haven't seen Math.min before... I assume that says to use whichever is smaller in case the array is smaller than that... thanks! – Kat Cox Jul 25 '13 at 17:53
0

See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener. The second argument of the addEventLister function must be a pointer to a function and not a call.

  • But it worked fine until I put it into the 'delnotifs' function... and if I didn't pass 'i' the 'waitFor' function didn't work. – Kat Cox Jul 19 '13 at 20:17
  • Anonymous function from that page doesn't work either `mywin2.addEventListener('load', function(){waitFor(i)}, false);`...still does the same thing. – Kat Cox Jul 19 '13 at 20:26
  • It seems you want to observe an event which has been already fired no ? mywin2 is loaded when you'll call delnotifs. – flavien.crochard Jul 19 '13 at 20:58
  • Yeah, but that was the case before I wrapped delnotifs around the loop... and the event listener calls something that loads the next window (if I didn't set mywin2 before it got there I got a 'not defined' error)... and the loop runs just fine and the event listener triggers and calls the function that creates and loads the next link, but then loops back to the beginning before the page loads... I think I either need another listener somewhere, or maybe the not matching rows are causing the problem? Maybe I could close the window at the end of 'waitFor', but I don't wanna do it that way... – Kat Cox Jul 19 '13 at 21:24
  • Maybe I need a return in there somewhere? – Kat Cox Jul 19 '13 at 22:29