Archive - December, 2006

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.

Live Clipboard in Operator

So this post Interesting Developments with Microformats from Mozilla and Microsoft at wizardishungryblog brings up the Live Clipboard support in Operator. I thought I would use this post to talk a little about Live Clipboard – what it is and why it is in Operator.

For those that don’t know, at its core, Live Clipboard is an XML wrapper around particular microformats that allows those microformats to be easily exchanged between applications. There is more to it than that, but I’ll leave that investigation up to the reader. What Operator supports is copying the hCard and hCalendar microformats to the Live Clipboard.

Along with the Live Clipboard concept, Microsoft has come up with a UI paradigm that involves placing a small orange icon anywhere on your page where you want a user to copy or paste data. Behind this icon is some JavaScript and other magic that interacts with the system clipboard. You would use this icon to copy the data from one site and then paste it on another site. The idea is that this will eliminate the “cloud of links” that many sites have to send data to other sites by providing one UI paradigm to move data like events and addresses from site to another. If you want to see an example of this icon, check out any event at eventful.com. The ironic part is that eventful.com chose to add the Live Clipboard icon to the “cloud of links!” (Incidentally, this is why you get two Operator entries for every event on eventful.com – Operator is detecting the microformat in the item and the microformat used for Live Clipboard.)

The approach that Operator is taking is really about taking the burden away from web developers as it relates to connecting with other sites, services and applications. Web developers shouldn’t have to add JavaScript to their site or understand some other sites API in order to provide functionality to their users. They should simply be able to mark up their sites using microformats and let the web browser (or in this case Operator) worry about what to do with the data.

But if Live Clipboard is successful, support is already available in Operator, so there is no need to update existing websites, except to add microformats (which you should be doing anyway).

Incidentally, the first application to support Live Clipboard (for hCalendar at least) is Microsoft’s Windows Live Writer. A plugin has been created called Event Plugin that adds Live Clipboard support. Using this plugin, we can immediately see the benefit of Live Clipboard support in Operator.

The Event Plugin is designed to connect to eventful.com – it provides the ability to search eventful.com from within Windows Live Writer. Because of the Live Clipboard support in Operator, I can go to any site that has an event marked up using the hCalendar microformat and paste it into Windows Live Writer:

What: Web 2.0 Expo
When: Monday, December 18, 2006 1:27 PM
Where: Moscone West

4th &Howard
San Francisco, California 94103

That event came from upcoming.org. (I’m using Windows Live Writer to write this post.)

So the final question then is why did I choose to add Live Clipboard support to Operator? The answer is because I could. Adding Live Clipboard required literally no effort at all and I thought it was an interesting feature to have. The Live Clipboard can be used to show Operator integration with Windows Live Writer as well as the live Clipboard demos. My goal was to show microformats interacting with various web APIs and Live Clipboard is one of those APIs.

Up next: adding new microformats to Operator.

Operator Architecture

With this post, I’m going to go into more detail about the architecture of Operator. To start out, we need to get on the same page with regards to terminology.

Handlers:

In the context of Operator each microformat has handlers associated with it. These handlers are the connections to various services. For instance, the tag microformat has handlers for flickr, delicious, technorati, and upcoming.org. Handlers are have nothing to do with the toolbar per say, they are associated with the microformat itself. Any user interface element could be used to invoke a handler on a microformat.

Actions:

Actions are a concept specifically associated with the toolbar at this point in time. An action is the pairing of a microformat with a handler in the user interface. For instance, if I pair the geo microformat and Google Maps handler, I have an action that looks up a location on Google Maps based on the content of the geo microformat.

When I created the Operator extension, I made a very deliberate distinction between the microformats themselves, and the toolbar. The microformats only contain information that distinguishes the format, such as its description, icon, class name or attribute value and handlers. They also have functions that no how to get a displayable name and to create a JavaScript instance of the microformat.

In addition to the microformats themselves, the Microformats JavaScript class has a number of functions related to finding microformats on web pages and working with them, but it has nothing that is toolbar specific.

So all that being said, I chose the toolbar as the user interface metaphor because I thought it was a good starting point. I see no reason why my architecture can’t be extended for other metaphors.

I invite comments to this post as to other user interface metaphors that could be used for microformats discovery.

Coming in my next post – why on earth did I put Live Clipboard support in Operator? And for that matter, what is Live Clipboard?

Adding handlers to Operator

Over at labs.mozilla.com you’ll see the announcement of a microformats extension I created called Operator. I figured the release of this extension was a good reason for me to start blogging again, since people have questions and comments about the extension. So that’s what I’ll be doing here.

So far, the response has been great. Here are some posts from LouderVoice blog, microformatique, wizardishungry/blog, guillermoesteves.com, pixelsebi’s repository (in German), and Not So Relevant.

So far I think the one thing that everyone has missed about Operator is that it is extensible out of the box. Here’s an example.

I got this question on the mozilla.dev.apps.firefox newsgroup:

Will a newer version have a built in mechanism that
will allow me to extend it without it being built
into the operator extension?

For example, I want to add an additional service
such as Yedda.com to show me questions and answers
on a certain tag.

In Yedda's case (and others with similar URL structure)
it simply means the ability to add a parameterized URL
handler so I can define something like:

http://yedda.com/questions/tags/{tags}

as the handler where {tags} will be replaced by the
values of the various rel-tags on the page.

And here’s my answer:

Operator already supports this functionality. Check
out the file handler-example.js in the directory where
the extension is called. For yedda, here is what it
would look like:

Microformats.tag.handlers['yedda'] = {
description: "Find questions on Yedda",

action: function(doc, item) {
tag = Microformats.tag.create(doc,item);
url = "http://yedda.com/questions/tags/" + tag.tag;
Microformats.loadUrl(url);
}
};
Save this to a file called "yedda.js" and place it
in a directory called "microformats" in your profile
directory and you have yedda support.

So as you can see, Operator was designed to be extensible out of the box.

I’ll go into more detail about the architecture of Operator with my next post. The main thing to remember is that it is NOT a microformats toolbar! It is a microformats architecture that is currently using a toolbar as the UI. I have kept the microformats part separate from the toolbar part.