Some motivation

Django has a field called ChoiceField which lets you very easily create a <select> dropdown in your forms. A great feature is the ability to transform nested choices into appropriate <optgroup> groups. For instance, the following code:

The problem

As it turns out, ChoiceField only supports one level of nesting. Five years ago someone submitted a patch to correct the problem, but it was rejected for good reason: HTML itself only officially supports one level of <optgroup> nesting.

To see if it would work anyway, I manually applied the patch to my Django installation. Although the patch itself worked (Django produced the nested option groups), Chrome wasn’t having any of it. My dropdown displayed incorrectly, and developer tools showed that the HTML got mangled during parsing.

Emulating nested optgroups

My solution to the problem is to fake it by using disabled <option> elements as group headers. Then, we apply indentation to the actual options to make them appear to belong to the groups. This is accomplished by a custom widget called NestedSelect (below), which is a cross between the original Select widget and the patch I linked to above.

Improving the aesthetics

The solution above works, but it can be improved in two ways:

The manual addition of padding results in an ugly side-effect – that padding is visible in the selected option. Look at the difference when Choice 1 and Choice 5 are selected (below). Choice 5 is aligned correctly, but Choice 1 appears to be floating out in no-man’s land.

We no longer have the nice bolding effect on the option group headers. It’s not possible for us to individually style the elements that are supposed to be headers.

To overcome these shortcomings of HTML, we must turn a JavaScript based replacement: Select2. With that plugin installed, the fix is just a little bit of JavaScript:

jQuery UI 1.9 is finally here! What does that mean for dialogWrapper? Well, it would seem like the answer to that question is: nothing. A redesign of the dialog API is not present in version 1.9, and it doesn’t look like it will happen until the 2.0 release, according to the official site.

The planned changes for the 2.0 release are something to get excited about now, however. Some of the changes discussed add some nice functionality and improve the overall design of the API. Heads up: so far, it doesn’t sound like the 2.0 release will make dialogWrapper irrelevant.

Changes, changes. I’ve just finished adding the grunt build system to all my JavaScript projects. This has made it so much easier to manage them.

Now instead of manually generating the minified versions (copy-pasting to Google Closure Compiler), worrying about the license files being up to date, etc., I can issue a single command and everything is taken care of.

This also means that JSLint is run whenever I build my projects. So naturally, in the span of a few hours I caught a bunch of warnings and errors that I had previously never seen. I’ll go through the projects one at a time.

Textarea Line Count

Very important fixes. Updated to version 1.4. Let me say, I’m surprised that I didn’t receive any bug reports on version 1.3. Running JSLint revealed variables that didn’t exist, or that were named incorrectly. Oops. That’s what I get for not using a build system sooner.

What’s new?

The biggest change is that all methods are now namespaced! For example, instead of writing:

$.alert("This is an alert dialog!");

… by default you must now write:

$.dW.alert("This is an alert dialog!");

Why did I do this? Well, I was getting concerned about my polluting the global $ namespace. It should now be easier for my plugin to work with other plugins that may have used the same or similar function names.

But that breaks compatibility!?

You can use the new $.dW.classicMode() method to restore the old style functions. Just call it once, with no arguments. Then you can go back to using $.createDialog and friends instead of the new namespaced versions.

What else is new?

This version has a few new nice features:

The callbacks for $.dW.alert(), $.dW.confirm(), and $.dW.input() are now executed within the context of the dialog. That means that you can now use this within the handler to reference the dialog.

I added a callback to $.dW.alert() that is executed when the Ok button is clicked.

Options that dialogWrapper adds, with hasClose being the only one so far, are now defaulted in $.ui.dialog.prototype.options, along with native options. This way, you can easily modify the default hasClose setting.

I really enjoy exploring jQuery’s source code. Recently, I’ve been using James Padolsey’s jQuery Source Viewer. It’s a really neat tool that lets you type in the name of a function (even if it’s an internal function!) and view its source.

The Deconstructed series is designed to visually and interactively deconstruct the internal code of JavaScript libraries, including jQuery, Prototype and MooTools.

It breaks the physical JavaScript into visual blocks that you can easiliy navigate. Each block opens to reveal its internal code. Clickable hyperlinks allow you to follow program flow.

What is interesting about the tool is that you do not necessarily need to know the name of the function you are looking for. What’s more, you can explore more than just functions! If, for example, you are interested in how jQuery can recognize attributes in selectors (e.g. $("div[name=mydiv]")), you can go to the Attributes section (1/3 of the way down), and view the Regular expressions that jQuery uses. In this particular example, the regular expressions are stored in a “private” variable, so it’s something that the other tool can’t access.

In my Greasemonkey scripts, I sometimes find it necessary to alert the user in some way without using the alert() function. In any other web application, I would normally use Facebox, a wonderfully free jQuery plugin that displays Facebook style pop-ups. However, there are several obstacles to adding any (well, most) jQuery plugins to Greasemonkey scripts:

The plugin itself is a script which must be kept somewhere. You can directly download the script from the Facebox server with Ajax, but that might result in an obscene amount requests to the server (which is not proper internet etiquette).

Media can sometimes be embedded in the script, but plugins can sometimes be too big or awkward to store inline.

Luckily, Greasemonkey and JavaScript contains the features necessary to resolve these issues.

The first and third issues can be solved with Greasemonkey’s GM_getValue() and GM_setValue() functions and a bit of Ajax. The idea is to download the plugin script once, and cache it using GM_setValue(). Then, the next time the script runs we can use GM_getValue() to get it.

The second issue can be solved using Firefox’s handy data URI feature. I used this website to upload the plugin’s image files and convert them to a data URI. In the code that injects Facebox, the references to these files in the plugin code is replaced with the file data, inline. Note that the Facebox CSS was minified as well, although I have misplaced the link to the website I used. Here is the code (or, alternatively, download it from here):