2

So, I wrote a script that loads images one at a time in a new tab... Got a stop button to work thanks to Brock over HERE...

Then I broke it adding in the counter that I had written in while waiting for an answer to that question.

I can't see any reason that should have broke it... help please?

My Script:

var box = document.createElement ('div');
box.id = 'mySelectBox';
GM_addStyle (
    ' #mySelectBox {             ' +
    '    background: white;     ' +
    '    border: 2px solid red; ' +
    '    padding: 4px;          ' +
    //'    position: absolute;    ' +
    '    position: fixed;       ' +
    '    top: 8px; left: 8px;   ' +
    '    max-width: 400px;      ' +
    ' } '
);
document.body.appendChild (box);
box.innerHTML = '';

var searchButton = document.createElement ('div');
searchButton.className = 'mySearchButton';
searchButton.textContent = 'Open';

GM_addStyle (
    ' .mySearchButton {           ' +
    '    background: #aaa;       ' +
    '    border: 1px solid #777; ' +
    '    padding: 1px;           ' +
    '    margin-left: 8px;       ' +
    '    float: right;           ' +
    '    cursor: pointer;        ' +
    ' } '
);
box.insertBefore (searchButton, box.nextSibling);

var stopButton = document.createElement ('div');
stopButton.className = 'myStopButton';
stopButton.textContent = 'Stop';

GM_addStyle (
    ' .myStopButton {           ' +
    '    background: #aaa;       ' +
    '    border: 1px solid #777; ' +
    '    padding: 1px;           ' +
    '    margin-left: 8px;       ' +
    '    float: right;           ' +
    '    cursor: pointer;        ' +
    ' } '
);
box.insertBefore (stopButton, box.nextSibling);

var closeButton = document.createElement ('div');
closeButton.className = 'myCloseButton';
closeButton.textContent = 'X';

GM_addStyle (
    ' .myCloseButton {           ' +
    '    background: #aaa;       ' +
    '    border: 1px solid #777; ' +
    '    padding: 1px;           ' +
    '    margin-left: 8px;       ' +
    '    float: right;           ' +
    '    cursor: pointer;        ' +
    ' } '
);

box.insertBefore (closeButton, box.firstChild);
closeButton.addEventListener ('click', function () {
    box.parentNode.removeChild (box);
}, true);

var mytable = document.getElementById

    ('lair-sort-pets').getElementsByTagName ('img');

var linksToOpen = [];
var mywin2 = null;

var okayToOpenLinks = true;

searchButton.addEventListener ('click', openpics);
stopButton.addEventListener ('click', stopLinkSequence);

function openpics () {
    okayToOpenLinks = true;

    if (linksToOpen.length === 0) {
        for (var J = 0, L = mytable.length; J < L; J++) {

            linksToOpen.push (mytable[J].src); //-- Add URL to list
        }
    }

    openLinksInSequence ();
};

original = box.innerHTML

function stopLinkSequence () {
    okayToOpenLinks = false;
}

function openLinksInSequence () {
    k = linksToOpen.length - 1

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

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

        box.innerHTML = '<center>Links left</center><br>' + '<center>' + k + '</center><br>' + original;

        mywin2.addEventListener ('load', openLinksInSequence, false);
    }
}


If I comment out this line it works again (except no status counter):

box.innerHTML = '<center>Links left</center><br>'+'<center>'+k+'</center><br>'+original;


WHY?

HERE is a possible target page for the Greasemonkey script.

Community
  • 1
  • 1
Kat Cox
  • 3,469
  • 2
  • 17
  • 29

1 Answers1

2

When you change an element's contents using innerHTML (or outerHTML), it trashes any event handlers of anything that element contained. It can also help cause performance problems and memory leaks. Don't use innerHTML in userscripts except maybe for the initial creation of brand new nodes.

For a countdown/status display, create the HTML once, then just alter the data content and/or use CSS to alter the display. Doing that, and sanitizing things a bit, that code becomes:

var box         = document.createElement ('div');
document.body.appendChild (box);    // Must append before set outerHTML
box.outerHTML   = multilineStr ( function () {/*!
    <div id="mySelectBox">
        <div id="myStatus">Links left<br>
            <span>86</span>
        </div>
        <div id="myCloseButton">X</div>
        <div id="mySearchButton">Open</div>
    </div>
*/} );

document.getElementById ("myCloseButton").addEventListener ('click', function () {
    var box = this.parentNode;
    box.parentNode.removeChild (box);
} );
var startStopBtn    = document.getElementById ("mySearchButton");
startStopBtn.addEventListener ('click', startStopPicsLoad);

var mytable         = document.querySelectorAll ('#lair-sort-pets img');
var linksToOpen     = [];
var mywin2          = null;
var okayToOpenLinks = true;

function startStopPicsLoad () {
    if (typeof startStopPicsLoad.isStartBtn === "undefined") {
        startStopPicsLoad.isStartBtn    = true;
    }
    if (startStopPicsLoad.isStartBtn) {
        //-- Change start button to stop button
        startStopBtn.textContent        = "Stop";
        startStopPicsLoad.isStartBtn    = false;

        if (linksToOpen.length === 0) {
            for (var J = 0, L = mytable.length; J < L; J++) {
                linksToOpen.push (mytable[J].src); //-- Add URL to list
            }

            //-- Display the status area.
            document.querySelector ('#myStatus').style.display = "block";
        }

        openLinksInSequence ();
    }
    else {
        //-- Change stop button to start button
        startStopBtn.textContent        = "Open";
        startStopPicsLoad.isStartBtn    = true;

        //-- Actually stop the sequence.
        okayToOpenLinks = false;
    }
};

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

    if (okayToOpenLinks) {
        if (linksToOpen.length) {
            var k           = linksToOpen.length - 1;
            var statDisp    = document.querySelector ('#myStatus span');
            statDisp.textContent = k;

            var link        = linksToOpen.shift ();
            mywin2          = window.open (link, "my_win2");
            mywin2.addEventListener ('load', openLinksInSequence, false);
        }
    }
    else {
        //-- Sequence is now stopped, reset the state variable.
        okayToOpenLinks = true;
    }
}

GM_addStyle ( multilineStr ( function () {/*!
    #mySelectBox {
        background: white;
        border: 2px solid red;
        padding: 4px;
        //position: absolute;
        position: fixed;
        top: 8px; left: 8px;
        max-width: 400px;
    }
    #myStatus {
        text-align: center;
        display: none;
    }
    #myCloseButton {
        background: #aaa;
        border: 1px solid #777;
        padding: 1px;
        margin-left: 8px;
        float: right;
        cursor: pointer;
    }
    #mySearchButton {
        background: #aaa;
        border: 1px solid #777;
        padding: 1px;
        margin-left: 8px;
        float: right;
        cursor: pointer;
    }
*/} ) );

function multilineStr (dummyFunc) {
    var str = dummyFunc.toString ();
    str     = str.replace (/^[^\/]+\/\*!?/, '') // Strip function() { /*!
            .replace (/\s*\*\/\s*\}\s*$/, '')   // Strip */ }
            .replace (/\/\/.+$/gm, '') // Double-slash comments wreck CSS. Strip them.
            ;
    return str;
}
Community
  • 1
  • 1
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • It actually didn't cause a pileup... all it did was disable the stop button... but the counter was working perfectly... (maybe you missed the line near the beginning where I set 'original' - before I did that they did pile up if I used 'innerHTML + k' and if I didn't use 'innerHTML +'it ate the buttons lol)... I see you also changed my 'getElements' - explain? This is so much more complicated than my version... Now to understand it before I use it... THANK YOU! – Kat Cox Oct 18 '14 at 07:21
  • Oops. Sorry about the "pileup" mixup. That's what I get for "testing" that part of the code in my head. ;) ... ... That "getElements" usage was "time-bomb code" since the return value of the stack wasn't checked. `querySelector` is far superior for that kind of thing, and it uses standard CSS selectors (which you need to know anyway) to grab elements. – Brock Adams Oct 18 '14 at 08:53
  • I updated Firefox and Greasemonkey recently and this script no longer works... the start button loads the first image but won't close it, and then if I hit stop, then hit start the image tab closes and then nothing - no error codes. Has anything changed since Firefox 24 that might be causing this? Or in the newest Greasemonkey? Or do I need to look at my numerous updated addons? – Kat Cox Nov 19 '15 at 04:43
  • Yes, quite a bit has changed. I don't see anything obvious that would break in this script, though. ... Add `// @grant GM_addStyle` to your header/metadata block. If that doesn't work, boil the problem down to an MCVE and ask a new question. – Brock Adams Nov 19 '15 at 05:06
  • Darn.... thanks anyways... // @grant GM_addStyle is already there because it's being used lol... so no easy fix - this'll be fun.... I DID read something about window.close() being changed in Firefox 35 (or somewhere around there) but I assume you would've noticed if it was something like that... this is why I don't ever upgrade... it broke another script too, finally rewrote it from scratch with more jquery - probably rewrite this one too. Thanks for trying to help. – Kat Cox Nov 19 '15 at 10:05
  • Ahah! Error: Permission denied to access property "addEventListener" Now to figure out why.... in this line: mywin2.addEventListener ('load', openLinksInSequence, false); or this one: mywin2= window.open (link, "my_win2"); – Kat Cox Nov 19 '15 at 11:53
  • Okay, that might be a PITA to get around in newer Firefox. Forgot about window open/close changes. And you have to keep up with upgrades. Otherwise, you'll get infected just by *viewing* web pages and without even knowing it. And AV programs always miss "zero day" attacks too. Make a new Q with an MCVE, if needed. – Brock Adams Nov 19 '15 at 18:06
  • I have a script that uses a jqueryui modal window to go through the links on a page with a next button... I may be able to use that as a basis, and I prefer the modal to the new tab anyways. Viruses don't worry me - I have a side job repairing computers and have yet to find the virus that can beat me (although I still haven't gotten around to installing the Ransom virus on my test computer). I keep hearing you can get viruses just by viewing a page but I haven't found one yet that doesn't require pressing a button. I haven't had a virus in years. And I don't even run a resident scanner. – Kat Cox Nov 20 '15 at 02:21