Greasemonkey compiler

Written by Adrian Holovaty on April 25, 2005

I've written a Greasemonkey compiler, which makes a Firefox browser extension (XPI) from a given Greasemonkey user script.

This is useful if you're a script developer and want to distribute your work to people without having to ask them to install Greasemonkey. It can also be a helpful starting point if you want to write a more advanced Firefox extension.

There's no support yet for the proprietary Greasemonkey JavaScript functions, but I've tested it on a bunch of existing user scripts that don't use those functions, and the generated extensions have worked nicely.

The compiler's Python source code is also available.

Comments

Posted by iant on April 25, 2005, at 8:41 p.m.:

this is great, looking forward to playing with this a lot more.

also, you made it onto radar today.

Posted by Jonathan Fenocchi on April 26, 2005, at 6:24 a.m.:

Sweet. Just sweet, man. Thanks!

Posted by Scott Johnson on April 26, 2005, at 7:56 p.m.:

Great work! It sure will be nice to be able to easily offer user scripts as extensions. Requiring GreaseMonkey to be installed is a tiny barrier, but I'm sure it prevents some from experiencing what these great scripts can do.

Posted by Jeremy Dunck on May 5, 2005, at 2:20 a.m.:

Please validate version number to be /^([0-9]+\.){0,3}[0-9]+\+?$/ which they apparently just changed to.

Posted by Anthony on May 5, 2005, at 7:05 a.m.:

Nice job, Adrian. I was having trouble getting the GreaseMonkey extension to work after I upgraded from Firefox 1.0.1 to 1.0.3, and this compiler solved my problem. Thanks!

Posted by Zheng Can on May 10, 2005, at 7:42 a.m.:

:)

Posted by Vitaliy on May 10, 2005, at 8:55 a.m.:

Super!!!!!!!!!!!!!!

Posted by Jeremy Dunck on May 13, 2005, at 8:51 p.m.:

Anthony,

FF 1.0.3 broke something in GM, and 0.3b fixed it. 1.0.4 broke something else, and 0.3.3 fixed that. We'll be broken again when trunk (1.1) lands. In general, Firefox seems quite unstable with regards to APIs which extensions depend on. We have not yet had a minor rev of FF that didn't break GM.

Nuts.

There was a recent discussion of this on Jesse Ruderman's site.

Anyway, stay on the latest rev of GM, and you should be good. ;-)

Posted by gracefool on May 19, 2005, at 2:25 p.m.:

Brilliant! This will encourage authors of simple javascript extensions to develop in parallel with greasemonkey, meaning less bloat and better compatability for greasemonkey users :)

Posted by Joe on June 2, 2005, at 2:45 p.m.:

Great tool!

I used it to build two extensions from GM scripts (Password Composer and RSS Panel).

Recently we all got alerted that Firefox 1.1 aka Deer Park will need for extensions to be updated.

Has GM Compiler already been tested with Deer Park? If not, what are the implications to be expected?

Cheers,

Joe.

Posted by yves2004 (at) gmail (dooot) co on June 27, 2005, at 1:20 a.m.:

I really like your GM compiler. When I want to view the source code to it, i get a 403 forbiddden...

Posted by Adrian on June 27, 2005, at 3:44 a.m.:

yves2004 -- Sorry 'bout that! I was making some server changes yesterday and inadvertently killed that file. It's back now.

Posted by Frédéric on June 27, 2005, at 6:29 p.m.:

Very good idea.

But i have a problem, i seem that whe can't use GM function in compiled scripts.

Is it true (i can have dreamed)?

Do you know a solution ?

Is it on work to be supported ?

On the worst case in can recode my GM_code for using conventional javascript (XMLHttpRequest)

In all case, thanks for geasemonkey compiler.

(i have a very poor english, excuse me for that)

Posted by alienn on August 11, 2005, at 7:40 p.m.:

Nice, but the only script I want to compile is the "terms highlighter" script that I have modified and it uses the GM_setValue function that seems not to work.

Is there a remedy ?

Thanks, alienn.

Posted by faultymonk on October 14, 2005, at 8:12 a.m.:

The guid generator seems to be broken.

Posted by William on October 14, 2005, at 10:01 p.m.:

I need a PHP tool like this.

Did you developed a version of your compiler in PHP in addition to the Python version ?

Posted by Adrian on October 14, 2005, at 10:41 p.m.:

William: Nope, no PHP. I encourage you to fall in love with Python.

Posted by Jon Wright on October 17, 2005, at 2:48 p.m.:

It's still giving max version as 1.0. But it's wonderful. Will it ever work on Mozilla/SeaMonkey? Is it just a question of editing the install.rdf or something more fundamental?

Posted by Buddy on December 4, 2005, at 4:59 a.m.:

Could you please change the max version so I can compile for firefox 1.5

Posted by |-|4{| on December 9, 2005, at 10:48 p.m.:

Buddy is right it does not work for 1.5

Posted by kallumama on December 13, 2005, at 5:23 a.m.:

Great job!

Can you add support for 1.5. I have a very simple script which should work in all FF versions but if I use the compiler above, it does not generate the extension for FF1.5 . Thanks a lot.

Posted by flotsky on December 22, 2005, at 12:11 p.m.:

I'm not convinced it is just a matter of upping the max version, I've just tried it on a script I've run through the compiler (you can unpack the .xpi file by renaming it to a zip file and extracting it. See Creating firefox extensions for more info.)

Posted by flotsky on December 22, 2005, at 3:02 p.m.:

Sorry to double post, but I've got it working now. I have created my extension using the compiler, then modified the install.rdf file, making sure that the required fields listed in the reference for Install Manifests were altered to mimic that style. So I used an e-mail address as an id, added a type field, changed the version numbers, and changed the tags [ RDF:Description ] to [Description]. I don't know which fixed it, but it did the job.

Posted by tekitou on December 24, 2005, at 2:32 p.m.:

// ==UserScript==

// @name Linkify Custom

// @version 1.0.1

// @namespace http://youngpup.net/userscripts

// @description Looks for things in the page that look like URLs but aren't hyperlinked, and converts them to clickable links. Supports http, https, ftp, ttp, tp, p

// @include *

// ==/UserScript

// Linkifyかってに改蔵

// https、ftp、h抜きURI(ttpとか)に対応

//

// Linkify:

// http://downloads.mozdev.org/greasemonkey/linkify.user.js

//

// History:

// Version 1.0.1:

// urlRegex \b 削除

// Version 1.0.0:

// https、ftp、h抜きURI(ttpとか)に対応

//

(function () {

//const urlRegex = /\b(https?:\/\/[^\s+\"\<\>]+)/ig;

const urlRegex = /(((h?t?t)?ps?|ftp):\/\/[^\s+\"\<\>]+)/ig;

// tags we will scan looking for un-hyperlinked urls

var allowedParents = [

"abbr", "acronym", "address", "applet", "b", "bdo", "big", "blockquote", "body",

"caption", "center", "cite", "code", "dd", "del", "div", "dfn", "dt", "em",

"fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6", "i", "iframe",

"ins", "kdb", "li", "object", "pre", "p", "q", "samp", "small", "span", "strike",

"s", "strong", "sub", "sup", "td", "th", "tt", "u", "var"

];

//var xpath = "//text()[(parent::" + allowedParents.join(" or parent::") + ") and " +

// "contains(translate(., 'HTTP', 'http'), 'http')]";

var xpath = "//text()[(parent::" + allowedParents.join(') or(parent::')+")]";

var candidates = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);

var t0 = new Date().getTime();

for (var cand = null, i = 0; (cand = candidates.snapshotItem(i)); i++) {

if (urlRegex.test(cand.nodeValue)) {

var span = document.createElement("span");

var source = cand.nodeValue;

cand.parentNode.replaceChild(span, cand);

urlRegex.lastIndex = 0;

for (var match = null, lastLastIndex = 0; (match = urlRegex.exec(source)); ) {

span.appendChild(document.createTextNode(source.substring(lastLastIndex, match.index)));

//ttp or tp or p

var uri = match[0].replace(/^(ttp|tp|p)/,'http');

var a = document.createElement("a");

//a.setAttribute("href", match[0]);

a.setAttribute("href", uri);

a.appendChild(document.createTextNode(match[0]));

span.appendChild(a);

lastLastIndex = urlRegex.lastIndex;

}

span.appendChild(document.createTextNode(source.substring(lastLastIndex)));

span.normalize();

}

}

var t1 = new Date().getTime();

//alert((t1 - t0) / 1000);

})();

Posted by Jeremy Dunck on January 15, 2006, at 5:42 a.m.:

There is an updated GM compiler which works for FF 1.5.

Posted by kruthy on January 20, 2006, at 10:54 p.m.:

Cool! A version that works with Firefox 1.5 would be most welcome.

Posted by flotsky on February 16, 2006, at 5:58 p.m.:

Thanks Jeremy for the update

Posted by Christooher on March 28, 2006, at 10:13 a.m.:

I just came across this and I would like to say thank you for such a wonderful resource! :-)

Comments have been turned off for this page.