Showing posts with label Greasemonkey. Show all posts
Showing posts with label Greasemonkey. Show all posts

2010-08-23

Friendlier github commits pages

I figured I should announce the news of a much improved github commits page I have been tinkering with for a while, that lets you unfold full details about commits (individually, or in batch) without leaving the page. A screenshot of what the Greasemonkey master branch commits might look like with a few unfolded:

screenshot of github commits page with the user script active

Usage is intuitive; just click anywhere in a commit that isn't already a link, and the commit will load in place (unless already loaded) and unfold its whole changeset, or refold itself again, when clicked a second time. Similarly, individual files changed can be folded and unfolded much the same way, though only by clicking their headers (I often want to copy and paste stuff from diffs, so no click magic there). To unfold or refold every commit on the page, either hit "f", or click the "(un)fold all commits" link at the top or bottom right of the page.

This user script (install link, userscript.org page with docs and complete change log) is incidentally compatible with extensions like AutoPagerize too, in case you prefer scrolling for content to finding and clicking "Older" (h) and "Newer" (l). And if you just want to try it out without installing anything, try this bookmarklet on any github commits page.

And it's all done by a hundred lines of jQuery, about a dozen lines of css and another dozen lines of Greasemonkey / Chrome portability code that breaks out of their respective sandbox environments to run what the script needs to run in the context of the web page itself.

That latter piece is useful too, by the way, modeled on a trick Anthony Lieuallen came up with for the Greasemonkey wiki at some point. This is what it looks like, including full docs:


The above-referred jQuery is already loaded by github's page template, so I don't need to bother grabbing or shipping one of my own. If you are hacking a more hostile site, and run Greasemonkey you might want to add a // @require http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js line to your script header instead (I haven't tested, but if you try to run jQuery in the mozilla javascript sandbox anything beyond really basic stuff fails due to the common pitfalls that jQuery, sanely, does not much attempt to evade).

All above code is freely poachable (read: MIT license) at github, with as much or little attribution as you like. I would of course be especially happy to see the github people adopt this for their default page templates, as it's really useful stuff. Share and enjoy!

2009-05-10

Little projects I'm warming up to

I've been cooped up a lot between real life, work and a low energy budget for a while now, but think I'm getting a hankering for some ideas I'd like to develop or see developed, again. Here's a little off-the-top-of-my-head list of a few of them, small and large:

  • Data SVGs: Craft a few examples of how to encode data in its original raw form in SVG graph(ic)s and have the SVG render them right via coordinate transforms. Forward goal: get Wikipedia to incorporate this principle in their guidelines for how to represent data in vector graphics. Erik Möller (Deputy Director at Wikimedia Foundation) and Brion Vibber (CTO) both found this a cool idea. I ought to at least blog it if I'm not going to be the main advocate rallying people around the idea.
  • Migrate Kronos Utils (user script here), which I'm not maintaining or developing as much as I used to, and other ikariam related hackery I've done at some time or others, to github, so others that want to hack at it have an easier time forking it. I apparently started doing that, at some time or others, in an ikariam repository, and then promptly forgot about it. *pushes recent changes*

    So I guess this pretty much boils down to migrating my updates off of Google Code and onto githubg. And figuring out how to have my pushes and/or commits trigger a tweet to @ikariam_tools, which apparently people have already spotted and started following, despite its severe lack of content. :-) Does anyone remember how that is done? I seem to recall some setting somewhere for it at github, but wasn't successful finding it in all of a minute's scouting around.

    Oh, and figuring out how to have vc-mode in Emacs do git things.
  • Run the jQuery test suite from a Greasemonkey script, to figure out how much breaks under the Firefox javascript sandbox. It'll be nice to have fine grained data on which parts that remain useable and which don't, so maybe someone would even care to fix the latter.
  • Revive the live Exhibit web scraper thing I crafted some year ago and never got to the point of happiness with where I ever blogged about it. With recent development in Ext JS, it seems it could get a nice UI indeed, this time in a pop-open window, so I don't have the CSS invasion problem, and don't invade the DOM we're trying to scrape.
  • Don't fold comments on pages we arrived at through a permalink with a fragment pointing to something in the foldable section (at that point, we know we foremost wanted to read that specific comment, and not the article, so don't tuck it away). Edit: Done!

Taking down that specification in text instead of code seems indicative I'm not really in a coding mood today and ought to go have lunch. See you around!

2008-07-24

Fun with Greasemonkey: @require

After the release of Greasemonkey 0.8, the door is open for @require helper libraries, the user script take on Ruby's require, or the C family's #include pre-processor directive. For security reasons, the required library is downloaded a single time at script installation time, and from a functional perspective, is equivalent to pasting the script or scripts referenced at the top of your script, in the order of the @require lines listed. (==UserScript== headers in the referenced files are presently ignored, so a library may not yet use @require or @resource lines of its own.)

@require in practice makes user scripting scale down better, which is essentially to lower the threshold towards getting a job done, to a level where implementation cost to scratch an itch is so low that rather than feeling that mild annoyance with something twice, you address the issue once, and never see it happen again -- on that site, or the web at large. We are still far from there (in as much as "getting there" would ever happen -- that threshold can always be chipped off further, I assure you) -- but @require is healthy progress.

This is what the feature can look like in an example script of mine which adds image captions to online comics, by default Dinosaur Comics and xkcd (expect another upcoming post about $x and $X):
// ==UserScript==
// @name      Image title captions
// @namespace http://code.google.com/p/ecmanaut/
// @require   http://ecmanaut.googlecode.com/svn/trunk/lib/gm/$x$X.js
// ==/UserScript==

I'll be sharing some of my own helpers here, in a little series of "Fun with Greasemonkey" posts. I encourage you to write, and share, your own, on your blog, as well. User script authorship is a very social form of software, especially when you share your results on userscripts.org, and your best practices, for instance by way of blogging.

2007-08-22

Extending Greasemonkey by way of getters

Javascript getters and setters may be one of the most useful upcoming language features today (already working in some browsers, including Firefox), but google the feature and you will be swamped with articles and posts, not on how to put them to good use, but how to defend against malicious use of them for web pages tripping (Firefox / ditto extension) security holes. It's really just John Resig that stands out of the crowd, showing how it is done, suggesting good uses, and teaching the stuff.

Getters and setters are a Javascript 1.6 (IIRC) language feature that lets you provide interfaces that look and feel like DOM 0 interfaces, where you read and set a variable or property like document.title or document.links, and receive something that may or may not require computation, compositing and much else behind the scenes. The only news is that you can now implement things like the location object (set href and affect all the other properties in one go) from mere javascript and that the syntax is even rather friendly, by javascript standards:
var myLoc = (function() {
var url; // private variable hidden in the function closure

return {
toString: function() {
return this.href;
},
get href() {
return url;
},
set href(h) {
return url = h;
},
get prototcol() {
return url.match(/^.*?:/)[0];
},
set protocol(p) {
url = p + url.match(/^.*:(.*)/)[1];
return p;
}
};
})();
- which will yield you an object with an href and a protocol property you can tweak, just like any other, and see changes reflect to the other property, what you see if you alert(myLoc), and so on. It's a dream for making APIs that don't feel like java pushed down your throat with a ten-foot pole.

I've been meaning to add some features to Greasemonkey to grant it proper introspection (as all great software systems are introspective), for the Greasemonkey header block, and once I thought twice about it, for the source code at large. Something like a self object, with a "source" property for the code and a headers property for the parsed headers -- so self.headers.include would be the array of all @include headers, and so on.

I wanted that feature to give anybody the option to make their own cool extensions and libraries to Greasemonkey, making use of structured information -- much like an @xpath feature I've been noodling on on and off over the past few months to make GM scripts much more maintainable (and quick to write, and, optionally, self deprecating).

Anyway, the natural way of implementing this is via getters, and I was just about done when I hit a wall with Mozilla's extension API which wouldn't let the script executing in the Greasemonkey sandbox read my exposed getter variable (at the time named GM_headers): it threw a "Permission denied to get property Sandbox.GM_headers" exception when code accessed GM_headers, and that was that. Is this feature crippled for extensions wanting to provide getter / setter APIs from javascript code, or do I miss some incantations to bless the sandboxed code to read that?

The (hopefully) full picture of relevant details, surrounding my implementation:
var safeWin = new XPCNativeWrapper(unsafeContentWin);
var sandbox = new Components.utils.Sandbox(safeWin);
// ...
sandbox.__proto__ = {
get GM_headers() {
return headers.get();
}
};
sandbox.__proto__.__proto__ = safeWin;
This misfeature is also what stopped us from getting a responseXML property on the GM_xmlhttpRequest response object, earlier this spring. Any Mozilla hackers out there with solutions, knowledge or even just input on this? Your help and insights on this would be most valued.