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

(more…)

ECMAScript 5 accessors

A while ago, I created a JavaScript library named Xccessors, which implemented the legacy non-standard accessor (getter and setter) methods in IE8. I initially created two different libraries and decided that the library that implemented the legacy methods would be more useful at the time due to no changes needed in a JavaScript program’s code to add accessor support for IE. I never released the second one that implements the ECMAScript 5 (formerly 3.1) standard accessor methods so I’m releasing it now. There can’t be two different libraries with the same “Xccessors” name, so I am also renaming the libraries accordingly to what they implement. The new names are Xccessors Legacy and Xccessors Standard.

Here are two examples of using Object.defineProperty and Object.getOwnPropertyDescriptor:

Using accessors

(function() {
// this creates a document.foo accessor
    var foo = 0;
    Object.defineProperty(document, "foo", {
        get: function() { return foo },
        set: function(x) { return foo += x }
    });
})();
 
document.foo = 5;
(document.foo = 4) === 9;
//Object.getOwnPropertyDescriptor(document, "foo") is {set:[...], get:[...]}

Setting a property

// this is the equivalent of window.foo = "bar";
Object.defineProperty(window, "foo", {value: "bar"});
window.foo === "bar";
Object.getOwnPropertyDescriptor(window, "foo").value === "bar";
window.x = 0;
Object.getOwnPropertyDescriptor(window, "x").value === 0;

Object.getPrototypeOf

The addition of Object.getPrototypeOf in JavaScript 1.8.1 reminded me of John Resig’s Object.getPrototypeOf implementation that uses constructor property even if it has been modified. If the constructor property has been modified, it can be reset by deleting the property. An easy way to detect if a property like constructor has been modified is check if the object’s hasOwnProperty method returns true when passed "constructor". This could have been modified too, so the safest bet it to call Object.prototype.hasOwnProperty. Though the thing is, you can’t even trust that, so you just have to assume that it isn’t function hasOwnProperty() false;.
Now I bet you’re wondering, why I should go through all this trouble to check if the constructor property is modified. This is because just storing the constructor, then deleting, checking, and restoring it will set the constructor property if it wasn’t already set, which can mess with iterators. Of course you could just delete it and hope that if it was set, it wasn’t important, but that won’t always end up well.

You can download my implementation at gist.github.com/154398.

Namespacing properties in JavaScript

Namespacing properties is a great way to make a JavaScript library produce extendible objects. Namespacing in JavaScript can be done by prefixing namespace:: before object and property names. Unfortunately, namespacing is only supported in JavaScript 1.6 and higher, which is currently only implemented in SpiderMonkey (Firefox’s JavaScript engine) and Rhino with E4X enabled. Namespaces should have a toString method that returns a string of the same name (Foo.toString() == "Foo"). In Firefox, the @mozilla.org/js/function namespace (“function”) seems to be the default at which everything is under. For example, function::document == this.document and x = "@mozilla.org/js/function"; x::document == function::document. Also, anything with a blank string representation behaves the same way as long as it’s being used in a property, for example:

var foo = "@mozilla.org/js/function", bar = "";
try { // using try..catch because the error still fires in a typeof statement
    foo::document; // works fine
    bar::document; // error
} catch(err if err instanceof ReferenceError) {
    // err.message == "reference to undefined XML name document";
}
this.bar::document == this.document;

The following example shows a naming conflict that can be solved using namespaced properties. In the examples, the fictional libraries, libSpaceTime and libDimensions are loaded. libDimensions adds a Size global and creates a ‘dimensions’ setter on Object.prototype that accepts various inputs to change the width/height/depth/ect. of something. libSpaceTime introduces the SpaceTime global. When a universe is created, the dimensions setter changes the number of dimensions the universe has. The width/height/ect. of a universe are automatically set (but can be changed) from the matter property.
(more…)

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

Extending Object.prototype.toString

Object.prototype.toString is a great way to find the “class” of an object, but it only works for the native constructors like String, Function, ect. Due to this limitation, I have created an open source JavaScript library named toStringX which adds support for non-native constructors so things like the string representation of new Foo are [object Foo] instead of [object Object]. I have also made some examples that you can run to see the toStringX library in action that you can find in the toStringX repository README.

Reusable pmxdr instances

I just released version 0.0.4 of the pmxdr client code to support reusable instances where the same iframe can be used for mutiple pmxdr requests to a domain. It’s still the same interface, but you need to call pmxdr.request() instead of pmxdr() to do a normal request. Instances are created with new pmxdr(host) where host is any URI from the website you want to request (pmxdr figures out where the API is located automatically). Then just call the request method on the instance once the interface iframe has loaded, which you can find out when instance calls it’s onload method once it’s loaded if you set it. The request method now also accepts an array of requests. To start loading the instance, you call it’s init method. To remove the interface frame, you call it’s unload method. Another thing added is the ability to completely remove pmxdr using its destruct method, which removes all event listeners and deletes the pmxdr variable. This does not delete any still-existing interface frames so don’t forget to unload them when you are done to avoid memory leaks.

Using reusable instances saves much more overhead than repeatedly re-requesting a website’s pmxdr host api. When I updated the demo to use a single instance for requesting eligrey.com, it started finishing a multitude of times faster. This is an example of using a reusable instance that uses one interface to make three requests:

var exampleDotCom = new pmxdr("http://example.com");
exampleDotCom.onload = function() {
  this.request([
    {
      uri     : "/foo.html",
      callback: responseHandlers.foo
    },{
      uri     : "/bar.html",
      callback: responseHandlers.bar
    },{
      uri     : "/baz.html",
      callback: responseHandlers.baz
    }
  ]);
};
exampleDotCom.init()
// after all responseHandlers[x] are called, call exampleDotCom.unload()

Custom error constructors

Most of the time, the standard six native error constructors and the one generic error constructor are not specific enough for an error. What if you want your library to throw a custom SecurityError if it detects an XSS vector on a website? I made a function to create such constructors that behave the exact same way the native error constructors, like SyntaxError by using methods like Error.prototype.toString and the standard error object format. This code makes throwing a custom fake error constructor made with ErrorConstructor("SyntaxError") have the same output as a native SyntaxError in a JavaScript shell. I’ve tested the code in Firefox 3/3.5 and Opera 9.6 and it seems to work fine. Comment and say if it works in your browser too.

function ErrorConstructor(constructorName) {
  var errorConstructor = function(message, fileName, lineNumber) {
  // don't directly name this function, .name is used by Error.prototype.toString
    if (this == window) return new arguments.callee(message, fileName, lineNumber);
    this.name = errorConstructor.name;
    this.message = message||"";
    this.fileName = fileName||location.href;
    if (!isNaN(+lineNumber)) this.lineNumber = +lineNumber;
    else this.lineNumber = 1;
  }
  errorConstructor.name = constructorName||Error.prototype.name;
  errorConstructor.prototype.toString = Error.prototype.toString;
 
  return errorConstructor;
}

Usage: ErrorConstructor([constructorName])
Note: If no constructorName is specified, the default of Error.prototype.name is used
Usage for generated error constructor: errorConstructor([message[, location[, lineNumber]])

Examples:

var SecurityError = ErrorConstructor("Security Error"),
MarkupError = ErrorConstructor("(X)HTML Markup Error");
//these will both throw a SecurityError starting with "Security Error on line 83:"
var xss_error = "Possible XSS Vectorn
 JSON XHR response parsed with eval()n
 Recommended fix: Parse JSON with JSON.parse";
throw new SecurityError(xss_error, "/js/searchResultsJSONloader.js", 83);
throw SecurityError(xss_error, "/js/searchResultsJSONloader.js", 83);
//these will both throw the following MarkupError:
//"(X)HTML Markup Error on line 1: Invalid DOCTYPE"
throw new MarkupError("Invalid DOCTYPE");
throw MarkupError("Invalid DOCTYPE");

pmxdr: postMessage cross-domain request library

pmxdr is a cross-domain HTTP request JavaScript library. pmxdr stands for postMessage cross-domain requester. As the name implies, it makes use of the HTML5 postMessage API to make HTTP requests. It requires that a pmxdr host be on the target domain and it respects all HTTP access control headers, even on browsers that don’t support them but do support postMessage, like Firefox 3.

You can download the pmxdr client library and the pmxdr host library (includes an example .htaccess file to help Apache users with PHP set it up) under the latest GNU GPL license and an MIT-style license. The host library must be able to be accessed from /pmxdr/api to be able to interact with the client library.

Read more at the pmxdr project page and try out the demo of it in action.

The following is a very simple example of how to use pmxdr to do a cross-domain POST request (impossible with the normal method of inserting a script tag):

// The requesting domain is example.net
// example.net doesn't want to give any control to example.com
pmxdr.request({
  method   : "post",
  uri      : "http://example.com/search.json",
  data     : "q=foo",
  callback : loadSearchJSON
})

Usually, in this hypothetical example, example.net would have to put a script tag with an src of http://example.com/search.json?q=foo&callback=loadSearchJSON and give example.com full control of example.net. This provides a secure cross-domain way to use APIs like this.

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;
	};
	apngTest.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACGFjVEwAAAABAAAAAcMq2TYAAAANSURBVAiZY2BgYPgPAAEEAQB9ssjfAAAAGmZjVEwAAAAAAAAAAQAAAAEAAAAAAAAAAAD6A+gBAbNU+2sAAAARZmRBVAAAAAEImWNgYGBgAAAABQAB6MzFdgAAAABJRU5ErkJggg==";
	// frame 1 (skipped on apng-supporting browsers): [0, 0, 0, 255]
	// frame 2: [0, 0, 0, 0]
}());