JavaScript (via Greasemonkey) cannot set "title" attributes on tags

I have the following (fair) simple JavaScript snippet that I hooked up to Greasemonkey. It scans the page, looks for the <a> tags whose href points to tinyurl.com

, and adds a "title" attribute that identifies the link's true destination. Most of the important code comes from an older (unsupported) Greasemonkey script that stops working when the internal component containing the XPath implementation has changed. My script:

(function() {
    var providers = new Array();
    providers['tinyurl.com'] = function(link, fragment) {
        // This is mostly taken from the (broken due to XPath component
        // issues) tinyurl_popup_preview script.
        link.title = "Loading...";
        GM_xmlhttpRequest({
                method: 'GET',
                url: 'http://preview.tinyurl.com/' + fragment,
                onload: function(res) {
                    var re = res.responseText.match("<blockquote><b>(.+)</b></blockquote>");
                    if (re)
                    {
                        link.title = re[1].replace(/\<br \/\>/g, "").replace(/&amp;/g, "&");
                    }
                    else
                    {
                        link.title = "Parsing failed...";
                    }
                },
                onerror: function() {
                    link.title = "Connection failed...";
                }
        });
    };
    var uriPattern = /(tinyurl\.com)\/([a-zA-Z0-9]+)/;
    var aTags = document.getElementsByTagName("a");

    for (i = 0; i < aTags.length; i++)
    {
        var data = aTags[i].href.match(uriPattern);
        if (data != null && data.length > 1 && data[2] != "preview")
        {
            var source = data[1];
            var fragment = data[2];
            var link = aTags[i];
            aTags[i].addEventListener("mouseover", function() {
                if (link.title == "")
                {
                    (providers[source])(link, fragment);
                }
            }, false);
        }
    }
})();

      

(The reason the "providers" associative array is configured as it is is that I can extend it to cover other URL shortening services.)

I have verified that all the different branches of code are being reached correctly, in cases where the link being checked does and does not match the pattern. What doesn't happen is any change to the "title" attribute of the anchor tags. I've watched this through Firebug, challenged alert()

left and right, and it just doesn't change. At the previous iteration, all expressions of the form:

link.title = "...";

      

was originally:

link.setAttribute("title", "...");

      

It didn't work either. I'm not new to JavaScript or Greasemonkey, but I have me stumped!

0


source to share


1 answer


Try replacing the body if

with this code instead .

        aTags[i].addEventListener("mouseover", (function(source, fragment)
        {
            return function()
            {
                if (this.title == "")
                {
                    (providers[source])(this, fragment);
                }
            }
        })(data[1], data[2]), false) ; 

      

Note that after the loop completes, execute aTags = null;

.



Your problem is that the if if block is not true scope, all var'd will be in the scope of external functions. Hence, your inner function that you provide as an event handler will use the source, reference and fragment of the last pass. Also, by maintaining references to the DOM object, you will have a memory leak due to circular references.

The above approach creates a new scope on each pass through the function call, so each source and fragment is in its own scope. It also takes advantage of the fact that a function called as an event listener has a property this

that points to the element it is attached to, and thus avoiding a circular reference that contains the DOM element.

+2


source







All Articles