Accessing Variables from Greasemonkey to Page & Vice Versa

Accessing Variables from Greasemonkey to Page & vice versa

  • Greasemonkey scripts operate in a separate scope and may also operate in a sandbox, depending on the @grant settings.

  • Additionally, the question code isolates greasy in a function scope (as gladoscc said).

  • Finally, by default, test.js will fire before the Greasemonkey script does, so it won't see any set variables, anyway. Use @run-at document-start to address that.


So, given this test.js, run right before </body>:

window.targetPages_GlobalVar = 'stovetop';

console.log ("On target page, local global: ", targetPages_GlobalVar);
console.log ("On target page, script global: ", gmScripts_GlobalVar);

Then the following will work:

No sandbox:

// ==UserScript==
// @name _Greasemonkey and target page, variable interaction
// @include http://YOUR_SERVER.COM/YOUR_PATH/*
// @include http://output.jsbin.com/esikut/*
// @run-at document-start
// @grant none
// ==/UserScript==

//--- For @grant none, could also use window. instead of unsafeWindow.
unsafeWindow.gmScripts_GlobalVar = 'greasy';

console.log ("In GM script, local global: ", unsafeWindow.targetPages_GlobalVar);
console.log ("In GM script, script global: ", gmScripts_GlobalVar);

window.addEventListener ("DOMContentLoaded", function() {
console.log ("In GM script, local global, after ready: ", unsafeWindow.targetPages_GlobalVar);
}, false);


With sandbox, no function scope, unsafeWindow:
==> Important update: Greasemonkey changed unsafeWindow handling with version 2.0, the next sample script will not work with GM 2.0 or later. The other two solutions still work.

// ==UserScript==
// @name _Greasemonkey and target page, variable interaction
// @include http://YOUR_SERVER.COM/YOUR_PATH/*
// @include http://output.jsbin.com/esikut/*
// @run-at document-start
// @grant GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
introduced in GM 1.0. It restores the sandbox.
*/

unsafeWindow.gmScripts_GlobalVar = 'greasy';

console.log ("In GM script, local global: ", unsafeWindow.targetPages_GlobalVar);
console.log ("In GM script, script global: ", unsafeWindow.gmScripts_GlobalVar);

window.addEventListener ("DOMContentLoaded", function() {
console.log ("In GM script, local global, after ready: ", unsafeWindow.targetPages_GlobalVar);
}, false);


With sandbox, no function scope, Script Injection:

// ==UserScript==
// @name _Greasemonkey and target page, variable interaction
// @include http://YOUR_SERVER.COM/YOUR_PATH/*
// @include http://output.jsbin.com/esikut/*
// @run-at document-start
// @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 GM_main () {
window.gmScripts_GlobalVar = 'greasy';

console.log ("In GM script, local global: ", window.targetPages_GlobalVar);
console.log ("In GM script, script global: ", window.gmScripts_GlobalVar);

window.addEventListener ("DOMContentLoaded", function() {
console.log ("In GM script, local global, after ready: ", window.targetPages_GlobalVar);
}, false);
}

addJS_Node (null, null, GM_main);

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);
}

Notes:

  1. You can test these script against this page (output.jsbin.com/esikut/1).
  2. With no sandbox, unsafeWindow and window are the same.
  3. All of these scripts produce the same output on the console:

    In GM script, local global: undefined
    In GM script, script global: greasy
    On target page, local global: stovetop
    On target page, script global: greasy
    In GM script, local global, after ready: stovetop
  4. The Script Injection code will work in a variety of browsers besides Firefox. unsafeWindow currently only works in Firefox+Greasemonkey(or Scriptish) or Chrome+Tampermonkey.

Auto select items-per-page (a drop down) using a Greasemonkey-like script

Since that select is driven by jQuery, you can use jQuery to change it and trigger all the necessary javascript.

But your Greasemonkey script must use injection or @grant none mode, because you need to trigger the page's javascript functions.

A complete script for that sample page would be like:

// ==UserScript==
// @name _Amazon-like store, auto select 50 items per page
// @include https://dl.dropboxusercontent.com/u/5546881/*
// @grant none
// ==/UserScript==

//-- $ not defined. Use jQuery
jQuery('#v_pagination_long select').val (50).trigger ('change');



Update:

Since the OP is not really using Greasemonkey, or a modern equivalent like Tampermonkey, @grant none is not supported.

Here is the same script using script injection, that will work on almost any browser+userscript-engine combo:

// ==UserScript==
// @name _Amazon-like store, auto select 50 items per page
// @include https://dl.dropboxusercontent.com/u/5546881/*
// @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 GM_main () {
jQuery('#v_pagination_long select').val (50).trigger ('change');
}

addJS_Node (null, null, GM_main);

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);
}



Important:

  1. That sample page shows 9 items max, so it's impossible to be 100% sure that the script is doing everything needed. With the OP's new sample page, verified that the script works on FF+GM and Chrome+TM.
  2. The <select> is wrapped in a div with the id: v_pagination_long. Use that to help get the correct control.
  3. That page uses various mouse events (not click), so it may be that more stateful approaches are needed (Can't tell for sure, see item 1). Not needed in this case for the demo page. See Choosing and activating the right controls on an AJAX-driven site for other pages.

Run an onchange function from a Greasemonkey or Tampermonkey script?

The location hack is a safe and easy way to execute a function defined in the page:

location.assign("javascript:window.onChange('incident.category');void(0)");

It's a lot like running a bookmarklet from within a Greasemonkey script, so it's perfect for scripts that need to a reference only a few things from the page. And, because javascript: URLs always execute in the content scope, this method does not have any of the security concerns that come with using unsafeWindow.

Access a secure cookie from a Greasemonkey script?

I'm guessing you really mean cookies with the HttpOnly attribute set. (See, also, Wikipedia for HttpOnly cookie.)

In that case, you cannot access these cookies from Greasemonkey because they are forbidden to javascript, and because Greasemonkey does not provide an alternate mechanism to see them.

You can try making a feature request, but I'm not optimistic about its reception. (Try anyway.)

Firefox add-ons, can work with these cookies, so you can fork the Greasemonkey source yourself or write a helper add-on (example) to get to these cookies.


If you mean cookies with the Secure attribute (Cookies that must be sent only over HTTPS), then I believe you can access those from injected code in the target page scope, but I'm not set up to test this at the moment. (The target page must be loaded over HTTPS and on the exact same domain as the cookies you want.)

How to control a Tampermonkey script's function from the browser's JS console?

Greasemonkey, and Tampermonkey, operate in separate scopes from the target page, and may use a sandbox as well.

The target page and JS console can not see variables and functions defined in the script scope, but your script can inject stuff into the target page's scope.

So, place your on variable in the target page scope, and you can then control that function from the console. In this case, use unsafeWindowDoc to do that.

A complete Greasemonkey and Tampermonkey script that does that is:

// ==UserScript==
// @name _Allow console control of Tampermonkey function
// @include http://YOUR_SERVER.COM/YOUR_PATH/*
// @grant unsafeWindow
// ==/UserScript==

unsafeWindow.on = true;

function doSomething () {
if (unsafeWindow.on){
//do stuff
}
}
setInterval (doSomething, 1000);

From the console, omit the unsafeWindow. That is, you would use:

on = false;
// OR
on = true;

to stop and start that script's action.


Note that, in Chrome, the script must be running in Tampermonkey, not Chrome's native userscript emulation.

How can I mimic Greasemonkey/Firefox's unsafeWindow functionality in Chrome?

contentWindow was available in Chrome 3, but removed in Chrome 4. Only possible solution for Chrome 4:

location.href="javascript:(function(){ alert('Hello'); })()"


Related Topics



Leave a reply



Submit