Pergunta

Eu tenho o simples seguinte (razoavelmente) fragmento de JavaScript que tenho com fio em Greasemonkey. Ela passa por uma página, procura tags cujos pontos href para tinyurl.com, e adiciona um atributo "título" que identifica o destino real do link. Grande parte do código importante vem de um antigo (sem suporte) script Greasemonkey que parar de funcionar quando o componente interior que realizou a implementação XPath alterado. Meu 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);
        }
    }
})();

(A razão da "provedores" matriz associativa está configurado do jeito que está, é para que eu possa expandir para cobrir outros serviços de encurtamento de URL também.)

Eu tenho verificado que todos os vários ramos do código estão sendo alcançados corretamente, nos casos em que o link a ser examinados faz e não correspondem ao padrão. O não é acontecendo, qualquer alteração ao atributo "título" das marcas de âncora. Eu assisti esta via Firebug, chamadas alert() jogados em esquerda e direita, e ele simplesmente nunca muda. Em uma iteração anterior todas as expressões da forma:

link.title = "...";

tinha sido originalmente:

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

Isso não funcionou, tampouco. Eu não sou nenhum novato para JavaScript ou Greasemonkey, mas este tem me perplexo!

Foi útil?

Solução

Tente substituir o corpo do if com este código em seu lugar.

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

Nota após o ciclo está completo aTags = null; fazer.

Seu problema é que um bloco if declaração não é um escopo verdade, qualquer coisa var'd vai pertencem ao âmbito funções exterior. Daí a sua função interna que você está fornecendo como um manipulador de eventos usaria a fonte, link e fragmento do último passe. Adicionalmente, mantendo referências a DOM objeto que você teria um vazamento de memória devido a referências circulares.

A abordagem acima criar um novo escopo em cada passagem através de uma chamada função para cada fonte e fragmento está em seu próprio âmbito. É também utiliza o fato de que uma função de chamada como um ouvinte evento tem a propriedade apontador this no elemento ao qual ele está ligado, evitando assim uma referência circular que contém um elemento de DOM.

scroll top