Eli Grey

Jetpack API

Mozilla Labs’ latest creation, Jetpack, is a great way to extend Firefox. It currently has a poorly documented API that doesn’t mention all of the public methods and fields. Due to Mozilla Labs’ decision of not putting the API documentation on MDC or the MozillaWiki, I cannot update the documentation myself. Therefore, I will list all of Jetpack’s documented and undocumented features as of version 0.1.2 in this blog post.

(Not) Assigning Properties

You can’t do things like jetpack.tabs.focused.contentWindow.foo = "bar". I find this much too restrictive, as it hinders a developer’s ability to make an API for a webpage to communicate with a jetpack to do things that need more privileges. Ironically, it seems that jetpacks have full access to Firefox’s XPCOM (Components.*, ect.) which means, with a little hacking, it may be possible to bypass this restriction. The follow code shows an example of getting an nsIAlertsService and using it instead of jetpack.notifications.show.

var body = "Some text",
title = "Notification",
icon = "http://code.eligrey.com/favicon.ico",
classObj = Components.classes['@mozilla.org/alerts-service;1'],
alertService = classObj.getService(Components.interfaces.nsIAlertsService);
alertService.showAlertNotification(icon, title, body);


textContent in IE8

I was creating a testcase for a bug that is present in every browser and I noticed IE still doesn’t support textContent as of IE8. I don’t like having to make code that supports both innerText and textContent so I implemented the standard myself using IE8’s support for ECMAScript 3.1 accessors. The following is all the code that you need to make textContent work in IE8.

if (Object.defineProperty && Object.getOwnPropertyDescriptor &&
     Object.getOwnPropertyDescriptor(Element.prototype, "textContent") &&
    !Object.getOwnPropertyDescriptor(Element.prototype, "textContent").get)
  (function() {
    var innerText = Object.getOwnPropertyDescriptor(Element.prototype, "innerText");
    Object.defineProperty(Element.prototype, "textContent",
      { // It won't work if you just drop in innerText.get
        // and innerText.set or the whole descriptor.
        get : function() {
          return innerText.get.call(this)
        set : function(x) {
          return innerText.set.call(this, x)

Save it as textContent.js and then include the following code to use it.

<!--[if gte IE 8]><script type="text/javascript" src="textContent.js"></script><![endif]-->

Why you shouldn’t use XDomainRequest

I just recently installed Windows and downloaded IE8 again and it seems that pmxdr works fine with the exception of one small MessageEvent.source bug in the host library that I fixed in version 0.0.5.

I went to check out if the XDomainRequest examples I created worked, and to my astonisment, they ALL failed except for the simplest example. It turns out, contrary to what I assumed of it only not supporting responseXML, XDomainRequest also doesn’t support much of the basic HTTP header functionality offered in XMLHttpRequest, such as setRequestHeader, getResponseHeader, and getAllResponseHeaders. This means that my implementation of XDomainRequest actually offered more functionality than IE8’s implementation.

Due to this, I have changed the XXDomainRequest library to implement a generic XDR constructor and I have renamed the library from XXDomainRequest to libxdr. The examples have been changed to use new XDR() instead of new XDomainRequest() so now every example works in IE8.

XDomainRequest is no longer IE-only

XDomainRequest is Internet Explorer 8’s cross-domain request function. It would be easy to add support for it in Firefox 3.5 using native cross-domain XMLHttpRequests, but that wouldn’t work in Firefox 3, Opera 9.6-10, and Safari 4. I have created a library named XXDomainRequest (means “Cross-browser XDomainRequest”) that builds on the pmxdr client library to create a fully API compatible version of XDomainRequest. Go to the XXDomainRequest project page to see (and run) the examples that request resources on code.eligrey.com.

APNG feature detection

I have made a simple script that utilizes the HTML5 <canvas> API in only 9 functional lines of JavaScript to detect if a browser supports APNG images. It can be useful for deciding when to serve a client browser APNG images instead of GIF images.
This will set the variable, apng_supported to true if the browser supports APNG.
I have also created a demo that uses this script.

(function() {
	"use strict";
	var apngTest = new Image(),
	ctx = document.createElement("canvas").getContext("2d");
	apngTest.onload = function () {
		ctx.drawImage(apngTest, 0, 0);
		self.apng_supported = ctx.getImageData(0, 0, 1, 1).data[3] === 0;
	// frame 1 (skipped on apng-supporting browsers): [0, 0, 0, 255]
	// frame 2: [0, 0, 0, 0]

HTML 5 dataset support

Update: Getting (not setting) data-* attributes through Element.dataset now works in IE8 with the help of Xccessors.

I have made an implementation of HTML 5 dataset (data-* attributes) support that almost conforms to the HTML 5 spec* and works in Firefox 1.5+, Opera 9.5+, Safari, and Google Chrome. It uses getters and setters to simulate a psuedo-native HTML 5 dataset API. The code is licensed CC GNU LGPL and can be downloaded here. I have uploaded a demo (also in XHTML 5) that you can try out. The script includes these extra functions: Element.removeDataAttribute(name), Element.setDataAttribute(name, value), and Element.setDataAttributes() (all explained below).

*You cannot set new items the standard way like Element.dataset.name = value (already existing items can though). You either have to add new items by doing Element.setDataAttribute(name, value) for single additions and Element.setDataAttributes(object full of {name, value:String} pairs) to add multiple items at once. Instead of delete element.dataset[name], you must use element.dataset[name] = undefined or Element.removeDataAttribute(name) to remove data-name. Example of setting values:

var foo = document.createElement('div');
foo.setDataAttributes({'bar':'blah', 'lorem':'Lorem ipsum.'});
foo.dataset.bar == 'blah';
foo.dataset.bar = 'eligrey.com';
foo.dataset.bar == 'eligrey.com';
foo.setDataAttribute('foobar', foo.dataset.lorem);
foo.dataset.foobar == 'Lorem ipsum.'

CiteDrag drag and drop script

Firefox 3.1 beta 2 recently added support for the standard drag and drop model (also with some extra Mozilla-only ones). I had an idea to automatically add citation info to text dragged from websites to plain and rich text editors using this newly supported API. I named the finished script CiteDrag, which requires no setup other than adding a single script tag anywhere in your website’s page. CiteDrag is licensed GNU LGPL and free to download in two flavors: CiteDrag and CiteDrag + Drag Image. CiteDrag + Drag Image is all of the normal CiteDrag code with some additional code to give a fancy canvas-generated drag image that shows the text content being dragged. CiteDrag is mostly useful for when someone blogs about another person’s blog post. Having the text automatically go into a cited blockquote and having a link back is very useful. I have installed CiteDrag on this blog and I have a demo of it and a rich text area you can use to test out CiteDrag fully.

Here are some examples of what it does when you drag various data types to various input areas: (Note wherever it says title, it will be replaced with the host name of the source page if there is no page title)

  • Drag a link or image (or linked image) to a normal text input: { [link URI] or [image URI] } via {source title} ( {source URI} )
    • Example:  http://example.com/ via Foobar ( http://foo.bar/post/example.com-ftw/ )
  • Drag a link or image (or linked image) to a rich text input: { [clickable link to link URI] or [image URI] or [clickable image linked to link URI] } via {clickable link to source page with title as text}
  • Drag formatted or non-formatted text to a normal text input: “{Text dragged}” ― {source title} ( {source URI} )
    • Example:  “Lorem ipsum dolor sit amet.” ― Eli Grey ( http://www.eligrey.com/ )
  • Drag formatted or non-formatted text into a rich text input: The dragged text goes into a <blockquote cite=”{source URI}”> and after the blockquote is ― {clickable link to source page with title as text}
    • Example:

      Lorem ipsum dolor sit amet.

jData – publicly share data

jData is a new (extremely tiny) library for sharing data about yourself everywhere without a website needing permission/URIs/ect. It is like having a globally accessible localStorage. It is accessible at jdata.eligrey.com in two different API flavors: postMessage and HTTP queries. It only works in browsers that support window.postMessage (ie. advanced browsers like Firefox 3 and the WebKit nightlies) and sorta works in IE 8 beta 2. I may add Google Gears support someday.

What is jData? – Think of the data stored on jData like cookies with no size limit; cookies that can be accessed by any website on the internet. It’s so lightweight that the postMessage API is exactly 300 bytes.
Why make this? – This would be a good resource for storing info about yourself that you are okay with any website on the internet knowing.

Hypothetical situation: Facebook started storing your name (with your permission) to jData.fullname. Then the people who run MySpace think this is a good idea and implement it too. Then other websites start checking jData and see if jData.fullname has been set already and pre-fill the corresponding input text box with your name on a sign up page.


More rotⁿ fonts

I previously made two rot13 DejaVu fonts (rot13 DejaVu Sans and rot13 DejaVu Serif) so I thought I might as well make fonts for the other less-widely used rotn ciphers. All of these fonts are based on the open source DejaVu fonts. These are by no way official DejaVu fonts and are just remixes by me under the same license as the normal DejaVu fonts. If you want to distribute the fonts on your website, feel free to do so, and you could optionally link back to me if you want. I don’t care what you do with them. As with all the rotn ciphers, using them twice (ie. using the rot47 font to view rot47 encoded text) will result in the unciphered text. It’s a cipher that decodes what it encodes by doing the same rotations. The example pages require a modern browser that supports webfonts, such as Firefox 3.1 beta or Safari 3.1.2.

Noteboard tweaks and Safari support

I am happy to say that Noteboard now supports Firefox 3+ AND Safari. It doesn’t support the current release of Safari so you have to use the Safari 3.1.2 nightlies as those builds include localStorage. Technically, I should be also be able to make Noteboard work with IE 8 beta 2 due to it also supporting localStorage, but I don’t want to waste my time making fixes for IE.

Now on to the tweaks for version 2.0.1:

  • Documents can now have custom titles instead of having the document name be the title.
  • The title quickly changes to “Noteboard” and changes back when you push Ctrl + D to bookmark Noteboard.
  • I stopped using uneval function built-into Firefox and took part of the JSON.stringify function from json.org’s JavaScript JSON script.
  • I added and changed these keyboard shortcuts:
    • Import is now Ctrl + Alt + 1
    • Export is now Ctrl + Alt + 2
    • To change the current document’s title, push Ctrl + Alt + T
  • Starting the open a document prompt (Ctrl + Alt + O), clicking OK, and leaving it blank opens up the shortcuts page.
  • The shortcuts page is no longer stored on your localStorage and is now a protected static document that can’t be edited/deleted.
  • A lot of code tidying up.