Category Archives: XUL, XBL, JS and DOM

Wanted: Wizard & Dialog Mochitests

Wizard tests and dialog tests.

Umm…

We don’t have a lot of tests to say that a wizard or dialog will function as desired. Since I’m building a pretty complex wizard, it’d be nice to have some assurance that when I hit “Next”, it will end up on the next page – and that the button changes to “Finish” when it’s supposed to, for example. I’d also like to write some tests specific to that wizard I’m building.

I’m not quite sure how to write such a test. The best idea I have is that the dialog check for a query string value indicating “I’m a test, do something different”. I need some sort of standard way for running tests a dialog’s opener specifies.

Asynchronous events and Mochitesting

Recently, I found that I needed my chrome Mochitest to wait for a XBL binding to apply, before continuing the test. For the end-user, waiting is hardly an issue – by the time they see the new user interface, all the bindings have applied. Mochitest (and most other automated test harnesses) runs straight through, and brakes for nobody. In some cases you can pull some trickery with nsIThreadManager, convincing Firefox to wait… but that’s hardly reliable.

So I came up with a three-part solution.

  1. Force my XBL bindings to fire DOM events when the constructor executes.
  2. Break up my test functions into (slightly) smaller functions, each of which handles a part of the overall test. Two parts cover the main functional testing, while a third part is specific to the XBL binding.
  3. Implement a generic testing harness for Mochitest which can manage the flow from one function to another.

This new test harness, which I call PendingEventsTest, adds a layer of complexity on top of SimpleTest. Each test function is added via PendingEventsTest.addTest(), and you can pause for a DOM event with PendingEventsTest.addEventLock(). The whole test sequence can abort with an error by calling PendingEventsTest.abortFail(). You can advance to the next test function in the sequence with PendingEventsTest.asyncRun() or PendingEventsTest.run().

There’s more complexity to it than that, of course. To move data from one test function to another, I also added “payload” support, for storing a generic object. Also, this is written for chrome Mochitests – it will likely fail in content Mochitests. Still, this new test harness helped me finish support in Verbosio for my equivalent of the <xbl:children/> element in markup templates.

Lastly, it (and the logging service I wrote a few weeks ago) is licensed under MPL 1.1/GPL 2.0/LGPL 2.1, so anyone who wants to borrow this for Mozilla code is welcome to. Cheers!

Wanted at OSCON: Wrapping GNU software into XPCOM

I’m taking next week off to attend the Open Source Convention 2009 in San Jose, CA. It’ll be a chance for me to get back to my cutting-edge (not quite bleeding-edge), unmanaged, free-to-foul-it-all-up-or-to-do-something-original mode.

Or to learn something. Like how to take a bunch of C code and create a XPCOM wrapper for it. I’ve talked about including diffutils as part of Verbosio before. I think I’d like to have someone actually help me do that. Likewise, I started looking at findutils as a possible angle for bug 421029 (file search in XPCOM/NSPR), though I’m not as certain about that.

So if there’s anyone else here attending OSCON (or free the preceding two days) and wants to hunker down for something different in Mozilla hacking, let me know through the comments. I’m also pretty good at writing stuff down, so sheppy & the DevMo crew might get a nice article out of it.

(P.S. Thank you, Gerv, for the discount code. I’m paying for this out of my own pocket.)

JavaScript modules for web pages (think Yahoo UI widgets)?

This is just a wild idea I had, and I don’t have time to adequately explore it right now. So I’m throwing it out here to see what you think.

Mozilla Firefox 3.0 introduced several new ideas, including these two:

I love the concept of JavaScript modules (sharing common code) so much, I started thinking: wouldn’t it be nice to provide the same for web pages – a common location to load files that several websites might want available?

Of course, it’s a really bad idea to expose chrome JavaScript to content – scripts that won’t work, at least, and security holes at worst (if you’re considering passing objects from chrome to content, as I’ve been known to do). But that’s not what I have in mind.

Yahoo UI widgets are a library of fairly complex, JavaScript-driven user interface classes. They’re actually pretty useful. However, a site using them must provide bandwidth to download them for every page view that references them. That can add up quickly, which is one reason scripts like it are often minified. With a resource:// URI, you could take it further (no downloads at all, it’s already on the user’s machine!) – but how do you ensure that URI exists?

Build a Firefox add-on.

Imagine an extension’s chrome.manifest like this:

# Library for Yahoo UI widgets
resource library:yahoo-ui res/yahoo-ui

That’s all. Then you’d need a res/yahoo-ui folder in the extension which would hold the Yahoo UI widgets library.

A colleague last night correctly pointed out this doesn’t factor in versioning of Yahoo libraries. Plus, you’d probably need a generic loading library which would look for the resource://library:yahoo-ui/whatever.js file first, and go download the YUI files from the website if it isn’t there.

Another downside is that this really abuses the resource: URI protocol. I’d feel better implementing another protocol that would be more flexible and still web-safe.

On the plus side, the scripts in the library wouldn’t have to be minified anymore. From the perspective of debugging with Venkman, it is a royal pain in the butt to figure out why a YUI widget doesn’t work…

Personally, I’d rather not stop there. I’d rather make whole extensions that were restricted to content – specifying in their install.rdf manifest that they weren’t chrome extensions and that their packages lived in the browser’s sandbox for web pages. You could then specify global objects that would trigger exceptions if they tried to do anything outside what a webpage could do. (I keep thinking XPathGenerator could really have used that, just to assure everyone it was safe for 1.9.1.)
GreaseMonkey makes an attempt at this (a good one). I’m wondering if it’s worth promoting that capability into the main Firefox build.

Anyway, that’s enough white-boarding for the moment. I’m really sorry I don’t have time to delve any deeper, but work plus my own Verbosio project keep me too busy. Comments are open – feel free to tell me I’m crazy or that the Web doesn’t need this.

I have a scrollable content object model… too late

Several years ago, I griped (unsuccessfully) about the need for a scrollable content object model. I remember someone mentioning on planet.mozilla.org that this would not be a problem going forward, but I couldn’t find the entry. So today, I was exploring another user-interface concept, and it led me back again to scrollable content. (As you read this, my context is the XULRunner 1.9.0.x code base.)

Ahh, I remember the frustrations well. It took me several hours (and a few blind alleys), but I actually hit on a really simple way to tell where a XUL box with scrollbars has scrolled to. Though the XUL box itself has to use my particular XBL binding and CSS styling, it’s still a nice starting point.

Here’s the binding, stylesheet, and a demonstration all in one. Note that it’s a lot cleaner than my previous attempt, and it works.

I realize the scrollX and scrollY properties are read-only. I don’t see a way around that for this approach. If you really want it, you’ll probably have to implement a native-code, C++-based component.

Or, you could wait for Firefox 3.1 / XULRunner 1.9.1, which now has scrollLeft and scrollTop for all DOM elements – and it’s settable there, too. (This makes the third big improvement I’m looking for in XR 1.9.1 that isn’t in 1.9.0.x, which means it’s time to seriously think about moving forward… The other two are new drag and drop features, and a DOM Range fix I pulled in from very early in the 1.9.1 cycle.)

Note I groaned very audibly when I was writing this article and decided to check what 1.9.1 has. Talk about a feeling of a wasted day!

JavaScript components should avoid nsIPropertyBag like the plague

I’ve been bitten by this a dozen times over the years. I try to find a simple data interface for getting a bunch of strings out, and I see nsIPropertyBag. I think to myself, “Hmm. That’s a pretty good choice.” Then I implement it, watch it QueryInterface for my component, and then watch it not call my getProperty() method. Why? XPConnect returns its own nsIPropertyBag object first when I try to call getProperty(). So my call goes to a different object than the one I intended.

I never, ever learn.

Back to Basics: Two-Dimensional Arrays

I had planned to write an article on ECMAScript Harmony and my ideas for corresponding XPIDL changes… but four months after its announcement, I find I still don’t know what’s in the Harmony spec! (We know a few things that are out… but since the initial blog surge, it’s been quiet.)

So I’ve decided to put my ideas for XPIDL on the side, and move on to the last part in this series: my attempt at creating a XPCOM component for two-dimensional arrays. Read on for further details.

Continue reading Back to Basics: Two-Dimensional Arrays

Back to Basics: Why write components in C++?

A year or so ago, I introduced the ArrayConverter
module
to Verbosio, and tried to get it into mozilla.org code. The idea
was simple: a JavaScript library for converting between native JavaScript
arrays, XPCOM arrays, nsIArray objects and nsISimpleEnumerator
objects. Although it did not get in, I’ve been rethinking half of the
ArrayConverter module’s functionality, and I believe now that I
overlooked something.

I planned on writing two different articles – one talking about
reinventing the wheel unnecessarily, and another talking about why I, a
JavaScript expert, would choose to write XPCOM components in C++. It turns
out, though, that each of these has roughly the same answer: the penalties of
XPConnect. Read on for
further details.

Continue reading Back to Basics: Why write components in C++?

Back to Basics: Read-only Data

(I’m posting two articles today – and for those of you who correctly pointed out my XPCOM Services article had bugs in the sample code, I’ve updated it to point to live code with a couple adjustments. I continue to welcome your insight.)

XPCOM provides a lot of basic data types – nsIVariant
is one of the more complex ones from a C++ standpoint. In particular, they
provide arrays through the nsIArray
interface, object containers through nsIPropertyBag
and nsIPropertyBag2,
and a bunch of primitive values such as strings and floating-point numbers
through nsISupportsPrimitives.
XPCOM also provides components
and contracts
for these data types in C++, so you don’t have to
reimplement them. (You can if you want to, but it’s usually not necessary, as
I’ll explain in another article.)

There’s only one downside to these basic components: they’re eternally
changeable. What that means is I can pass a
nsISupportsString to your component, and it can change that
value before sending it onto another component. From my perspective, I don’t
have any way of “sealing” the data, of making it read-only. Even if I pass
you one of these components in an interface that has no change methods
(nsIArray), you could easily QueryInterface it for
an interface that has change methods (nsIMutableArray).
You’ll find an exception to the rule in nsIWritableVariant, but
that’s about it.

In this article, I’ll talk about two approaches to this problem – and the
choice I made.

Continue reading Back to Basics: Read-only Data

Back to Basics: Defining XPCOM Services

Once upon a time, I asked a question in the #developers channel
on irc.mozilla.org:

How do I define that a XPCOM component is
actually a service?

The answer I received:

See if the caller uses do_GetService(), or
Components.classes[…].getService().

This is less than satisfactory. I should be able to say “There can be only
one” and not “Oh, please, don’t create more than one of me.” Over the years,
I came up with different solutions for JavaScript – and I recently discovered
the standard way to do it for C++-based XPCOM components. Read on in the
extended entry for details.

Continue reading Back to Basics: Defining XPCOM Services