I have the following code in test.js which is run right before </body>:
alert(\'stovetop\');
alert(greasy);
I have the following code in test.user.js:
(function () {
\'use strict\';
var greasy = \'greasy variable\';
document.title = \'greasy title\';
}());
\'stovetop\' gets alerted so I know the page javascript works, and document.title
gets changes so I know that the script javascript works. However, on the webpage I get the error:
Error: ReferenceError: greasy is not defined Source File: /test.js
How from the webpage do I access the variable set by Greasemonkey and how about 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://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://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://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:
- You can test these script against this page (jsbin.com/esikut).
- With no sandbox,
unsafeWindow
and window
are the same.
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
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.
Your variable greasy
is defined in the scope of the anonymous function. You cannot access greasy
even in your userscript, unless it is part of your function. Example:
(function(){
var foo = 5;
alert(foo);
}();
alert(foo); //ERROR, because foo is undefined outside of the function.
Do it this way:
var foo = 5;
(function(){
alert(foo);
}();
alert(foo);
Also, why are you putting all your code in an anonymous function and then executing it?
You can also use localStorage:
localStorage.setItem(\"numberOfThings\", \"42\");
localStorage.getItem(\"numberOfThings\");