Asked  1 Year ago    Answers:  5   Viewed   5 times

Ever since the new Greasemonkey 1.0 was released a few days ago, every site that has jQuery and where I use jQuery in my Greasemonkey script do not run my script properly. The jQuery I have in my GS script (using the @require metadata) conflicts with the page's jQuery. This is due to the new @grant code.

I've read the documentation but still don't know how to run GS scripts in a sandbox again; the only options seem to be to either grant access to a GS API or to grant it to none and run the script without any security limitations, which doesn't work at all for me when I've designed my dozens of GS scripts to run WITH security limitations and like it that way.

 Answers

5

Greasemonkey 1.0, radically changed the way the sandbox works, busting thousands of scripts. This is a huge problem, and I hope you will join me in voicing your opinion/experiences on the principle bug report for this issue.

The Greasemonkey blog claims that you can workaround the issue with the following:

this.$ = this.jQuery = jQuery.noConflict(true);

... Which I'm not sure will work in all cases. And it is the exact wrong approach from a side-effects-avoiding, DRY-principle, atomic-coding philosophy.   In my opinion, the best strategy is to restore the sandbox.

Reactivate the sandbox by specifying a @grant value (other than none). Edit your Metadata Block to end with the following lines:

// @grant       GM_addStyle
// @grant       GM.getValue
// ==/UserScript==
/*- The @grant directive is needed to work around a design flaws introduced in GM 1.0
    and again in GM 4.0.
    It restores the sandbox.
*/

The sandbox will be restored and all conflicts will be resolved.
And the scripts will be compatible with superior engines like Tampermonkey and Violentmonkey.

Tuesday, June 1, 2021
 
mopsyd
 
2

From "User Script Tip: Using jQuery - Erik Vold's Blog"

// ==UserScript==
// @name         jQuery For Chrome (A Cross Browser Example)
// @namespace    jQueryForChromeExample
// @include      *
// @author       Erik Vergobbi Vold & Tyler G. Hicks-Wright
// @description  This userscript is meant to be an example on how to use jQuery in a userscript on Google Chrome.
// ==/UserScript==

// a function that loads jQuery and calls a callback function when jQuery has finished loading
function addJQuery(callback) {
  var script = document.createElement("script");
  script.setAttribute("src", "//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js");
  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);
}

// the guts of this userscript
function main() {
  // Note, jQ replaces $ to avoid conflicts.
  alert("There are " + jQ('a').length + " links on this page.");
}

// load jQuery and execute the main function
addJQuery(main);
Tuesday, June 1, 2021
 
ALH
 
ALH
4

Yes you can, but not with a typical browser. Browsers are sandboxed to not have access to the local file system (except cookies) so that malicious sites can't read from / write to your hard drive. As far as I know there is no way to override this behvior (short of writing your own browser).

However, this can be done in JavaScript using Node.js. It runs as a process rather than in a browser window and can access the file system. Specifically, there is already an npm module (node library) for serial communication: https://github.com/voodootikigod/node-serialport

Alternatively, you could always just spin up a local web server (via node.js, php, rails, etc). Web servers can access file systems, and therefore should be able to access serial ports.

Hope this helps.

Monday, August 9, 2021
 
4

The quick and dirty way to do this, if you don't need any GM_ functions and you don't @require your own jQuery, is to use @grant none mode. This works:

// ==UserScript==
// @name     _unsafeWindow tests
// @include  http://jsbin.com/xaman/*
// @grant    none
// ==/UserScript==

var jQuery = window.jQuery;
jQuery(document).bind ("MyEvent", function () {
    console.log ("From GM script: MyEvent caught!");
} );

If you did need GM_ functions, you can sometimes use the new exportFunction().
Unfortunately, jQuery and jQuery event handling is a special case. Depending on what you try, you will get error messages like:

Permission denied to access property 'handler'
or
CloneNonReflectorsWrite error

I've simply found no way to do this using any of the new unsafeWindow functionality. Your only recourse is to inject the code. Like so:

// ==UserScript==
// @name     _unsafeWindow tests
// @include  http://jsbin.com/xaman/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @grant    GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/
function myEventHandler (zEvent) {
    console.log (
        'From GM script: "' + zEvent.type + '" triggered on ', zEvent.target
    );
}

function bindMyEvent () {
    //-- Gets "jQuery is not defined" if GM script does not also use jQuery.
    jQuery(document).bind ("MyEvent", myEventHandler);
    console.log ("The jQuery version being used is: ", jQuery.fn.jquery);
}

//-- Create A COPY OF myEventHandler in the target page scope:
addJS_Node (myEventHandler);
//-- Create A COPY OF bindMyEvent in the target page scope and immediately run it.
addJS_Node (null, null, bindMyEvent);

function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    if (runOnLoad) {
        scriptNode.addEventListener ("load", runOnLoad, false);
    }
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';

    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    targ.appendChild (scriptNode);
}

You can test both of these scripts against this jsBin page.


If you need to run/call GM_ functions from within the injected event handler(s), use techniques shown in "How to call Greasemonkey's GM_ functions from code that must run in the target page scope? ".

Thursday, October 21, 2021
 
3

In this case, just add the code inside the delinkChangeStat function.
From:

//-- Change the link
if (deltaText) {
    jNode.text (jNode.text () + " - " + deltaText);
}

To:

//-- Change the link
if (deltaText) {
    jNode.text (jNode.text () + " - " + deltaText);

    var deltaVal = parseInt (deltaText, 10);

    if ( (1 <= deltaVal)  &&  (deltaVal <= 10) )
        jNode.removeClass ("F-link-secondary").addClass ("F-rank-good");
    else if ( (11 <= deltaVal) && (deltaVal <= 22) )
        jNode.removeClass ("F-link-secondary").addClass ("F-rank-neutral");
    else if ( (23 <= deltaVal) && (deltaVal <= 32) )
        jNode.removeClass ("F-link-secondary").addClass ("F-rank-bad");
}
Tuesday, December 7, 2021
 
shaikh
 
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share