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

# What is Greasemonkey

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.

Installing addon

Installing addon is very simple in Firefox, just navigate to

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.

Read made scripts

Userscripts.org has thousands of scripts, lightweight Web Browser applications, created by a community of thousands of developers, that enrich your experience of web sites you already use.

http://userscripts.org/

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.

# Script development

Writing first script

I love Google as search engine, but it's logo is really boring. I would like to see something better, they have a lot of other good logos here http://www.google.com/logos/. So lets write small script that replaces default Google logo with another one.

Right click on monkey face and choose new user script.  Enter information like on screenshot and click OK.

New Greasmonkey script windows

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.

Parsing data

As you noticed I used xpath function to get access to DOM element. This is very convenient way of doing this comparing to regular expression. Here are some more examples:

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

Submit data to other server

As you know AJAX prohibits data exchange with sites from domain not matching current site. GM has function to overcome this and make AJAX requests to any arbitrary site.

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

Permanent storage

Greasemonkey allows you to store variables permanently. They will survive page reload and even browser restart. To use this functionality 2 functions exists: ``` GM_getValue($variable) ```
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.

Script installation

Okay, you wrote your cool script and now want to show it to the world to use it. You need installation. Scripts are installed in a very simple manner.

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:

GreaseMonkey install new script

User interface

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:

GM_registerMenuCommand

Script autoupdate

This simple thing can add "check for update" functionality for your scripts. It is very simple, first downloads script and checks version, if it does not match, propose to update by navigating to script url.

// ==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);

Metablock

The metadata block is a section of a user script that does not execute any code, but describes the script. It contains the script name, namespace, description, and include and exclude rules.

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

# Misc stuff

How to change default script editor

Default script editor path is stored in about:config, greasemonkey.editor variable.

Debugging and logging

If you are developer and use Firefox, you probably has Firebug installed. Firebug is a very feature rich javascript debugger. Greasemonkey scripts can be easily debugged using firebug. Also you can use Firebug console for logging:

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

Greasemonkey and jQuery

This is a simple snippet that helps us load the jQuery power into our userscripts with Greasemonkey. ``` // Add jQuery var GM_JQ = document.createElement('script'); GM_JQ.src = 'http://jquery.com/src/jquery-latest.js'; GM_JQ.type = 'text/javascript'; document.getElementsByTagName('head')[0].appendChild(GM_JQ);

// 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>