Greasemonkey script question: read data from similarly-named tags

I’m working on my first-ever Greasemonkey script. I’m reasonably familiar with Java-proper, but new at JS.

My script executes on a page with a specific sort of layout. The page contains a group of <SPAN> tags that are named as follows:

<SPAN id=“TheSpanName_Row1”>3</SPAN>
<SPAN id=“TheSpanName_Row2”>5</SPAN>
<SPAN id=“TheSpanName_Row3”>2</SPAN>

…and so on. The exact number of these tags will vary, but they’re all TheSpanName_Row, and each span contains an integer. What I need the script to do is total all the integers contained in these spans.

The parts I don’t know how to do are (most importantly) to read the data from the tags into an array, and (somewhat less importantly) to display the result in a new page element instead of just 'alert’ing it. If someone could point me in the right direction for learning how to do this, I’d be much obliged.

Thanks in advance for any advice.

First thing to remember: Javascript has nothing to do with Java. Read that sentence ten times. To a n00b they might look like they kinda-sorta have similar syntax, but they are nothing at all alike. So you won’t get anywhere if you try to apply Java thought-patterns to your Javascript.

That said, Greasemonkey allows you access to the page’s DOM API. DOM is kinda a shitty API, but you can do what you want using raw DOM methods, or use one of the many DOM-wrappers out there. (jQuery is my favorite. It also does all sorts of other useful stuff.)

It would be nice if the DOM had a way to grab elements that match a regex (then you could do /TheSpanName_Row\d+/ or something) but it doesn’t. So here’s a way you can grab all <span>s and keep the ones you want:

(Code off the top of my head, not tested)



var myspans = [ ];    // empty array
var allspans = document.getElementsByTagName( 'span' );

// loop over all the <span> tags, and push the ones with matching IDs onto our array
for( var i = 0; i < allspans.length; i++ ) { 
    if ( allspans*.id.match( /TheSpanName_Row\d+/ ) ) { 
        myspans.push( allspans* );
    }
}


Now here’s a way to total them:



var total;
for( var i = 0; i < myspans.length; i++ ) { 
    var rowspan = myspans*;
    var num = rowspan.innerHTML - 0;   
    /* we subtract zero to force to integer. You can't add zero because + also does string concatenation. */
    total += num;
}


Investigate createElement and the various append methods for how to stick this total into the document. BTW, here is why I love jQuery. You could do the same thing with something like:



var total;
$('span').filter(function() { return this.id.match(/TheSpanName_Row\d+/); }).each( function() { total += ( this.html() - 0 ) } );


Wow, brilliant. I’d have been happy with just learning the existence of document.getElementsByTagName, but this will save me a good bit of time. Just reading up on the methods/properties you’re using, you’re right about one thing…Java it ain’t.

Thanks muchly. Careful, though; there’s such a thing as TOO nice…now I might be back to ask additional n00bish questions :D.

BTW, get this book: Javascript: The Good Parts. It will save you from innumerable traps, like the above-mentioned overloading of the + operator.

I’m a big fan of Javascript: first-class functions, prototypal OO, closures, etc. But boy does it have its warts. (null, false and undefined?! No block scope!? Aarrrghghgh.)

Hrrm. Looks like I’m running into a JS quirk right now, so, here’s that other newbie question I warned you about.

I created a GM script from your code, and tested it by adding a final line of alert('Total is ’ + total);. That gave me a popup that reads “Total is NaN”. So, I threw in another alert to call out num on each iteration, which worked fine. Is total not correctly typed for some reason?

ETA: Blargh. Two seconds after I post, every time. Not JS, just an oversight on my part… total = 0;, problem solved. Thanks again.