An xmpp4moz notebook

I like documentation that looks like a laboratory notebook—not a linear and sure path from problem to solution, but a record of the paths tried, including the bad ones, reasons why they were bad, intuitions that led toward the solution, and ideas about where to go next.

So I was pleased to stumble on the blog about the development of TrueTalk. I’m still not sure about what TrueTalk is, but it is based on xmpp4moz and the authors frequently report about the challenges they meet and how they face them.

If you’re considering writing something on xmpp4moz and want to get an insider’s perspective, have a look at this blog.

XTech over

A lively XTech is over. After some wandering and (too) much train I’m again in (too) sunny Italy.

Circumstances of the presentation were a little adventurous—wi-fi wasn’t officially available, and what do you do when you want to demonstrate an instant messaging application and there’s no network to talk to a remote partner? Easy: you program an assistant robot and run it on localhost. (Easy? Um, ok.)

I coded Alyssa (source available if anyone is crazy enough to want to look at it) and it pardon, she helped demonstrate shared web application over xmpp4moz. Apart from drawing silly pictures and playing chess she enjoyed renovating Google home page in… pretty shades of pink. I must confess though that the funniest (for the audience, not for me) moment was unplanned: an hour earlier, after rehearsal, I had forgotten to stop her, so when the actual demo started I found her already in the middle of the script. I had to bring up a terminal and say excuse me while I reboot my assistant.

Presentation being toward the end of the conference and keeping me worried most of the time, and my social skills being low even on a geek scale, was not enough to keep me from shaking hands and exchanging laughs with great people from Google, Twitter, Thoughtworks, Opera, Jaiku and more. As the icing on the cake, just before leaving Paris I got to chat over dinner with Process-One folks, who managed to laugh at most of my terrible Jabber jokes and helped make me some sense of the menu (although I’m still not sure what the last thing I ate was, but it had much chocolate in it and tasted great).

Enough now with this real world stuff—back to the code!

SamePlace spinoffs #1: CSS Query

Before:


var xulScriptlet;
var blueprint = document.getElementById('blueprints').firstChild;
while(blueprint) {
    if(blueprint.getAttribute('class') == 'scriptlet')
        break;
    blueprint = blueprint.nextSibling;
}

var xulScriptlet = blueprint.cloneNode(true);
xulScriptlet.getElementsByAttribute('class', 'name')[0].value =
    scriptlet.info.name;
xulScriptlet.getElementsByAttribute('class', 'version')[0].value =
    scriptlet.info.version;
document.getElementById('scriptlets').appendChild(xulScriptlet);

After…



var xulScriptlet = $('#blueprints > .scriptlet)._.cloneNode(true);
$(xulScriptlet).$('.name')._.value = scriptlet.info.name;
$(xulScriptlet).$('.name')._.version = scriptlet.info.version;
$('#scriptlets')._.appendChild(xulScriptlet);

I got tired of writing DOM code, and envious of how the excellent jQuery uses CSS selectors. However, I needed a couple of things more than jQuery offered and a couple of hundreds less, I needed them in XUL rather than in HTML, and since Joel turned my XHTML templating system into an XML-to-Erlang compiler, I have been dying to write something with a “compile()” function in it. A few hours of healthy hacking later, the result was in the SamePlace repository.

(It was also an excercise in what I call API transparency, about which I’ll hopefully write soon.)

Here’s a quick rundown on how to use it. The ”$” function opens a “query environment”, where you can write using (a subset of) CSS selector syntax. Examples:


$('#foo')
$('.bar')
$('#foo > label')
$('#foo [hidden="true"])


You can chain query environments, so these two lines are equivalent:


$('#foo > label')
$('#foo').$('> label')

To escape the query environment and get to the DOM world, use ”_” for the first matched element and “_a” for an array of all matched elements:


$('#foo > label')._.value = 'hello, world!';
$('#foo > label')._a.forEach(function(label) { label.value = 'hello, world!'; });

If you already have a DOM element to start searching from, pass that to ”$()”; it will set the context for subsequent queries:


var xulFoo = $('#foo');
$(xulFoo).$('> .name')._.value = 'Ben';
$(xulFoo).$('> .surname')._.value = 'Bitdiddle';

As I said, I needed a couple of extra things: parent and ancestor selectors, respectively mapped to ”<” and ”^”. For example, to iterate over all boxes which are parent of hidden elements:


$('[hidden="true"] < box')._a.forEach(function(box) { doSomething(box); });

Limitations: search by class maps to getElementsByAttribute(), so $(”.bar”) will only find elements with class="bar" and not elements with class="bar baz". I didn’t want to compile down to XPath (which isn’t available in Thunderbird), and using JavaScript to walk an element’s subtree and test each descendant’s attribute for a match was a terrible performance hit. Also, I’m not happy at all with the “_a” property, can someone think of a less ugly name?

Anyway, enjoy, and let me know if it proves useful.

Trivia: it is said of obscure programmers that “they can’t understand they’re own code the day after they’ve written it”. I don’t usually consider myself “obscure”, but I believe I found a new low in the above criteria:


return function(context) {
    if(!('length' in context))
        context = [context];

    return fold(
        function(finder, candidates) {
            return fold(
                function(candidate, newCandidates) {
                    return newCandidates.concat(
                        Array.slice(finder(candidate)));
                }, [], candidates);
        },
        context, finders);
}


Which, I confess, I wasn’t understanding while I was writing it.

XTech

I am amiss in not mentioning XTech sooner. In a few days, I’ll be there to speak about XMPP, enabling real-time and user-to-user communication in the browser, and how that changes the rules.

Last year saw a fantastic line-up of speakers talk about Mozilla-related technologies. I stopped counting at around ten! This years there will be, uhm, me. Timing isn’t my strongest point.

If you are in Paris around May 15-21 and would like to meet up for a drink and chat about web technologies, functional programming, and the other things we do when we should be getting some sleep instead, please drop me a line. See you there!

SamePlace, meet Twitter. (Introducing scriptlets.)

I don’t use Twitter, but some of my friends do and I also see them updating their IM status message often. I assumed that the Twitter bot was watching the status and updating accordingly, but it turns out you have to message it explicitly.

“Catching status changes in SamePlace”, I thought, “and forwarding them to the Twitter bot, that would need just a handful of lines”. And updating both IM and Twitter status with a hotkey looked attractive.

But how to distribute a handful of lines? An extension is too much, and yet it’s not generic enough to belong in the main application.

Thus, some hours later SamePlace got support for scriptlets, and it’s now available in the development branch.

Scriptlets are micro-extensions: self-contained JavaScript files that you can use by simply dragging them from a web page into the scriptlet manager (after having read and accepted a big fat warning, of course—after all they run with extension privileges). They don’t require browser restart.

They’re also ideal for quick, live prototyping: just create the JavaScript file under [firefox_profile_dir]/sameplace/scriptlets and enable it from the “Actions -> Scriptlets -> [name of scriptlet]” menu. When you modify the file, either disable and re-enable the scriptlet, or click on “Reload” in the scriptlet manager.

The Twitter scriptlet can be found here.