Low Pro: Unobtrusive Scripting For Prototype

http://www.danwebb.net/2006/9/3/low-pro-unobtrusive-scripting-for-prototype

Low Pro is a set of extensions to the Prototype library that make it easier to implement unobtrusive DOM scripting and forms the JavaScript component of the Unobtrusive JavaScript Plugin For Rails but can be used separately. It’s essentially a compilation of various tried and tested, previously published techniques adapted for use with Prototype and mainly centres around enhancing event handling and DOM manipulation. Low Pro uses portions of code and/or inspiration from Dean Edwards, Matthias Miller, Sylvian Zimmer, Justin Palmer and John Resig.

To start out with Low Pro, download the 0.2 distribution from my Subversion repository and included it along with the Prototype JavaScript file. Low Pro depends on Prototype so don’t forget to include it first:

<script src=”/js/prototype.js” type=”text/javascipt”></script><script src=”/js/lowpro.js” type=”text/javascipt”></script>
In the distribution is a standard commented version and a compressed version. Now for a quick tour of the features.

DOM navigation and manipulation
As Prototype’s DOM manipulation is very innerHTML centred Low Pro adds few useful methods to elements to help you navigate and manipulate the DOM in the nice clean W3C way.

$('doomed').remove(); // removes the element from the DOM and returns it$('item').nextElement(); // returns the next element in the document (excluding text nodes)$('item').previousElement(); // guess…$('thing').insertAfter(element); // the DOM gives you insertBefore but not this$('bong').replaceElement(element); // replaces an element and returns the substitute
You can get to all of these methods via the DOM object as well.

DOM.remove(element);DOM.insertAfter(oneElement, anotherElement);
Also, Low Pro aids you in creating node structures via the DOM with a Prototype version of DOM Builder. Each HTML tag has a builder function called $[tag]. You can nest these to create complex DOM structures easily.

var listItem = $li({ id : 'item-1' }, $strong(“Some text”) ); // returns a node equivilent to: <li id=”item-1″><strong>Some text</strong></li>$('a_list').appendChild(listItem);
Read more about DOM builder over at The Web’s Bollocks.

Events
The event handling code in Prototype is one of it’s weakest points so Low Pro replaces out Event.observe() and Event.stopObserving() totally with a version of Dean Edwards’ addEvent() and removeEvent() routines. This offers much more consistency across browsers and a few neat fixes:

Event.observe('thing', 'click', function(e) { this.hide() // this refers to the triggering element. return false; // stops the default behaviour (even in Safari!)});
All other methods remain backwards compatible. For convenience, observe() and stopObserving() are mixed in to elements. A trigger method is also provided to allow you to trigger event handlers programmatically.

Event.trigger(element, 'click');
Event.onReady() allows you to stack up callbacks that will trigger as soon as the DOM is ready rather than onload which triggers after the whole page is loaded.

Event.onReady(function() { $('thing').visualEffect('highlight');});
Repeated calls will simply stack up callbacks.

Behaviours
Low Pro adds declaritive behaviours to Prototype. Event.addBehavior() allows you to specify element behaviours via CSS selectors.

Event.addBehavior({ 'a.todo:click' : function(e) { new Ajax.Request('todo/add', … ); }, 'div.feature:mouseover' : function(e) { this.hide(); }});
These behaviours are applied as soon as the DOM is loaded and are reapplied to new elements after Ajax calls. An alternative more OO approach is to create a Behaviour ‘class’ which can be attached to elements. Each element gets it’s own instance of the behaviour class that retains it’s state throughout the life of the page. Within behaviour classes, this.element always points to the attached element.

var Resize = Behavior.create({ initialize : function() { // gets called when the element is loaded. }, onclick : function(e) { // use on methods to set event handlers on a object }});
Finally, I’ve included Sylvian Zimmer’s optimisation of the $$ selector which speeds up node selections quite dramatically. It is, in my experience, a little bit buggy though so if you encounter problems you can revert to the normall $$ code.

LowPro.optimize$$ = false;
So, that’s it. Any feature suggestions are much appreciated as are bug reports. Please log them on my Trac and I’ll fix them ASAP.

Update: Low Pro is compatible with any of the Prototype 1.5 releases but will not work with 1.4 or below.