October 31, 2006

Mozilla's Context Menus

Mozilla's Context Menus

Several years back I followed Mozilla's (the product now known as SeaMonkey) progress pretty closely and one person who's blog I followed was Matthew Thomas, or as everyone seems to know him, MPT. The guy pushed usuability and user interface design on bugzilla and God knows Mozilla needed it, the interface was quite simply horrible.

I wasn't directly involved in any Mozilla development, past the odd bug report, so my perspective is very much as an outsider, but I gather that as Mozilla was open sourced most of the developers were those on the payroll of Netscape (which was now a division of AOL Time Warner). The idea of open sourcing a project and instantly attracting developers who sacrafice their free time is flawed, however MPT was a guy who wasn't employed by Netscape but devoted time to helping with usability and triaging in bugzilla.

Mozilla was an open source project but the original goal of the project was to drive the Netscape browser. With all the contributors to Mozilla being employees of Netscape several desicions that went into the codebase, and notably the UI, were driven by Netscape without heedence of the community.

One example of this, which has always stuck in my mind, is the context menus. I'm not entirely sure of the story behind the context menus but bug 75338 follows MPT's spec and related discussion. After an extended period of time and several iterations a pretty darn beautifull context menu specification is created (complete with classic mozilla.org banner) which is miles more elegant than the context menus which existed in Mozilla at the time. I find these context menus amazingly well thought out and designed and I still think this spec is really something.

This story doesn't have a happy ending, ultimately a Netscape engineer created a massively inferior spec which didn't change the menus too much (they still had the oh-so-useful "Set as Wallpaper" option) so the diehard faithful users wouldn't get too confused (what users?). The Netscape spec was implemented and MPT got fed up of being ignored and jumped ship.

The reason I am posting this is because I don't want to lose the link to MPT's context menu specification. It made a real impression on me and I can only hope that when I come to create a UI it is as well planned and designed as this.

April 26, 2006

rbNarcissus v0.2

rbNarcissus v0.2

I updated rbNarcissus to a second version with a lot of jiggling so that it actually works when parsing anything that I tried to throw at it now. I also stuck up an example script which shows how you can extract information by walking the parse tree.

Running the Ruby parser over the Narcissus parser takes a second or two, so I don't think it's stunning performance wise. Next I'd really love to have the time to look at creating a run time. I'd also like to know enough Ruby to make it a module, but the reference seemed rather brief on the topic so I didn't really know where to run.

April 19, 2006

Scope of Variables in JavaScript

Scope of Variables in JavaScript

A little piece of JavaScript trivia; the scope of JavaScript variables is decided at parse time, not at run time, just like named functions. An example:

function () {
 foo = 'bar';
 var foo
}

The scope of the variable foo is the function body, even though the variable is declared in the statement after an assigment to the variable. It works in my the same way that this runs without error:

function () {
 var bar = foo();
 function foo () {
  return 'baz';
 }
}

Even though the function foo is not defined in the code until after it is called, the parser picks up the name of the function so that the run time knows what to do.

April 14, 2006

Variable Names vs. Argument Names in Spidermonkey

Variable Names vs. Argument Names in Spidermonkey

Spidermonkey, the JavaScript engine at the heart of Firefox and other Gecko browsers, treats variables declared inline and those declared in the argument list differently. I noticed this quirk a little while ago, and stumbled upon it again recently. To demonstrate, first an example.

function foo (arg1) {
 alert(arguments[0]);
 arg1 = 'bar';
 alert(arguments[0]);
}

foo('test');

In this example the first alert box says 'test', however the second alert box says 'bar'. This might not be what you expect and certainly isn't what I expected. The variable arg1 is not just a reference to the object that was passed in. Using the assigment operator doesn't just change the reference contained in the variable arg1 to point to another object, it also changes the arguments array.

What I expected to happen, and what happens in other browsers would be more like this:

function foo () {
 var arg1 = arguments[0];
 alert(arguments[0]);
 arg1 = 'bar';
 alert(arguments[0]);
}

foo('test');

With both the first and second alert boxes reading 'test' and the variable simply being a reference, independant of the reference in the arguments array.

Odd.

April 10, 2006

innerHTML using a Pythonesque Template Object

innerHTML using a Pythonesque Template Object

There are becoming some increasingly prettier ways to hide away the verbosity of using the W3C's DOM to create anything more complicated than a single element, for example Vivabit's DOM Builder. The other option, generously donated by Microsoft, is to just throw a HTML string at the innerHTML attribute of any Element object.

As part of its standard library Python provides a Template class contained in the string module. This class makes it easy to construct templates which can be used over for several substitution operations, or just one. Recently I've been using a JavaScript implementation to generate HTML strings for use with innerHTML, letting me avoid the DOM.

The object definition is given below. It processes the string in the constructor, providing improved performance for multiple substitutions.

function Template (template) {
 this.template = template;

 var idpattern = new RegExp("^({(" + this.idpattern + ")})|(" + this.idpattern + ")");
 var parts = [];
 
 var i = 0, j = 0;
 while ((j = this.template.indexOf(this.delimiter, i)) != -1) {
  if (i != j) { parts.push(this.template.substring(i, j++)); }

  // check for an escaped delimiter, doubled up
  if (this.template.charAt(j) == this.delimiter) {
   if (typeof parts[parts.length - 1] == "string") {
    parts[parts.length - 1] += this.delimiter;
   } else {
    parts.push(this.delimiter);
   }
   i = ++j; continue;
  }

  var result = this.template.substring(j).match(idpattern);
  if (result == null) { throw new Error("Invalid placeholder in string: index " + i); }
  
  var key = result[2] || result[3];
  parts.push(key.split("."));
  i = j + (result[1] ? result[1].length : key.length);
 }
 if (i != this.template.length) { parts.push(this.template.substring(i)); }

 this._compiled = parts;
}

Template.prototype.delimiter = "$";
Template.prototype.idpattern = "[_A-z][._A-z0-9]*";

Template.prototype.substitute = function (keys) {
 var str = "";

 var i = 0, part;
 while (part = this._compiled[i++]) {
  if (typeof part == "string") { str += part; }
  else {
   for (var j = 0, value = keys; j < part.length; j++) {
    value = value[part[j]];
   }
   str += value;
  }
 }

 return str;
}

This object is great to use with a response from one of Yahoo's API calls, formatting the JSON object. An example implementation of the showUrls from my previous post would like this:

function showUrls (result) {
 
 var link = new Template('\
  <p><a href="$ClickUrl" target="blank">$Title</a><br>\
    <span style="color: gray;">$Note</span>'
 );
 
 var links = "<div>";
 var results = result.ResultSet.Result, i = 0, url;
 while (url = results[i++]) { links += link.substitute(url); }
 links += "</div>";
 
 $("url_container").innerHTML = links;
}

One thing to be careful about here however is escaping the HTML and attributes correctly. This is a poor man's E4X.

I really need to get around to setting up a code repository so that it's easier for me to maintain my snippets online, rather than just posting them to my blog and letting them stale.

April 06, 2006

Source Code Highlighting from the Clipboard on OS X

Source Code Highlighting from the Clipboard on OS X

So it doesn't get lost here is a command you can use to highlight source code on OS X:

$ pbpaste | \
  tr '\r' '\n' | \
  source-highlight --no-doc --css foo.css --src-lang js | \
  pbcopy

First, pbpaste pastes the contents of the clipboard (or pasteboard in Mac lingo) onto standard out. We then pipe it to tr which is a simple substitution command to replace the Mac line breaks with UNIX line breaks that source-highlight, a GNU program, understands. This is then piped through to source-highlight, with options to format using CSS and a flag specifying the language (the CSS file name can be anything, it makes no difference with the --no-doc flag). Finally it's piped to pbcopy which sticks it back onto the clipboard. Easy!

I had to install source-highlight from source, the version on Fink was too old and didn't have the JS language definition (and what good is it without JavaScript!). The only dependancy is the Boost C++ RegExp library. This isn't too hard to install; first you have to download the bjam binary, a make tool, and use it to compile and install the Boost libraries.

Lo and behold, highlighted source code.

Yahoo! APIs

Yahoo! APIs

Yahoo! have recently been populating their developer page with an impressive array of APIs for folks to access the raw data from their various services, as well as their recent acquisitions. The services are super easy to use too.

When Google first announced their SOAP API to their search engine, while the data was there to be had, there was a large barrier to getting to it. Yahoo's APIs can all be accessed using REST, which means simple GET and POST requests and as well as offering language neutral XML they also offer JSON and PHP formatted results. For a Web developer constrained to a Web browser it doesn't get better than this, the APIs can be queried accross domains.

Below is a simple object that I've been using to fire off requests to the Yahoo APIs.

var yApi = {
 IMAGE: "http://api.search.yahoo.com/ImageSearchService/V1/imageSearch",
 RELATED: "http://api.search.yahoo.com/WebSearchService/V1/relatedSuggestion",
 MYWEB_URL: "http://api.search.yahoo.com/MyWebService/V1/urlSearch",
 MYWEB_TAG: "http://api.search.yahoo.com/MyWebService/V1/tagSearch",

 defaults: {
  appid: "idontsmoke"
 },
 
 get: function (url, parameters) {
  
  // add in the defaults
  for (var key in this.defaults) {
   if (parameters[key] == undefined) {
    parameters[key] = this.defaults[key];
   }
  }
  url = this.encode_url(url, parameters);
  
  var script = document.createElement("script");
  script.src = url;
  script.type = "text/javascript";
  document.getElementsByTagName("head")[0].appendChild(script);
 },
 
 encode_url: function (url, parameters) {
  components = [];
  for (var key in parameters) {
   values = parameters[key];
   if (typeof parameters[key] != "array") { values = [values]; }
   for (var i = 0, len = values.length; i < len; i++) {
    components.push(
     encodeURIComponent(key) + "=" +
     encodeURIComponent(values[i]));
   }
  }
  return url + "?" + components.join("&");
 }

}

Which can then be called using something like:

yApi.get(yApi.MYWEB_TAG, {
 yahooid:  "ashleysowden",
 tag:      ["javascript", "awesome"],
 output:   "json",
 callback: "showUrls"
});

The only problem is I can't get the damn thing to respond with a list constrained to my Yahoo ID and the support channels for the APIs seem questionable at best.

December 22, 2005

JsBot, Jot and another Year

JsBot, Jot and another Year

So another year is coming to a close, and this one was pretty. This summer saw me interning at JotSpot, the premier Wiki company. I got the opportunity to work out in San Francisco, California alongside some DHTML guys I've pseudo-known for 5 years; Alex and Dave "Schnotz". I also got the chance to meet some other cool people and drink lots of tequila, notably at the Renkoo launch party.

While at Jot I had the chance to work on the Dojo JavaScript toolkit, and helped to push its first release out of the door. I ended up pouring hours and hours into it and my biggest contribution was the Jot sponsored RichText component which attempts to wrap up the WYSIWYG editing capabilities of the browsers in a lightweight way, without trying to push them where they don't want to go. A horrible and thankless job, but what I feel turned out to be a rather reasonable output. I also think its best moment is yet to come, we'll have to wait and see where.

More recently I've wrapped up PircBot so as to allow IRC bots written in JavaScript, a fantastically flexible scripting language, dubbed JsBot. It's another small project that I unfortuantly don't have the time to take anywhere as my final year at university sucks up all my time.

Moving onto next year, I finally pop out of my formal education and into the job market, we'll have to wait and see where that does take me.