Communication between HTML and your extension

See also Interaction between privileged and non-privileged pages.

Communication between an HTML page and and extension

After building a sample extension by reading carefully and following the complete instructions for Building an Extension I was able to get an extension that could display something on the status bar. What I wanted to do was have an extension "look" for something on an HTML page and if it found that something perform some operation on the found thing and then update the status bar with the results of the operation. With a lot of help from irc:// and irc:// I was able to get it running pretty well, but I still would rather have the client less responsible for pinging the extension to "look" for what is on the page.

What I tried
  • My first attempt was trying to create an XBL component. From what I gather, XBL components are more designed for creating custom components and their specific component behavior rather than trying to impose some kind of messaging on existing components.
  • Next I started investigating events, there are only a handful of events and the W3C documentation is pretty complete.

The basic problem with the event model is probably due to what I was trying to do. In my HTML I have an input element in a form. I set the onBlur action to a little javascript function that performed a standard AJAX request to get a result. The onreadystatechange was set to another little javascript function that would update a specific element on the HTML page with the result. The result of the AJAX request was the something that I wanted the extension to find. There were only a handful of events that seemed relevant (Load, Change, DOMInsertNode, DOMInsertNodeIntoDocument, DOMActivate) and I tried them all in many different ways. Some of the events only apply to certain types of elements so I included trying to modify the result of the AJAX request to be of the appropriate element type (img, which supports "onLoad," rather than span, which doesn't, for example).

The problem with the events is the timing. I wasn't sure about the difference between the capture or bubbling flag that you pass to addEventListener but every time I would catch the event in the extension, the element from the AJAX request wasn't fully updated into the HTML page. What that meant is that everytime the extension went looking for the element, it wasn't there yet.

As a last ditch effort I tried setting a timeout using setTimeout when I got the event in the extension to wait a few milliseconds before looking for the desired element. This was non-optimal and the timeout wasn't very reliable for some reason. Sometimes I would get the timeout, sometimes I would'nt.

What I ended up with

Some helpful information on the irc channel led me to believe that a custom event might help. I started to research custom events on Google but everything that I found was far too complicated for what I wanted to achieve. Eventually I put the creation of the custom event into the stateChanged function that was handling the receipt of the AJAX request. After the HTML component was update with the result of the AJAX request, I created and dispatched the event like this:

   var event = document.createEvent("Events");
   event.initEvent("my-custom-event", true, true);

In the code of the extension that catches the loading of a new page I added this code:

   var doc = aEvent.originalTarget; // doc is document that triggered "onload" event
   // do something with the loaded page.
   // doc.location is a Location object (see below for a link).
   // You can use it to make your code executed on certain pages only.
   if (doc && doc.addEventListener)
     doc.addEventListener("my-custom-event", myExtension.customReceived, false);

Since the event is dispatched after the element in the HTML is updated by the statusChanged function, the element that extension is looking for is there to find.