We've just tagged the first release candidate of Prototype 1.7: a major new version with some major new features.

Sizzle as the selector engine (or mix in your own)

With Prototype 1.7, we've finally realized our long-held goal of moving to Sizzle, the middleware selector engine used by jQuery and others. I wrote our previous selector engine, used since 1.5.1, but nevertheless I'm excited to switch to a more robust engine that's shared between frameworks.

So Sizzle is the new default. But there's more to it than that. In moving to Sizzle, we've modularized the selector engine entirely. If you want to use Diego Perini's NWMatcher library in place of Sizzle, you can. Just check out the source code and build like so:

rake dist SELECTOR_ENGINE=nwmatcher

If you're a sentimentalist, you can use the legacy Prototype selector engine by specifying SELECTOR_ENGINE=legacy_selector. Or add your own selector engine by creating a subdirectory in vendor/ and following some simple conventions.

Element#on

Element#on is a new way to access the Prototype event API. It provides first-class support for event delegation and simplifies event handler removal.

In its simplest form, Element#on works just like Element#observe:

$("messages").on("click", function(event) {
  // ...
});

An optional second argument lets you specify a CSS selector for event delegation. This encapsulates the pattern of using Event#findElement to retrieve the first ancestor element matching a specific selector. So this Prototype 1.6 code...

$("messages").observe("click", function(event) {
  var element = event.findElement("a.comment_link");
  if (element) {
    // ...
  }
});

...can be written more concisely with Element#on as:

$("messages").on("click", "a.comment_link", function(event, element) {
  // ...
});

Element#on differs from Element#observe in one other important way: its return value is an object with a #stop method. Calling this method will remove the event handler. (Technically, this is an instance of a new class called Event.Handler.) With this pattern, there's no need to retain a reference to the handler function just so you can pass it to Element#stopObserving later.

For example, in Prototype 1.6, where you'd need to write something like...

start: function() {
  this.clickHandler = function(event) {
    // ...
  };

  $("messages").observe("click", this.clickHandler);
},

stop: function() {
  $("messages").stopObserving("click", this.clickHandler);
}

...you can now write:

start: function() {
  this.clickHandler = $("messages").on("click", function(event) {
    // ...
  });
},

stop: function() {
  this.clickHandler.stop();
}

Also note that the Event.Handler class has a corresponding #start method that lets you re-attach an observer you've removed with #stop.

So, to review, Element#on is both a new approach to event observation and an implementation of event delegation. Feel free to eschew Element#observe and use Element#on exclusively; or use Element#on just for event delegation; or keep using Element#observe the way you always have.

Element.Layout: Your digital tape measure

The second major feature in 1.7 is Element.Layout, a class for pixel-perfect measurement of element dimensions and offsets.

Now you don't have to decide between properties like offsetWidth (which return numbers, but not the numbers you want) or retrieving computed styles (which have their own set of quirks and require a call to parseInt).

The simple case

If you want a one-off measurement of an element, use the new Element#measure:

$('troz').measure('width'); //-> 150
$('troz').measure('border-top'); //-> 5

// Offsets, too:
$('troz').measure('top'); //-> 226

The argument passed to measure is one of a handful of intuitive names, most of which are derived from their CSS equivalents. So width means the width of the content box, just like in CSS — but we throw in extra properties (e.g., padding-box-width, margin-box-height) for some common measurements. This approach gives you far more granularity than common DHTML properties like offsetWidth and clientHeight.

These measurements are guaranteed to be in pixels. Even in IE. (In fact, Prototype works around a handful of IE quirks that would ordinarily result in inaccurate measurments.) It can even measure elements that are hidden, as long as their parents are visible. (Like when you want to animate an element from a hidden state and need to know how tall it will be.)

The complex case

If you need to measure several things at once, though, Element#measure is not the most efficient way to do it. Often an element will need a bit of manipulation before it reports its dimensions accurately, which means measurements can be costly.

The Element.Layout class tries to minimize that cost. It's a read-only subclass of Hash that remembers values in order to avoid re-computing.

First, use Element#getLayout to obtain an instance of Element.Layout:

var layout = $('troz').getLayout();

Now use Element.Layout#get to retrieve values, using the same property names you used for Element#measure:

layout.get('width');  //-> 150
layout.get('height'); //-> 500

layout.get('padding-left');  //-> 10
layout.get('margin-left');   //-> 25
layout.get('border-top');    //-> 5
layout.get('border-bottom'); //-> 5

layout.get('padding-box-width'); //-> 170
layout.get('border-box-height'); //-> 510

layout.get('width');  //-> 150

Here's where the remembered values (or memoization, if you prefer) come in. When I ask for width, Prototype measures the element – which, as we discussed, is a costly operation — and returns a value. A few lines later, I ask for width again, and I get the same value. But this time it didn't do any measuring. It remembered the value from last time.

There's more. When I ask for border-box-height, Prototype knows that's just height plus border-top plus border-bottom. All three of those properties are already memoized, since I asked for them earlier, so it skips the measurement phase and just gives me the sum.

How does it know when an element's dimensions change? It doesn't. Don't hang onto an instance of Element.Layout for too long; it's meant for short-term efficiency, not long-term caching. You can grab a new instance by calling Element#getLayout again.

Believe it or not, this is the short version. Read the documentation to learn more.

JSON fixes, ES5 compliance

The JSON interface slated for ECMAScript 5 is already being implemented in major browsers. It uses many of the same method names as Prototype's existing JSON implementation, but with different behavior, so we rewrote ours to be ES5-compliant and to fall back to the native JSON support where possible. A few other methods, like Object.keys, received similar treatment.

And, of course, bug fixes

Consult the CHANGELOG for further details.

Download, report bugs, and get help

As always: thanks to the many contributors who made this release possible!

Comments

  1. Mislav #

    Element#on, my new favorite method!

    April 5th, 2010 @ 12:02 PM
  2. Mike Taylor #

    Modular selector engines FTW.

    April 5th, 2010 @ 12:10 PM
  3. Gianni "gf3" Chiappetta #

    Sexy, can’t wait for the final!

    April 5th, 2010 @ 12:13 PM
  4. Phunky #

    Awww everything covered in this post sounds soooo good!

    Can’t wait to get my hands on these :) great work guys.

    April 5th, 2010 @ 01:40 PM
  5. Gabriel Gilini #

    Why didn’t you guys just embed the memoization logic inside the – measure – method?

    April 5th, 2010 @ 01:41 PM
  6. Jeff Micklos #

    I have been wondering where you guys have been! 1.7 looks like it is going to be hot (insert Sizzle pun here) – keep up the good work! This is a great start to the month of April!

    April 5th, 2010 @ 01:55 PM
  7. Animuchan #

    Yay! Impressive work, as always. You’re the best <3>

    April 5th, 2010 @ 03:43 PM
  8. Andrew Dupont #

    Gabriel: Because we wouldn’t know when to “expire” the memoized value. What happens when the element’s dimensions change?

    April 5th, 2010 @ 04:15 PM
  9. Martin Ström #

    Great work – #on looks amazing! Cannot wait to see what you guys have planned for 2.0 :)

    April 5th, 2010 @ 04:59 PM
  10. Gabriel Gilini #

    Andrew: Fair enough. A parameter indicating if you want the live values defaulting to no would look a lot more coherent, though.

    April 5th, 2010 @ 05:37 PM
  11. Dan Popescu #

    In the new prototype there is a: var layout = element.get(‘layout’); shouldn’t it be: var layout = element.getLayout();

    April 6th, 2010 @ 02:38 AM
  12. bugrain #

    Great news. But as one who is still going to be using the older version for a while in production shouldn’t the on-line documentation show the new/changed stuff somehow? Otherwise, how do I know?

    April 6th, 2010 @ 03:16 AM
  13. superruzafa #

    I agree with @bugrain. I missed up the documentation for the currently stable version of prototype. Please make it available again since I have multiple projects built with prototype 1.6.1.

    April 6th, 2010 @ 09:39 AM
  14. Luke Andrews #

    Is this release considered to be compatible with the latest version of Scriptaculous?

    April 6th, 2010 @ 11:29 AM
  15. Ben #

    Looks great. I was excited when I saw Element.Layout in the API docs the other day, but disappointed that it wasn’t implemented yet.

    April 6th, 2010 @ 01:36 PM
  16. P #

    Why oh why does these pages have Version: ‘1.5.2_pre0’? I wanted to check it out in Firebug immediately :)

    April 6th, 2010 @ 02:42 PM
  17. firejune #

    I found the following small error:

    $H({foo: ‘bar’}).toJSON() //-> “[Object Object]”

    April 6th, 2010 @ 11:40 PM
  18. Tobie Langel #

    firejune: That isn’t an error, it follows the specs. toJSON() methods are requested to return an object (or primitive) ready for serialization with Object.toJSON.

    Try this:

    Object.toJSON($H({foo: ‘bar’}));
    //-> '{"foo": "bar"}'
    April 7th, 2010 @ 12:33 AM
  19. Sagar #

    Great!! When can I get the final version??

    April 7th, 2010 @ 01:51 AM
  20. superruzafa #

    Removing the documentation for stable version in this movement you-better-use-1.7_RC1-right-now-or-die is very annoying and I hope you fix it soon. At least you should support a transition phase between developers using 1.6.1 in their current production projects and those that will learn 1.7 and eventually 2.0 (me included) in their development projects.

    Meanwhile I found documentation for prototype 1.6.0 located here http://globalmoxie.com/projects/prototype-pdf/index.shtml

    April 7th, 2010 @ 03:13 AM
  21. Raul #

    Tobie Langel: Yeah, but earlier versions had it like:

    $H({foo: ‘bar’}).toJSON() //-> '{"foo": "bar"}'

    It is still specified like that in the Introduction to JSON turorial page. Version 1.7 will break a lot of code (including mine,) so, is it really gonna be like this?

    April 7th, 2010 @ 09:12 AM
  22. Tobie Langel #

    @superruzafa: We’re working on the doc issue (sorry for the glitches).

    @Raul: Yes, it will. The impact on existing code should be minimal, as most users are using Object.toJSON(…) rather than calling the toJSON instance method of hashes or arrays.

    April 7th, 2010 @ 10:18 AM
  23. Tobie Langel #

    Documentation for Prototype 1.6.1 is now available here.

    April 7th, 2010 @ 06:13 PM
  24. Nahum #

    this is neat… VIVA PROTOTYPE =), awesome job.. the same question, do you have in mind the release date… I’m so excited to have it in my hands…

    April 7th, 2010 @ 09:15 PM
  25. Rob Sterner #

    Nicely done, looking forward to using 1.7 and (hopefully soon!) 2.0!

    April 8th, 2010 @ 10:26 AM
  26. superruzafa #

    Thanks for the effort in make available the 1.6.1 doc again. I’m expecting the final 1.7 release. Good job!

    April 9th, 2010 @ 03:54 AM
  27. Veejay #

    Veejay approves of this.

    April 15th, 2010 @ 10:17 AM
  28. Filippo Buratti #

    nice work, thanks so much!

    April 15th, 2010 @ 04:34 PM
  29. Erik #

    Very exciting, and glad to see the code get divided into modular components! Thank you.

    My feature request is an easy way to omit the ajax code from prototype to reduce file size. Or can I do that already?

    April 18th, 2010 @ 02:11 PM
  30. Tobie Langel #

    @Erik: You’ll see something related make its way in Prototype 2.0

    April 18th, 2010 @ 06:36 PM
  31. Lisandro Puzzolo #

    It’s always great to know a new Prototype version is out.

    I’ve found a problem with ‘nth-last-child’ selector. It is not working at all on 1.7.rc1

    April 19th, 2010 @ 09:15 PM
  32. Tobie Langel #

    @Lisandro: that’s most probably an issue with Sizzle. You should report the issue there.

    April 20th, 2010 @ 07:08 AM
  33. Kemal Delalic #

    Really great move with moving to Sizzle AND leaving other engines optional, the on() method was really missed ( or something similar ), and the measuring methods are ( hopefully ) impressive, I haven’t tried it yet.

    Good job people, now prototype IS ( it always was ? ) the best JavaScript framework.

    April 20th, 2010 @ 03:05 PM

Sorry, comments are closed for this article.

Search Blog


Search the prototype blog.

Subscribe to the blog

Akismet badge