IE8 is Gonna Rock

So maybe my title was a bit overdramatic. But in the announcement of IE8’s features, one jumped out at me as a potentially game-changing feature.

http://www.microsoft.com/windows/products/winfamily/ie/ie8/readiness/DevelopersNew.htm#dom

Yes.

That’s right.

“Selectors are a query language for searching and “selecting” tags (elements) within a webpage. They are most commonly seen in CSS to “select” a group of elements to which certain properties will be applied:

Selector{
   property: value;
   property2: value;
}

In Internet Explorer 7 there is no way of “executing” the selector independently of CSS. Internet Explorer 8’s implementation of the Selectors API is based on the W3C Working Draft: http://www.w3.org/TR/selectors-api/”

Yes. You read that correctly. To the extent of IE8’s support for CSS2.1 (which should be relatively complete, according to their announcement), it will be possible to use the standards-compliant querySelector and querySelectorAll in IE to get collections of elements at native speed. This means fast class-name lookup, fast attribute lookup, and much much more.

Here’s a lame example of its use from an IE8 whitepaper:

function doValidation ()  {
// Retrieve the required elements by using Selectors
   // Selects all the form fields with 'required' classes
var reqs = document.querySelectorAll(".required");
   // Set the flag to false by default
var missingRequiredField = false;
// Validate that the form data is not empty
for (var i = 0; i < reqs.length; i++)  {
if (reqs[i].value == "")
         missingRequiredField = true;
   }

Yep. It is what it looks like. Finally, the days of slow IE selectors may be coming to an end. And finally, one where MS is ahead of the curve (in fact, a lot of the IE8 improvements are pretty neat and forward-looking; I recommend taking a look at it)

Modularity in jQuery: Part II

Last time, we talked about using event bindings to provide a publish/subscribe mechanism for your plugins, and introduce modularity via the event system.

This time, we’ll talk about two new features added since jQuery 1.2: Setup and teardown for events and the element data store. First up, the element data store:

Prior to jQuery 1.2, data was added to elements via expandos. If, for instance, d was an element, and we wanted to add some data named “foo” with the value “bar”, we would do d.foo = "bar". Simple enough. But there are two major issues:

  • Other libraries, plugins, or widgets might try and use the foo name. We could try and obfuscate the name (jQuery 1.0 used $events as the expando name for the events array on an element), but there was still a chance that another library could accidentally use the same name. In fact, that’s exactly what happened. MooTools inadvertently used $events, and people who tried to use both libraries got hosed.
  • IE’s garbage collection gets all flummoxed under certain circumstances when an element is removed but its expandos still have references to live objects.

The solution, which jQuery adopted for 1.2, is to create a new data store that’s independent of the element and in the jQuery namespace, and which jQuery garbage collects itself when you remove the associated elements. This provides a mechanism for tagging elements with information that can then be used by different modules in your program. While jQuery uses it to track which events belong to which elements, it can also be used for other purposes.

For instance, the jQuery metadata plugin allows you to specify data to be stored in the data store in your markup. Here’s an example:

The markup

<div data="{foo: 'bar'}">Some div element is here</div>

The code

$.metadata.setType("attr", "data");
$("div").metadata().foo == "bar"

The metadata plugin produces a thin sheen over the data-store, allowing you to pass information into the store via markup. That might be quite useful for plugins, to allow your users to specify options for your plugin without needing to write any special code. For instance, you could write this code in your plugin:

Markup

<div class="myPlugin" data="{myPlugin: {option1: 12, option2: "stringyString"}}">Some Text</div>

The Code

$.metadata.setType("attr", "data");
jQuery(function($) {
  $("div.myPlugin").each(function() {
    $(this).myPlugin($(this).metadata().myPlugin);
  });
});

This is assuming, of course, that there is some $.fn.myPlugin that takes option1 and option2 as options. This technique allows you to put the initialization code in your plugin itself and let the user interact with it in fairly high-level ways via markup. The TableSorter plugin makes use of this technique.

But you can use the data store for other purposes as well. In particular, you can interact directly with the data store by doing $.data(el, “key”, “value”) to set a key in the store, or $.data(el, “key”) to retrieve a key. jQuery 1.2.3 will also add a new shortcut (which we’ll discuss in more length in the next post in this series), which will allow $(”div”).data(”key”).

I use this technique in the autocomplete plugin to tag a keystroke as “final” (hitting escape, for instance, should not trigger a new dropdown if it’s used to cancel the autocomplete). Even though the autocompleter is in a separate module from the event code that triggers the autocompleter, this information can be tagged onto the element so it’s accessible from any module.

Setup and Teardown

Setup and teardown lets you further customize event binding. In effect, setup and teardown functions are called immediately before an event is bound (and immediately before an event is unbound), allowing you to preform processing. Returning true from the setup function causes it to get bound using the browser’s native handlers, instead of the jQuery event system (don’t worry about this; it’s extremely rare). Let’s take a hypothetical activate.myPlugin event.

The Code

$.event.special["activate.myPlugin] = function() {
  /* “this” is the element being bound */
  /* do some processing */;
}

Later, when you do $("div").bind("activate.myPlugin") the special method will get run. This allows your plugin’s users to add some processing to when your plugin gets bound to an element, without having to override the plugin binding method.

Next up: New features that will be introduced in 1.2.3, and bringing this all together :)

Modularity in jQuery

There have recently been several comments along the lines that jQuery is not very modular, once you get past modifying DOM elements. I get why people are saying that, but there’s been a lot of features added to jQuery over the past year or so that provide a compelling architecture for building modular apps.

It’s not exactly OO, which is what a lot of people are used to; it’s more like a publish/subscribe model, with points of modularity added via message passing. That’s because jQuery provides a pretty kick-ass system for custom events (events that are not built-into the browser), including a mechanism to subscribe to such events and a mechanism to trigger (i.e. publish) the events, with custom data.

It also provides the potential for setup and teardown for both browser and custom events, as well as a central data store for persistent data that would traditionally be attached directly to an element. This solves both the memory-leak issue (jQuery manages garbage collection of objects in the store that are no longer valid because the DOM element doesn’t exist anymore) as well as a crucial compatibility issue (we don’t store the data in the element itself, so we work fine with other libraries that do, or other libraries that have their own store in their own namespace).

Events

If you use jQuery, you already know about browser events:

$("div").click(function() { /* code here */ });

That’s a shortcut for:

$("div").bind("click", function() { /* code here */ });

What you probably don’t know is that you can also bind your own custom events:

$("div").bind("clickeroo", function() { /* code here */ });

That probably doesn’t seem all that useful until you realize you can also trigger these custom events:

$("div").trigger("clickeroo")

or even:

$("div").bind("clickeroo", function(e, data1, data2) {
  // some stuff that uses data
});
$("div").trigger("clickeroo", [dataObject1, dataObject2]);

And finally, you can bind custom events with namespaces:

$("div").bind("activate.dialog", function(event, options) {
  // some stuff that uses options
});

Triggering activate or activate.dialog will trigger the event, and because all JS arguments are optional, the options argument will work whether or not the core event was triggered with the additional data.

Where does this bring us?

So I claimed earlier that this provides us with a useful tool for modularity. If you’ve been paying attention, and like me, have run into some modularity ceilings, you should be realizing some of the possibilities here. Effectively, what you have is a publish/subscribe model for events. If I create a dialog plugin, I don’t have to have a massive options hash to provide a callback for the dialog opening, the dialog closing, the dialog resizing, etc. All I need to do is blindly trigger open.dialog, close.dialog, resize.dialog, etc. and allow the user to subscribe to those events if necessary. This even allows for meta-plugins that simply subscribe to events published by the main plugin and extend them. This is the approach I take in my autocomplete plugin, which publishes “autocomplete.activate”, “autocomplete.cancel”, and “autocomplete.selected” events.

My plugin also subscribes to the “updateList.autocomplete” event, which allows outside code to provide a list for the autocompleter at any time, without having to know how the internal autocomplete code works. In fact, the Ajax extension to the autocomplete plugin simply registers a callback for the call to getList that the plugin calls, which publishes an updateList.autocomplete event with the appropriate data when done.

In the end, this allows you to create self-contained modules in your application that communication with each other by providing public publish and subscribe points for interaction. In the case of the autocomplete plugin, all the events are published onto the input element, and external interfaces subscribe to events published to that element. This allows multiple autocomplete plugins on a single page that don’t need to use a single message bus. However, for more global events, you can publish/subscribe to/from the window or document object, which can provide a more global event bus.

Next time, I’ll talk about the setup and teardown methods for custom events, as well as using the element data store to store data about an element that needs to be shared between modules.

Merb.next

No, ladies and gentlemen, we haven’t taken a break after releasing 0.5 (The “Thanks Zed” release). With 0.5 out, stable and fast, the Merb team finally took a hard look at where we’re going with the framework. Thanks to Engine Yard’s investment in our work, I was able to meet with Ezra in person and spent a large part of last week planning out Merb.next.

First up, we’re closing in on Merb 1.0. The next major release will be numbered 0.9, and will be the point release immediately prior to 1.0. In order to help make Merb even more modular and tight, Merb 0.9 will be broken up into a merb-core gem and a package of merb-more gems. The entire package will still install via gem install merb, and will be fully maintained by the core team. However, in Merb.next, it’ll be trivial to leave off chunks of functionality that you don’t want.

Merb Core, which we’re working on right now (you can follow our progress at Git Hub), will be the tight core of the framework, just enough to run basic web services and simple web sites. It’ll be possible to use Merb Core for a single-page app (a la Camping or Sinatra) or an app with a full-blown application structure (like Rails or current Merb).

Merb 0.9 will also tie up a bunch of loose ends, not shying away from breaking things in order to give Merb 1.0’s API as much longevity as possible. At the same time, we’re trying to make the upgrade path from Merb.current to Merb.next as painless as possible.

In an effort to keep Merb core really tight, we’re also adopting some more formal programming and documentation techniques that will make working on and using Merb much easier:

  • All methods (public and private) are required to provide a clear method signature, including the types for any parameters, and the possible values for any options hashes, as well as return types and other information (see below for an example).
  • Methods can be tagged @public, which means that changing them will break the public API. Methods can also be tagged @semipublic, which means that they’re used in other parts of the framework and possibly the test harness. This’ll aid future refactoring, because methods that are not public or semipublic can be reimplemented at will as long as the test suite still passes.
  • We’re removing all hardcoded paths from the framework. This means that Merb will scale from a single-page app to any application structure you want. You can even specify how to name template files (you can go from the traditional controller/view.mime.type or controller.view.mime.type or even view.mime.type for a single controller app)
  • We’re splitting our test suite into public and private tests. Public tests test the public API, while private tests test things like the Request object. Public tests are required to use only methods in the public or semipublic API, so they should still pass after major refactors.

Merb Core is also based on a Rack adapter now, so it’ll work out of the box with Mongrel, Evented Mongrel, FCGI, regular CGI, thin, webrick, and Fuzed, as well as any server you can write a rack adapter for. And fear not, you’ll still have access to the raw mongrel request if you want to do fancy stuff like streaming or deferred rendering outside the mutex.

Here’s an example of the new documentation standards:

  # Render the specified item, with the specified options.
  #
  # ==== Parameters
  # thing<String, Symbol, nil>::
  #   The thing to render. This will default to the current action
  # opts<Hash>:: An options hash (see below)
  #
  # ==== Options (opts)
  # :format<Symbol>:: A registered mime-type format
  # :template<String>::
  #   The path to the template relative to the template root
  # :status<~to_i>::
  #   The status to send to the client. Typically, this would
  #   be an integer (200), or a Merb status code (Accepted)
  # :layout<~to_s>::
  #   A layout to use instead of the default. This should be
  #   relative to the layout root. By default, the layout will
  #   be either the controller_name or application. If you
  #   want to use an alternative content-type than the one
  #   that the base template was rendered as, you will need
  #   to do :layout => “foo.#{content_type}” (i.e. “foo.json”)
  #
  # ==== Returns
  # String:: The rendered template, including layout, if appropriate.
  #
  # ==== Raises
  # TemplateNotFound::
  #   There is no template for the specified location.
  #
  # ==== Alternatives
  # If you pass a Hash as the first parameter, it will be moved to
  # opts and “thing” will be the current action
  #
  #—
  # @public
  def render(thing = nil, opts = {})
    <snip>
  end

Some description: The render method takes two parameters, a “thing” to render and an options Hash. The “thing” can be a String, Symbol, or nil. The options hash takes :format, :template, :status, and :layout options, which are described under Options. Th :status option must respond_to? to_i and the :layout options must respond_to? to_s. It returns a String (the rendered layout), and raises a TemplateNotFound if the template specified is not found. It is part of the @public API.

The documentation format will be itself documented as part of the Merb Core release, and we hope to write a parser that uses RDoc to spit out just the public API (leaving out public methods that are not marked @public).

The public test suite itself is also designed to provide a useful starting point for Merb plugin authors; here’s an example:

  # @public
  it "should accept template-type registrations via #register_extensions" do
    Merb::Template.register_extensions(Merb::Test::Fixtures::MyTemplateEngine, %w[myt])
    Merb::Template.engine_for(”foo.myt”).should == Merb::Test::Fixtures::MyTemplateEngine
  end

All in all, it’s going to be damn tight, formal, and grokkable. I plan to release some code traces once 0.9 is done that trace the path of a request through the Merb framework, so you can grok exactly how requests go through the pipeline and are eventually rendered.

Good Coding and Good Luck!

Almost There: 30% Off jQuery in Action!

As you might know, I’m putting the final touches on jQuery in Action, an introductory book on all things jQuery for Manning Publications. I’ve spent the last half a year diligently plugging away at it, along with my co-author Bear Bibeault, and we’re finally hitting the home stretch.

It’s taken a lot of time, and focus, and while it’s been a great experience, I’m also looking forward to being able to once again put my full energy into the various Open Source projects I’m involved in (including jQuery, of course). We’re reviewing typeset PDF’s of what looks to be just about ready to print — there’s light at the end of this tunnel!

The book is set to print in early to mid-January; as a final push before publication, Manning is offering 30% off until December 31st, with the code JQM30. Though the book is also available on Amazon.com, among other places, Manning is the only place you can also get the e-book, which at least for me, is really important.

Thanks to everyone who’s been there for me in this crazy busy time, and for everyone who’s had to grin and bear it while my focus was split. I’m almost done!

Search in a Directory (Third time’s the Charm)

So for all two of you who have been using my Search in a Directory bundle, I have a new version, that has been substantially improved:

  • a massive rewrite that successfully handles closing the window during a grep
  • some UI tweaks
  • an all-around improvement to the underlying code

I am also in the process of adding support for skipping certain directories (the current version skips .svn directories by default, but I want you to be able to turn on and off skipping Rails directories).

Download the bundle today!

Better Threading in Mail.app

I really like the new Mail.app in Leopard. With Gmail moving to IMAP, I was finally able to get virtually all of the functionality that I’m used to in Gmail on my desktop Mail application, which is really cool.

Well… except for one little thing. Mail.app has threads, but it does not thread Sent Mail in with Received mail. In Gmail, on the other hand, inbound email gets threaded with outbound email, so I get a nice breakdown of the actual discussions I’ve been having. Devoid of outbound context, the threads are frequently confusing or meaningless.

The workaround I came up with is to create a new Smart Folder that includes Inbound email and Outbound email (Inbox and Sent Items). The Smart Mailbox, in threaded mode, correctly handles putting all of the email together. The little caveat is that outbound email that was not a reply to something appears in this view too (it does not appear in Gmail), but I think I actually prefer that mode of operating.

Textmate Search in a Folder (with grep) Part Deux

I posted my initial “Search in a Folder” solution a couple of days ago, and it turned out it had a few bugs (like the backgrounded ruby script never closing, and thus spawning a new ruby process for each time you loaded up the window. There were other user-experience annoyances, too. The good news is that that’s all in the past now.

The new version of the Wycats bundle has the following changes:

  • I am now using a utility window, so the search window always remains in front
  • I am now tracking open windows, so if you have an open window, another one doesn’t open
  • I track all available exit conditions and correctly exit the event loop
  • Other bugfixes and tweaks

Download version 1.0.1 today!

Proper Search in Directory

In August, I refactored a TextMate bundle to support Search within a folder via Grep. It was nice, but was fairly ugly, and non-configurable. Today, I’m releasing a (very alpha quality) version of a dialog that packages up grep within a directory into a nice GUI package (it looks a lot like Textmate’s default Search Within a Project dialog).

With this bundle, you can search within the entire project or any selected directory and get back the data in the bottom of the search pane, just like Textmate’s default search box. The bundle is activated by hitting Apple-Shift-F, but you can change it to whatever combination you like.

A couple of caveats

  • I don’t current block new windows from being created if one already exists. As a result, close your windows once you’re done with them.
  • Double-clicking a line in the bottom section of the dialog brings up the file with the caret on the line, as you expect. However, it hides the search window. Hit Apple-~ to get back to the search window. Hitting Apple-Shift-F will create a new window, so don’t do that.

Download the bundle today!

JSpec: BDD for JS

A couple of weeks ago I wrote a nice little piece of JS that implemented BDD-style testing in JS. It was originally 70 or so lines of code, and supported code like:

jspec.describe("Some stuff", function() {
  it("should rock", function() {
    7.should("==", 7);
  });
});

It was (and still is) a very simple piece of code, that only dumps the output to the Firebug console. Because should() was a simple method, I was able to delegate out to a pluggable jspec.matchers object, which is where I specified the “match” definition, and allowed the customization of a “failure message.” The original jspec had just two matchers (”==” and “include”), and allowed the creation of new ones by extending the jspec.matchers object (all JS, no magic).

When I tried to actually use it to test real-world code, though, some issues came up. First, functions were being dumped in full into the output, which was sucky. Secondly, the default describe syntax was sucking a bit for certain cases. And finally, I wanted you to be able to plug in any logger you wanted (for say, pretty HTML output). I added those new features, and am now releasing this quick and dirty code for people to look at.

Some examples

(which are included in the downloadable file)

jspec.describe("JSpec", function() {
  it("should support ==", function() {
    (1).should("==", 1);
    var arr = [];
    arr.should(”==”, arr);
    var obj = new Object;
    obj.should(”==”, obj);
    document.should(”==”, document);
  });

  it(”should support include”, function() {
    [1,2,3,4,5].should(”include”, 3);
    [1,2,3,4,5].should_not(”include”, 3);
    document.getElementsByTagName(”div”).should(”include”, document.getElementById(”hello”))
  });

  it(”should support exists”, function() {
    document.should(”exist”);
  });

  jspec.matchers["have_tag_name"] = {
    describe: function(target, not) {
      return jspec.compress_lines(this) + ” should ” + (not ? “not ” : “”) + “have ” + target + ” as its tag name.”
    },
    matches: function(target) {
      return (this.tagName && this.tagName == target) ? true : false;
    },
    failure_message: function(target, not) {
      return “Expected ” + this.toString() + (not ? ” not ” : ” “) + “to have ” + target + ” as its tag name,” +
        ” but was ” + this.tagName;
    }
  };

  it(”should support custom matchers”, function() {
    document.getElementById(”wrapper”).should(”have_tag_name”, “DIV”);
    document.getElementById(”wrapper”).should_not(”have_tag_name”, “SPAN”);
    document.getElementById(”wrapper”).should(”have_tag_name”, “SPAN”);
  });
});

And the Output

In Firebug

JSpec
  - should support ==
    - 1 should equal 1 (PASS)
    - [] should equal [] (PASS)
    - [object Object] should equal [object Object] (PASS)
    - [object HTMLDocument] should equal [object HTMLDocument] (PASS)
  - should support include
    - 1,2,3,4,5 should include 3 (PASS)
    - 1,2,3,4,5 should not include 3 (FAIL)
      Expected [[1,2,3,4,5]] not to include 3
    - [object HTMLCollection] should include [object HTMLDivElement] (PASS)
  - should support exists
    - [object HTMLDocument] should exist. (PASS)
  - should support custom matchers
    - [object HTMLDivElement] should have DIV as its tag name. (PASS)
    - [object HTMLDivElement] should not have SPAN as its tag name. (PASS)
    - [object HTMLDivElement] should have SPAN as its tag name. (FAIL)
      Expected [object HTMLDivElement] to have SPAN as its tag name, but was DIV

Some caveats

  • Despite some work put in, I can’t figure out how to get jspec to recover gracefully from errors and continue on. This will work in a future release
  • I temporarily override the Object prototype (evil, I know) for the duration of the test. You will still be able to load in libraries that expect Object to work correctly, but you will not be able to test functions (such as prototype’s Object.extend) without accounting for the fact that Object.prototype has been extended.

Happy hunting (Download here)

Update

There is now a git repo for the project at git.caboo.se/jspec.git

« Previous PageNext Page »