Behaviour: Using CSS selectors to apply Javascript functionality

An amusing library that lets you use CSS selectors to specify elements to add javascript events to.

The terms pattern matching, and declartive programming come mind.

You can also think about it as an embedded DSL.

I came across Behaviour via this simple example which shows the style of programming the library leads to.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

yay Javascript

This is why Javascript is a good thing--people are seeing the power of higher-order functions, and having fun using them liberally. Look, a doubly-nested closure!

Actually, I think it would simplify his idiom if he eliminated one of the levels of nesting and abstracted away some of the mutation from the client. Instead of:

var myrules = {
    'b.someclass' : function(element) {
        element.onclick = function() { ... };
    },
    '#someid u' : {
        element.onmouseover = function() { ... };
    }
};

he could change it so that the selectors get themselves mapped to associative arrays, which in turn map the event name to the event handler:

var myrules = {
    'b.someclass' : {
        onclick : function() { ... }
    },
    '#someid u' : {
        onmouseover : function() { ... }
    }
};

Now it's that much more declarative. The client doesn't lose anything by eliminating the lexically scoped element variable, because they can access the DOM node via the dynamically scoped this, which he used in his examples anyway.

The library can easily take responsibility for setting the event handlers by using the for .. in form to iterate over the properties of the associative array of event handlers, which moves the mutation into the library and away from the grubby hands of the client.

for (var p in eventHandlerArray) {
    element[p] = eventHandlerArray[p];
}

another use

Another cool use of this "behavior" idea is that you can use CSS classes like traits or mixins, adding behavior to any node you like. You can always give any HTML node multiple classes by separating them with spaces:

<div class="codeSnippet italicized clickable"> ... </div>

So you can combine these behaviors (almost) modularly.

modularity

If you have multiple behaviors competing for the same properties, all bets are off. For example, if a clickable property overwrites the onlick property, and a draggable behavior overwrites the onclick property, boom! whoever gets there first destroys the other one.

This means the interface of a behavior includes the set of properties it overrides, and it's probably most reasonable to say that a well-formed composition of behaviors can never combine behaviors that override the same property.

Alternatively, if you use functional composition to extend event handlers instead of overwriting them, you can actually compose behaviors. (But the order of composition should probably not affect what the behaviors do--just ask the AOP folks.) However, it would be harder to remove a behavior later.

If you want the ability to remove behaviors you've added, then you could make a behavior be a function that has a "registry" property (all functions are objects in Javascript, so they can contain properties). The body of the function would never change; it would always just iterate over the registry and apply each registered behavior in turn. Then adding and removing behaviors would go through the registry.

Blowing my own trumpet

I blogged about this a bit before it appeared on LtU. I'm repeat the interesting bits of my comments here:

This gives cleaner code, though I'm not sure how useful it will be in practice, for two reasons:

  • It will be slower than just writing the event handlers directly in the HTML. How much slower I haven't measured, so this may not be a problem.
  • I don't write much Javascript directly (except when trying out new ideas). Instead I tend to generate it (along with HTML) from other sources, so achieving a separation between Javascript and HTML isn't an issue for me.

However I don't want to give a negative view of this library. I think it is really neat, and it has interesting similarities to Aspect-oriented programming (AOP).

Dave has said more about the AOP relationships here, on his blog, and on Untyping.

an optimization

If it turns out to be too slow, perhaps the behaviors could be applied to the HTML on the server.

Trade CPU cycles for brain cycles

While it might be slower for the CPU than just writing the event handlers directly in the HTML, it's immensely faster than hand-managing all the inline JavaScript code.

With properly separated and well-designed CSS/JS/HTML, the server-generated HTML can remain simple and the backend programmers don't need to worry about CSS presentation and JS behavior. As long as the HTML has been structured properly and given the right class attributes & etc, the CSS and JS can be relegated to simple reusable includes.

All of this really helps out when you're working on a team with people specialized in backend programming, HTML UI, and visual design, respectively.

Check this link about Unobtrusive Javascript for more info.

I blogged about this a bit be

I blogged about this a bit before it appeared on LtU...

And you failed to mention it here first?! Shame on you...

The Shame I Bear

And you failed to mention it here first?! Shame on you...

Indeed. I thought about posting it but didn't think it would be high-brow enough for LtU. In future all items of (possible) interest shall appear!

High-brow?

Us?! Nah...

here's a prototype

I've implemented a prototype of what I described above. Event handlers are described in a more declarative style (as maps from event names to handler functions), and they are combined with composition, rather than overridden.

Cool!!

Cool!!

One problem with the more dec

One problem with the more declarative style, at least with respect to my "Drag the boxes, stretch the lines" linked above:

If you look at the page source, you can see that I don't strictly declare "onFoo" handlers.

For ".note" elements, I set some style attributes as well as instantiating some Draggable objects.

For the "img.line" lines between boxes, I use the "alt" attribute to parse out the names of two other elements. And then, on those two elements, I append functions to a chain which gets called every time the draggable element moves. This allows the line to get updated when one of its two end points moves.

While the composition features would have come in handy in my example, I'd still need the non-declarative style to fire off my anonymous functions for each matched element.

sure

Good point, I did make the language strictly less expressive. I'll probably add that back in somehow in a bit. At the moment, though, I'm off to celebrate our independence from.. uh, Noel, I guess.

:-)

from.. uh, Noel, I guess.

Good one...

Tk

Looks quite a lot like the functionality provided by [bind]/[bindtags] in Tk for over a decade. The pattern matching here is a bit more sophisticated (Tk allows binding to an individual instance or a class), but other than that I don't see much difference. e.g. in Tk I could do:

bind MyClass <Button-1> ...
bind MyClass <Enter> ...
bind MyClass <Leave> ...
somewidget .foo -class MyClass ...

You can trivially go from that to something more like:

widgetclass MyClass {
    <Button-1>  { ... }
    <Enter>     { ... }
    <Leave>     { ... }
}

Why the fuss?

Fuss

The fun part is that this isn't part of the language, but rather a cool hack.

no Tk in Firefox

I can't remember the last time I was allowed to use Tk in my day-to-day web development job. :)