Greetings programmers. It’s been too long.
First, a quick personal update: For the last 2.5 years I’ve been busy at Cloudera helping them build a bunch of tools for Apache Hadoop which I’ve written about here and elsewhere. Over that period I wrote a lot of JavaScript, nearly all of which could be found on github but it wasn’t ever packaged up for your easy consumption. In that same period, I posted here infrequently as I was so busy contributing to MooTools and doing my job. All good things must come to an end though, and as of mid-May I decided it was time to move on and try and focus my career back where I’m happiest which has, historically, been building web sites and applications for consumers and culture. In a week or two I’ll likely be taking on a role that sees me programming a lot less, at least for my day job.
Anyway, over that 2.5 years of cranking out tons of JavaScript, I was always itching to put the polish on the things that were most interesting to release them for your consumption. I spent the last few days doing that and finally updating my download builder to work with the new MooTools dependency system so that I could release my latest work. So let’s get to it!
Clientcide 3.0
After a shameful delay, mostly due to the fact that my download packager was built around the old “scripts.json” dependency system, I’m finally ready to release the latest Clientcide code. I push to this codebase regularly as I fix bugs and add features, but rolling a release was always at the bottom of a long list of priorities. The big thing to note is that this release is finally on MooTools 1.3 – no compat layer needed as only native 1.3 methods are used. Woot.
The second thing you’ll likely notice is that there’s a lot fewer things on the list. I’ve deprecated stuff that I wasn’t willing to continue supporting; stuff that I just doubt many people were using. The list of deprecated plugins is rather long – about 25 files. Fear not! All those files are still on github on the 1.2x branch of Clientcide if you need them. If you find that you want something on that list, I encourage you to take the files and release them yourself.
For more details, check out the release notes in the readme in the Clientcide repo on github. This release is actually tagged 3.0.1.
Behavior
As mentioned here a while ago, while at Cloudera we implemented an abstraction for code invocation (typically the stuff you put in a domready statement) that reads configuration from declarative HTML. It’s changed the way I build things so much that I doubt I’ll ever build anything without it. The nutshell is that instead of having a domready function that finds the stuff in your DOM and sets up instances of classes and whatnot, you put the configuration in the HTML itself and write the code that calls “new Foo(…)” only once. Example:
Instead of this:
$$('form').each(function(form){
new FormValidator(form, someOptions);
new Form.Request(form, someOptions);
});
new Tips($$('.tip'));
$$('.accordion').each(function(container){
new Accordion(container.getElements('.toggler'), container.getElements('.section'), someOptions);
});
etc
You do this:
<form data-behavior="FormValidator FormRequest" data-formvalidator-options="{someOptions}">...</form>
<a data-behavior="Tip" title="I'm a tip!">blah</a>
<div data-behavior="Accordion" data-accordion-options="{someOptions}">...</div>
Why?
Think of it as delegation (as in event delegation) for class invocation. If you use domready to do your setup and you want to swap out some HTML with XHR, you need to reapply that startup selectively to only your components that you’re updating, which is often painful. Not with Behavior, you just apply the filters to the response and call it a day.
You do a lot less DOM selection; you only ever run $$(‘[data-behavior]‘) once (though some filters may run more selectors on themselves – like Accordion finding its togglers and sections).
Domready setup is always closely bound to the DOM anyway, but it’s also separated from it. If you change the DOM, you might break the JS that sets it up and you always have to keep it in sync. You almost can’t do that here because the DOM and its configuration is closely bound and in the same place.
Developers who maybe aren’t interested in writing components don’t need to wade into the JS to use it. This is a big deal if you’re working with a team you must support.
Behavior is designed for apps that are constantly updating the UI with new data from the server. It’s NOT an MVC replacement though. It’s designed for web development that uses HTML fragments not JSON APIs (though it can play nicely with them). If you destroy a node that has a widget initialized it’s easy to make sure that widget cleans itself up. The library also allows you to create enforcement to prevent misconfiguration and an API that makes it easy to read the values of the configuration.
There are some other nifty things you get out of it; you get essentially free specs tests and benchmarks because the code to create both of them is in the Behavior filter. Here’s an example of what it takes to write a spec for a widget and ALSO the benchmark for its instantiation.
Behavior.addFilterTest({
filterName: 'OverText',
desc: 'Creates an instance of OverText',
content: '<input data-behavior="OverText" title="test"/>',
returns: OverText
});
This code above can be used to validate that the HTML fragment passed in does, in fact, create an OverText instance and it can also be used with Benchmark.js to see which of your filters are the most expensive. More on this stuff in a minute.
Included in the library is also a file called Delegator which is essentially the same thing except for events. For example, let’s say you have a predictable UI pattern of having a link that, when clicked, it hides a parent element. Rather than writing that code each time:
document.body.addEvent("click:a.hideParent", function(e, link){
e.preventDefault();
link.getParent().hide();
});
You register this pattern with Delegator and now you just do:
<a data-trigger="hideParent" data-hideparent-options ="{'target': '.someSelector'}">Hide Me!</a>
It provides essentially the same value as Behavior, but at event time. The above example is pretty straight forward so, you know, why bother, right? But consider how many of these little things you write to make a web app function. If you can create them once and configure them inline, you save yourself a lot of code. For example, one of the things I’m releasing today is a delegator that makes it easy to have a link that updates any specified DOM element; basically AJAX without the J.
MooTools Development
I also wrote a while back about a portable MooTools development environment. Since then this little project has progressed to add a lot of useful features for a development sandbox. With a little bit of configuration work, you get docs, demos, specs testing, and benchmarks. It’s seriously pretty awesome and I use it now exclusively for working on front-end coding. By working in the sandbox, writing docs and specs, I’m much more likely to end up with generic, reusable code that isn’t too tied to any specific application. Enough talk, here, check it out running here on Clientcide:
dev.clientcide.com
As you can see you get docs with a simple quick-search, demos of all the components with the ability to view the source of any demo (and not just the HTML for the demo but also any other “interesting” files you choose to highlight), specs tests that anyone can run in their browser, and benchmarks which will show you how your code performs. Using this environment makes it easier for me to just focus on the code and use these tools over and over again.
The other thing that’s really nice about it is the ability to create a code configuration and share it with others. For example, you can run this development environment locally yourself with just the few following commands (assuming you have python 2.6 installed):
$ git clone git://github.com/anutron/mootools-development.git
$ cd mootools-development
$ git checkout -b behavior origin/behavior
$ ./go install # or just "./go i"
$ ./go depender_check # or just "./go d" - this checks the JS dependency tree
$ ./go run # runs the server on port localhost:9876
This will give you the development environment set up for Clientcide and Behavior (basically what’s running at dev.clientcide.com). If you don’t check out the behavior branch before you build, you’ll just get MooTools Core and More.
More Behaviors
Finally, the last shiny new present I have for you is a starter collection of Behaviors that you can use in your own apps. While working at Cloudera I authored maybe 50 of these things, but I haven’t had time to polish all of them up. Included in today’s release you’ll find Behaviors in the Clientcide release and another, stand-alone repo called “More Behaviors” which is principally used for instantiating widgets from MooTools More. Not everything has a Behavior filter, but you’ll get the idea of what they’re for and how to use them. Maybe chip in and help me write more of them! There’s a handful of Delegator triggers in there, too, and while they aren’t really related to MooTools More they dovetail nicely with the other plugins and show you how to use them.
Where?
Ok, so I’m releasing all this stuff, but how do you get it? Well, you can download a single JS package with everything you need, as always, on the download page. You can dig into the docs and demos at the new dev.clientcide.com. Finally, you can get it all on github:
But if you want to be really cool, you’ll just check out the development environment and run it locally. It’s what all the kids are doing these days.
Etcetera
I’m excited to release all this stuff finally and hope that you find it useful. Some of it may migrate over to official MooTools status, but maybe not; we’ll see. If you find yourself using these things please give me feedback and maybe send me a pull request to make it better. Getting involved in helping the code grow is the fastest way to ensure it meets your needs and that I keep working on it.