A Flurry of Prototype Updates
With so much discussion happening recently about the state of Prototype, it’s great to see some updates finally rolling in. Hopefully this is only the beginning of what’s to come.
Here is the changelog as of around 7:00 CST:
Make destructive Element, Form, and Form.Element methods return their first argument, so that multiple calls can be chained together. [sam]
ex. $(“sidebar”).addClassName(“selected”).show();
The following methods now return their first argument: Element.toggle, Element.hide, Element.show, Element.remove, Element.update, Element.replace, Element.addClassName, Element.removeClassName, Element.observe, Element.stopObserving, Element.cleanWhitespace, Element.scrollTo, Element.setStyle, Element.makePositioned, Element.undoPositioned, Element.makeClipping, Element.undoClipping, Form.reset, Form.disable, Form.enable, Form.focusFirstElement, Form.Element.focus, Form.Element.select, Form.Element.clear, Form.Element.activate, Form.Element.disable, Form.Element.enable.
For consistency, Element.toggle, Element.show, and Element.hide no longer take an arbitrary number of arguments. [sam]
!! BACKWARDS COMPATIBILITY CHANGE !!
If you have code that looks like this: Element.show(‘page’, ‘sidebar’, ‘content’); You need to replace it with code like this: [‘page’, ‘sidebar’, ‘content’].each(Element.show);
- Mix in Form and Form.Element methods to forms and form field elements with $() and $$(). Closes #4448. [Dan Webb, sam]
- Add Object.clone [sam]
- Add Form.Element.disable and Form.Element.enable. Closes #4943. [jan@prima.de]
- Field is now simply an alias for Form.Element. [sam]
- Add Element.Methods.getElementsByClassName and Element.Methods.getElementsBySelector. Closes #4669. [Andrew Dupont, DHH, sam]
- Avoid race condition when stopping an Ajax.PeriodicalUpdater. Closes #4809. [e98cuenc@gmail.com]
- Improve support for synchronous requests. Closes #5916. [sam, jthrom@gmail.com]
- Add serialization and observation support for input type=search. Closes #4096. [rpnielsen@gmail.com]
- Properly decode query components in String.prototype.toQueryParams. Closes #3487. [sam]
Add Array.prototype.reduce [sam]:
- [1, 2].reduce() // [1, 2]
- [1].reduce() // 1
- [].reduce() // undefined
Add Object.keys and Object.values [sam]
- Simulate non-GET/POST requests by POSTing with a _method parameter set to the actual verb [DHH]
- Make Element.update() handle TABLE-related elements with the DOM API because of IE’s missing .innerHTML property on them [Thomas Fuchs, thx to Rick Olson]
- Sync to script.aculo.us unittest.js library as of 2006/08/29 [Thomas Fuchs]
- Add additional unit tests to test/unit/dom.html for testing Element.update and $().update in various enviroments [Thomas Fuchs]
- Prevent possible exceptions on unloading the page in IE [Thomas Fuchs]
Object.keys and Object.values
New to Prototype is Object.keys and Object.values. There are a couple things to be aware of however. These methods won’t work on Prototype classes the way you might expect. So for instance, this will not work:
var Foo = Class.create();
Foo.prototype = {
intialize: function(str) {
console.log(str);
},
bar: function(str) {
console.log(str);
}
}
console.log(Object.keys(Foo));
// ["prototype","bind","bindAsEventListener"]
The reason for this is that Foo is a Function and you’ll get the keys for the Function object. A relatively easy work around for this is ask for the keys on Foos prototype object:
console.log(Object.keys(Foo.prototype)); //["intialize","bar"]
Of course, you don’t get the class methods with this so you can use something like this. Not a particularly useful class, but you get the idea:
var Inspector = Class.create();
Inspector.prototype = {
initialize: function(obj) {
var instanceMethods = Object.keys(obj.prototype);
var classMethods = Object.keys(obj).reject(function(method) {
return ['bind', 'bindAsEventListener', 'prototype'].include(method);
});
console.log(instanceMethods, classMethods);
}
}
Form and Form.Element methods mixed in to $ and $$
This is great and well help put an end to some of those very verbose Form operations. Now you can do stuff like:
<form action="/search" id="searchform">
<input type="text" value="this is text" name="q" id="search" />
<input type="submit" value="submit">
</form>
//Javascript
console.log($('searchform').getElements());
// [<input type="text" id="search" name="q" value="this is text">,<input type="submit" value="submit">]
Shorter syntax for Event Observing
Dan Webb’s very old patch for event observing went in. This means we can now do:
$('element').observe('click', function(e) { alert(e); });
Full support for chainability
All the methods listed in the CHANGELOG overview above now return their first argument.
$('sweet').observe('click', function(e) {
console.log("%s was clicked", Event.element(e));
}).setStyle({color: 'red'});
This is just a quick overview of what is going into Prototype as we speak. It seems Sam is on the move today and there is a flurry of activity so we’ll likely see more before the day is over with. I’ll try to update this post as soon as I learn more.
Sorry, comments are closed for this article.



Discussion
Long live chainability! Prototype can learn a lot from jQuery, and binding custom methods to elements was a good start.
There are some (more) things I would love to see in Prototype:- Real multiple selectors for $$()
- More array steriod:
In the old days (the era of 1.3.0) you already could chain array methods to do a horde of operations. Because of those wonderfulObject.extend(Array.prototype, { sum: function(initial) { return this.inject(initial || 0, function(x, y) {return x + y;}); }, random: function(range) { var i = 0; if (!range) range = this.length; else if (range > 0) range %= 1; else i = range; range = this.length + range % this.length; return this[Math.floor(range * Math.random() - i )]; }, shuffle: function(deep) { var i = this.length; var clone = this.toArray(); while (i) { j = Math.floor((i--) * Math.random()); t = deep && clone[i].shuffle === undefined ? clone[i].shuffle() : clone[i]; clone[i] = clone[j]; clone[j] = t; } return clone; }, unique: function() { var result = []; for (i = 0; i < this.length; i++) { if (result.indexOf(this[i]) < 0 ) result.push(this[i]); } return result; } });Really handy for advanced array operations.Enumerablemethods you could do wonderful things like this instead of writing endless loops:var totalImageContainerWidth = $$('img').collect(function(element) { return element.parentNode; }).invoke('getDimensions').pluck('width').compact().inject(0, function(x, y) { return x + y; });Now with more chainability blessing Prototype developers can write concise DOM operation code they have long envied on jQuery.Good to see that the synchronous bug is fixed, I used to have problems with it.
Will these be packaged for release soon? Or are we to go to the source?
I’m delighted to see some activity in Prototype! It seemed to be dormant for a few months, and I was getting worried about depending on it in my projects.
Michael: Why would you be worried about it? If there are any major bugs then you could fix them yourself. Its not like the library is hugely unstable or unusable because of the lack of updates.
Good to see that there are some updates being made to Prototype, new features are always welcomed.
Worried is the wrong word. You are correct that the library works and is stable, so old projects would be fine.
I guess what I really meant is that JQuery and other libraries have been improving by leaps and bounds, and Prototype (was) stagnant. In fact, some of these improvements are just catching up to jquery.
Although I really like prototype, I was beginning to think the maintainer had moved on, and I should switch to an alternative. Until very recently, there were numerous bug patches submitted to the project, but none had been applied for months.
Wow! Great!
Thanks so much for keeping us updated!
how come the main site for Prototype (http://prototype.conio.net/) doesn’t even have the latest version of it for download. It still has v 1.4.0. The lack of support by its creators is really starting to bug me. I am very close to switching.
Mario: As with most projects, there are stable builds (1.4, the one listed on the prototype homepage) and edge builds (1.5, the one in svn right now).
So, actually—the latest stable version is available for download on the homepage.
I can’t wait for all this new stuff. I’m off to go play around with my new toys now.
Great news! As Justin said, sam might have a surprise or two up his sleeve:) I believe that the flurry will be followed by more impressive activities.
where exactly can I find this edge version?
Same question as Wesley, is there a quick beside svn to get a hand of this version ?
Sam IS the man!
Does the $F work with radio button groups yet?
Keep up the great work; Do you know how many hours of coding (and even more in testing) you’ve save us all?
With you and Fuchs doin’ half my gig, I should probably throw down some commission.
;-)
Stable hmmm… if you are using 1.4.0 with Ajax and IE7.0 you might be in trouble because of the arbitrary re-firing of GET requests. I guess it’s like Philip Plante says, you really need to know what’s going on in the code, and fix the bugs yourself.
here is a small exention just by looking at prototype and knowing what i wanted to do with it.
Element.Methods.setLocation = function(element, t, l){ Element.setStyle( $(element), { top: t + 'px', left: l + 'px' }); } // add methods Object.extend(Element, Element.Methods); Element.addMethods();now you can set a location (as long as the element’s position is absolute and its a block element)
$('panel').setLocation(50, 100);then add other functions like a Element.Methods.center() function and now you have something to center your modal or anything else needed to be centered.
so rather than complaining or constantly comparing libraries, please try to at least give solutions like the first comment for this article. Or better yet, start a community initiative.