If you are Mozilla Firefox user you probably know what are addons and use some of them to make surf life more comfortable.
This article is about GreaseMonkey addon. I'd like to introduce it mostly for developers and want to share my knowledge cause I was surprised by its power, simplicity and functionality.
I tried to gather all useful technics, code snippets and documentation in one place to make it a good start page.
All code was tested on
Mozilla Firefox: 3.5.5
GreaseMonkey: 0.8.20090920.2
Firebug: 1.4.3
Shortly speaking, this addon can execute your javascript code on any page load in browser. Actually this addon offer javascript plugin functionality, you can very easily add your javascripts plugins to it. This javascript plugins can modify page on the fly by adding additional functionality. It can add or replace page content, change colors, styles, add new buttons, reformat text, etc
Using GM is much simpler, comparing to write own FF addon.
My favorite feature is: grab and submit page content using AJAX calls to ANY site. A short and simple script can extract for example stock exchange rates and post them to your site, while you are browsing. Or even more, browsing can be automated as well behaving like a spider.
This greatly improves user experience.
https://addons.mozilla.org/en-US/firefox/addon/748
click to "Add to Firefox" and that's it. Browser restart is needed. After installation you notice small smiling monkey face in lower right corner. That is it.
Also you can download various scripts to understand how they work. However most important and interesting aspects of this I will explain in this article.
Right click on monkey face and choose new user script. Enter information like on screenshot and click OK.
You favorite editor will show up. Paste script below and save it.
// ==UserScript==
// @name Test Script
// @namespace ME
// @description This script is for testing purposes
// @include http://*.google.*/
// ==/UserScript==
function xpath(query, object) {
if(!object) var object = document;
return document.evaluate(query, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
}
if (document.body) {
var tmp;
tmp = xpath("//div[@id='logo']");
tmp.snapshotItem(0).style.background = "transparent url(http://www.google.com/logos/newyear09.gif) no-repeat scroll 0% 0%";
tmp.snapshotItem(0).style.width = "320px";
tmp.snapshotItem(0).style.height = "138px";
}
Now navigate to google.com and you should see Christmas logo instead of default one. It is really simple.
tmp = xpath("//table[@id='village_info']/tbody/tr[3]/td/a");
tmp = xpath("//div[@id='content']/*/a"); // all links in content div
tmp = xpath("//td[@class='report_content']/table[@id='attacker']/tbody/tr[2]/td");
function returns tmp.snapshotLength - Number of elements found tmp.snapshotItem(i) - Element tmp.snapshotItem(i).innerHTML - content of element tmp.snapshotItem(i).getAttribute("href") - element attribute tmp.snapshotItem(i).parentNode - parent node
Function is called GM_xmlhttpRequest
Here sample usage:
GM_xmlhttpRequest({
method: 'POST',
url: 'http://site.com/script.php',
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
'Accept': 'application/atom+xml,application/xml,text/xml',
'Content-type': 'application/x-www-form-urlencoded; charset=utf-8;',
},
data: encodeURI("data=" + json(task.data)),
onload: function(responseDetails) {
if (responseDetails.status == 200 && responseDetails.statusText == "OK")
posterState = "success";
else
posterState = "error";
},
onerror: function(responseDetails) {
posterState = "error";
}
});
GM_setValue($variable, $value)
Supported types are: string, bool, and 32 bit integers. If you want to store other types like objects, I recommend to use JSON serialization to convert object to string and store it as string. There are a lot of JSON libraries on the internet, I use this one http://www.sitepoint.com/blogs/2009/08/19/javascript-json-serialization/
All stored values can be access via "about:config". Type about:config in browser location, in Filter text box enter greasemonkey. It will show all values.
One method is to join script comminity on http://userscripts.org/.
Another way just copy your script to any hosting and put link to .js file in html. Notice ".user." part in script name.
<a href="http://mysite.com/script.user.js">Click here to install</a>
By clicking on this link new windows will appear, that asks user to confirm installation. Like this one:
Interaction with user can be done by embedding UI into pages directly. Also GM offers basic UI functionality by adding menu items into GM menu with function:
// ==UserScript==
// @name Update test
// @namespace ME
// @include http://a32.me/wp-admin/
// @include http://ameoba32/project/
// ==/UserScript==
var VERSION = "1.0";
var SCRIPT_URL = "http://ameoba32/project/php/travian/www/js/update_test.user.js";
function updateCheck() {
try {
GM_xmlhttpRequest({
method: 'GET',
url: SCRIPT_URL + "?rnd="+Math.random(),
onload: function(result) {
if (result.status != 200) throw "status="+result.status;
var tmp = /VERSION[\s=]+"(.*?)"/.exec(result.responseText);
if (tmp == null) throw "parse error";
if (VERSION != tmp[1]) {
if (window.confirm("New version "+tmp[1]+" is available. Update ?")) location.href = SCRIPT_URL;
} else {
alert("No new version available");
}
}
});
} catch (error) {
alert('Error updating: '+error);
}
}
GM_registerMenuCommand("Check for update", updateCheck);
The metadata block appears in JavaScript comments and may appear anywhere in the top level Greasemonkey code scope of the script, but is usually near the top of the file. Changing the metadata of an installed script does not do anything, as this data is only accessed during installation. The script must be re-installed for these changes to take.
More information on http://wiki.greasespot.net/Metadata_block
This function prints debug messages even if script is run without GM, for debugging.
function _log( msg) {
if(typeof GM_log == 'function') {
GM_log(msg);
} else {
console.log( msg );
}
}
// Check if jQuery's loaded function GM_wait() { if(typeof unsafeWindow.jQuery == 'undefined') { window.setTimeout(GM_wait,100); } else { $ = unsafeWindow.jQuery; letsJQuery(); } }
GM_wait();
// All your GM code must be inside this function function letsJQuery() { alert($); // check if the dollar (jquery) function works }
<strong>UPDATE:</strong> Greasemonkey 0.8 introduce the @require metadata key that can be used to load JavaScript libraries into you user-script. See @require in the Scripting Reference for more info.
// ==UserScript== // @name jQueryPlay // @namespace http://www.example.com/jQueryPlay/ // @description Plays around with jQuery. Simply appends " more text." to string in the element with id sometext. // @include http://www.example.com/ // @require http://code.jquery.com/jquery-latest.min.js // ==/UserScript==
(function() { // This will be executed onLoad // Append some text to the element with id #someText using the jQuery library. $("#someText").append(" more text."); }());
<strong>That's it. </strong>Comments are welcome.
<strong>UPDATE: </strong>Recently I wrote script, take a look <a href="/2010/07/catsone-gmail-integration-plugin/" target="_self">here</a>.
## Links
<ul>
<li><a title="Greasemonkey install" href="https://addons.mozilla.org/en-US/firefox/addon/748" target="_blank">Install GreaseMonkey addon</a></li>
</ul>
<ul>
<li><a href="http://wiki.greasespot.net/Greasemonkey_Manual:API">API Documentation</a></li>
</ul>
<ul>
<li><a href="http://www.sitepoint.com/blogs/2009/08/19/javascript-json-serialization/" target="_blank">JSON serializer</a></li>
</ul>
<ul>
<li><a href="http://userscripts.org/" target="_blank">User scripts database</a></li>
</ul>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 1297px; width: 1px; height: 1px;"><span style="border-collapse: separate; color: #000000; font-family: Arial; font-size: 14px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"><span style="color: #808080; font-family: Tahoma; font-size: 13px;">arbitrary</span></span></div>