Global Differences in Userscripts in Chrome and Firefox

Asked

Viewed 198 times

5

I started programming Userscripts in Chrome and almost all snippets of code I find work, but when going pro Firefox gives problem. In Chrome I use the Tampermonkey and in Firefox the Scriptish (which is a Fork greasemonkey).

[Note to future visitors, advise against emphatically working with Scriptish, there are things that run smoothly in GM and TM but not in it.]

For example, if I add a script in the DOM, whose return is a JSONP, the function callback (global) of JSONP gives undefined in FF. Or, if I make an AJAX call, at the time of executing a global function within the success also gives undefined in FF.

I made a reduced version that demonstrates the problem. The function global_function runs on Chrome but not on FF. The execution domain is SOPT and the AJAX call is to the Stack Exchange API.

// ==UserScript==
// @name           (SOPT) FF problems
// @namespace      sopt.se
// @author         brasofilo
// @include        /*
// @description    Testando problemas no FF
// ==/UserScript==

jquery_url = '//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js'

global_function = function() {
    alert( 'yes!' );
}

/**
 * Chamada depois que o jQuery foi carregado
 */
function jqueryLoaded() {
    jQ.ajax({
        url: 'http://api.stackexchange.com/2.2/users',
        data: { order: 'desc', sort: 'reputation', site: 'stackoverflow' },
        type: 'get',
        dataType: 'json',
        cache: false,
        success: function(data) {
            console.log(data);
            global_function();
        }
    });
}

/**
 * Carrega jQuery e chama callback quando carregar
 * Nota: jQ substitui $ para evitar conflitos
 * 
 * https://stackoverflow.com/a/3550261/1287812
 */
function addJQuery( callback ) {
    var script = document.createElement( 'script' );
    script.setAttribute( 'src', jquery_url );
script.addEventListener( 'load', function() {
        var script = document.createElement('script');
        script.textContent = 'window.jQ=jQuery.noConflict(true);(' + callback.toString() + ')();';
        document.body.appendChild( script );
    }, false );
    document.body.appendChild( script );
}

addJQuery( jqueryLoaded );

I tried to window.global_function = function(){ }, function global_function() {}, unsafeWindow.global_function = function(){ } and following undefined. And I checked the following discussions but I didn’t clarify anything...

How to resolve this issue of Scope? And in addition, there are other basic differences when programming Userscripts for Chrome and Firefox?

  • Stackoverflow already carries the jQuery. The code you run within script tags could access the stackoverflow jquery without having to load the library again.

1 answer

2


For security reasons1, greasemonkey Userscripts run in a sandbox separate from the normal scripts on your page. In particular, the greasemonkey script has a window difference of window of the rest of the page scripts: global variables defined in userscript do not leak to page scripts and vice versa.

In particular, the code within the script tags you created will run in the context of the page, which is different from the original context of your userscript.

The links you found suggest using the unsafeWindow property to access the page window from the greasemonkey window but this unfortunately doesn’t work anymore, since Firefox recently removed the unsafeWindow support, which can no longer be used by the greasemonkey from the version 2.0.

To solve your problem, has more of an approach you can take:

  • Use the new API export_function to export global_function from the greasemonkey scope to the page scope, where you are loading jQuery.

    I think this solution only works in Firefox.

  • Load jQuery into the scope of the greasemonkey script, using require. So your code runs all the way through the greasemonkey scope and you can skip the page scope (and dynamically inserted script tags).

    I think avoiding dynamic script tags would be the least "gambiarra" solution. The problem is that I don’t know if you can do this in the tampermonkey and not every library you want to use accepts to be rotated in the scope of greasemonkey.

  • Do the opposite of the second alternative: scroll your entire codex in the page scope and ignore the greasemonkey scope. The easiest way to do this would be to put all its functions inside the jqueryLoaded, which is the function you are Serializing into the script tag:

    function jQueryLoaded(){
        function global_function(){ ... }
    
        jQ.ajax({
            success: function(){
                 global_function();
            }
        });
    }
    

    Putting your entire code inside the injected script tag is pretty simple and "cross browser" and it’s also the only way to override variables defined by the page scripts (if you need to do this). The main drawback is that the line numbers of the error messages you get do not match the line numbers of your original file.


1 greasemonkey provides some more privileged Apis, which we do not want to be accessed by the scripts we load from the web.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.