Thursday, May 21, 2009

Graceful degrading of gists

I've written a small bit of jQuery based code to take <pre> tags with certain markers and upgrade them in place into pretty embedded gists. The idea is that the tag int the blog post is a <pre> instead of a <script>.

Unfortunately you may have noticed my blog was supposedly in violation of the TOS for the past few hours. I suspect this is due to adding this script. It has now been unflagged but if you'd like to use it be aware that Blogger didn't seem to like it much at first.

When you want to embed a gist paste in an HTML document you are provided with a <script> tag that has two document.write calls, one to add a stylesheet and the other to add a <div> tag for the actual paste. Usually you'd then want to complement this with a <noscript> tag containing a <pre> with a copy of the code so it displays in aggregators or systems with javascript disabled.

Here's how I embed a gist now:

<pre class="fake-gist" id="fake-gist-115368"><code>
use Moose;

has fun => ( isa => "Constant" );
</code></pre>

My script iterates all the elements of the class fake-gist, wraps them with the same styling as the gists, and then fetches the actual gist with syntax highlighting. When the gist has been fetched document.write is trapped and instead of appending the gist to the end of the document it calls a replaceWith on the <pre> tag.

This also makes the page load much faster, since the fetching of gists is no longer synchronous.

Feel free to download the script and get banned from Blogger yourselves. You'll also need to add github's embed.css and jQuery 1.2 or newer.

3 comments:

beppu said...

Nice.

Scott said...

I really like this technique, I'll probably end up using something like it! I don't agree with putting the "brought to you by GitHub" footer there because that's misleading until it's actually loaded, but that's just my personal taste.

You should store the old document.write in a local variable and call it like old_write.apply(document, arguments) since document.write can take an arbitrary number of arguments. Also, I think the content test should be more specific (you can use indexOf rather than a regex). You can test for the stylesheet (link href="gist.github.com"), throw it out, then for the gist (div id="gist-). Otherwise this will break document.write on anything containing "gist" :-).

Thanks!

nothingmuch said...

Hmm, fair enough, I wanted to preserve the link and ended up copying the whole thing.

Want to fork and make those changes? I would like to apply them all =)