Monday, September 1, 2008

Drubiquity: a proof-of-concept Ubiquity interface for Drupal

I've been pretty impressed with Ubiquity, a Firefox extension that combines web APIs with the command-line and some natural language processing, so you can compose together applications using javascript in a very unix-y way.

As an experiment and a weekend hack, I wanted to create an interface to Drupal, the awesome software that I run my blog on. I have something pretty cool working, but sadly, I can't really recommend using it, because the REST API that I integrated with has some serious problems. Maybe I'll get around to re-implementing this with the Services API system, but it's late Sunday and I haven't gotten around to that yet, so I thought I'd post. Anyone is welcome to pick this up and make it work for real :)
Read on for a screenshot and the source code.

Right now, what my ubiquity command does is queries the API of a Drupal site for the list of users, and matches that list against what the user types. So if the user types "drubiquity ijones", they'll get two users on my site, me and a test user.

The preview function uses the API to fetch the picture of the user that you're currently looking at and insert it asynchronously, as shown below. Then if you hit "enter" it will bring you to the blog for that user.

It should be simple to extend for some more uses. For instance, you could implement something like the "twitter" command to post a brief blog entry for a Drupal site, or the preview function could list recent blog entries or more info about the user. Leaning more toward the mashup idea, you could map user locations, or insert photo album pictures into an email, or click on an image and blog about it, etc. The fun thing is that lots of sites use Drupal, so anything you build with Ubiquity can be leveraged across all those sites.

Here's a screenshot and the source code in case anyone is interested. I should warn you that I'm not exactly a Javascript programmer, so your mileage may vary. I'll post again if I end up re-implementing this with the services API.

// ------------------------------------------------------------
// * Site specific things to modify:
// ------------------------------------------------------------

//change the command to something about your site:
const cmdName = "drubiquity";

//If you modify this, you are the author:
const currentAuthor = { name: "Isaac Potoczny-Jones", email: ""};

//Set this to your home page for documentation purposes.
const currentHomepage = "";

//This should point to the root of your drupal site:
const sourceURL = "";

// This should point to the root of your rest / JSON API. If it's
// correct, you should be able to go to jsonURLRoot/help and see
// instructions for what's available.  You must install this pluggin:

const jsonURLRoot = sourceURL + "?q=/=/";

//end site-specific modifications

// Dynamically match input to the list of usernames
var noun_type_user = {
  _name: "user name",
  userList: null,

  callback: function (users) {
        noun_type_user.userList = users.value;

  suggest: function( text, html ) {
        //fetch the list of users and suggest them.
            var jsonURL = jsonURLRoot + "user/name.json";
            if (noun_type_user.userList == null) {
                jQuery.getJSON(jsonURL, noun_type_user.callback);
                return [];
            if (text.length < 2) return [];
            var suggestions = [];
            for ( i = 0; i < noun_type_user.userList.length; i++ ) {
                var userName = noun_type_user.userList[i];
                if (userName.match(text, "i") && userName != "" )
            return suggestions.splice(0, 5);
} //username type

  name: cmdName,
  homepage: currentHomepage,
  author: currentAuthor,

  contributors: ["Isaac Potoczny-Jones"],
  license: "BSD3",
  description: "Some commands to interact with Drupal."
           + " Requires the Rest API extension on the target site.",
  help: "Type '" 
            + cmdName + "' and you should get some hints.  You can search for users "
            + "by typing a few letters of their username. You should be presented "
            + "with a preview picture if they have one on file. Hit enter for the "
            + "given user, and you'll be taken to their blog.",

  takes: { "user": noun_type_user},

  preview: function( pblock, userName ) {
            //displays user's image if available.
            var prevMessage = "View blog for user: " + userName.text;
            pblock.innerHTML = prevMessage;
            getUserRec (userName,
                            var picURL =  sourceURL + user.value.picture;
                            pblock.innerHTML = ""
                                + prevMessage;

  execute: function( userName ) {
            //looks up user's uid and constructs blog URL from that.
            getUserRec (userName,
                        function (user) {
                            var blogURL = sourceURL + "?q=blog/" + user.value.uid;
                            Utils.openUrlInBrowser (blogURL);

// looks up the user record given the user name object. callback takes user record
function getUserRec (userName, userCallback ) {

    var userNameSt = userName.text;
    var jsonURL = jsonURLRoot + "user/name/" + userNameSt + ".json";
    var prevMessage = "View blog for user: " + userNameSt;
                       userCallback (user);

No comments:

Post a Comment