Adding new microformats to Operator

In this post, I’m going to talk about adding a new microformat to Operator. We’re going to add partial support for hResume. In the process, you’ll learn some of the APIs that are available to you in the Microformats class.

The APIs in the Microformats class can be divided into three types:

  1. APIs to help create a handler
  2. APIs to help create a microformat
  3. APIs to help create a microformat renderer (like the Operator toolbar)

In the next post, we’ll cover all the APIs we missed. Notes that these APIs might change in the future, but I’ll try to maintain compatibility.

Also, for all you JavaScript experts out there, if you see me doing something wrong or if there is a better way to do what I am doing, please tell me.

To start with, we need to create the file hResume.js and place it in the microformats directory in our profile, similar to what we did for our handler. Here’s a link to a completed hResume.js to take a look at. We’ll go over each line in the file.

try {
  Microformats;
} catch (ex) {
  promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                            .getService(Components.interfaces.nsIPromptService);
  promptService.alert(window, "", "Microformats are not available. Microformats.js must be included before hResume.js");
}

I put this code at the top of each of my microformats just to make sure we have the APIs we need.

Microformats.hResume = {

Here we’re actually defining the class of our microformat. The name should be the true name of the microformat (the user will see this name)

  microformat: true,

This value is used when we are enumerating objects in the Microformat class looking for microformats. It must be set to true

  className:   "hresume",

This is the class property that identifies the microformat.

  description: "Reume(s)",

This is the descriptive name of the microformat.

  icon: "chrome://operator/content/other.png",

This is the icon of the microformat. In most cases, I use a 16×16 base64 encoded PNG that corresponds to the microformat.
We also have a default “other” icon that I have specified here.

  handlers: [],

This is an empty array that will contain the handlers for this microformat.

  defaultHandler: "google",

This is the default handler. If no default handler is specified, we use the first handler we find.

Now that we’ve setup the members of our class, let’s take a look at the functions we need. There are three required functions, getDisplayName, getError, and create.

The getDisplayName function should return a string that will be used to uniquely identity the format visually to a user. For instance the fn in a hCard, or the summary in an hCalendar.

Here’s getDisplayName for hResume

getDisplayName: function(item)
  {
    vcards = Microformats.getElementsByClassName(item, "vcard");
    if (vcards.length > 0)
    return Microformats.getValue(vcards[0], "fn");
   },

Here we are intruduced to two helper APIs in the Microformats class. First we have Microformats.getElementsByClassName. This does exactly what it says – it gets an array of all the nodes in the given This will be used a lot as we are parsing the microformat. Second we have the function Microformats.getValue. getValue is very useful because behind the scenes, it handles the various ways a particular class in a microformat can be encoded, such as multiple class=”value” items, or the use of the abbr/title. getValue should always be used when you need the text of an indivudual class. When a class has the potential to have more than one value (such as nickname in an hCard for instance) you should use getValueArray. getValueArray will return an array with all of the values for the corresponding class.

Next is the getError function

getError: function(item)
  {
    vcards = Microformats.getElementsByClassName(item, "vcard");
    if (vcards.length == 0)
      return "No vcard specified";
  },

You might have noticed that there are cases where getDisplayName returns nothing (if there is no vcard in the hResume). In these cases, if you have debug mode turned on in Operator, you will see a menu item that says “Invalid select for more details” If you select this menu item, getError is called. We’ll use this function to display an error message to help people figure out what the problem is.

Next up is the actual parsing/creation of the Javascript object that corresponds to the microformat

  create: function(indoc, innode)
  {
    return new function(doc, node)
    {
      vcards = Microformats.getElementsByClassName(node, "vcard");
      if (vcards.length > 0) {
        this.vcard = Microformats.hCard.create(doc, vcards[0]);
      }
      affiliations = Microformats.getElementsByClassName(node, "affiliation");
      for (var i=0;i < affiliations.length;i++) {
        if (!this.affiliation) {
          this.affiliation = new Array();
        }
        this.affiliation[i] = Microformats.hCard.create(doc, affiliations[i]);
      }
      experiences = Microformats.getElementsByClassName(node, "experience");
      for (var i=0;i < experiences.length;i++) {
        if (!this.experience) {
          this.experience = new Array();
        }
        this.experience[i] = Microformats.hCalendar.create(doc, experiences[i]);
      }
      var temp;
      if (temp = Microformats.getValue(node, "summary")) {
        this.summary = temp;
      }
    }(indoc, innode);
  }

The create function will be called by handlers and anyone else that needs a Javascript representation of the microformat so that individual entires in the microformat can be accessed. The cool thing about the hResume microformat is a compound microformat which means that we can reuse the other microformats in Operator to populate the hResume.

First we create an hCard that corresponds to the vcard in the resume. Then we enumerate through all the affiliations in the resume and create hCards for each of those. Next we enumerate all the experiences in the resume and create hCalendars for those. Finally, we use the Microformats.getValue function to get the summary.

Now that we have the ability to create an hResume, let’s create a handler that uses the hResume we have created.

Creating a handler was already covered in this post, so the main thing we need to see is how to access the hResume we just created.

Microformats.hResume.handlers['google'] = {
  description: "Search Google!",

  action: function(doc, item)
  {
    hresume = Microformats.hResume.create(doc,item);
    url = "http://www.google.com/search?q=" + hresume.vcard.fn;
    Microformats.loadUrl(url);
  }
}

Three things to notice here. First, we were able to create an hResume using our new create code. Then we were able to reference the fn in the hResume’s hCard by simply doing hresume.vcard.fn. Finally, we see the use of an API in Microformats called Microformats.loadUrl. This is a helper function for a handler that loads a URL in a new tab.

That’s it for now. Next time we’ll explore the rest of the APIs in the Microformats class.

Please note: I reserve the right to delete comments that are offensive or off-topic.

Leave a Reply

Your email address will not be published. Required fields are marked *

3 thoughts on “Adding new microformats to Operator