Behaviors, simple jQuery extension.

November 14, 2010

Behaviors as an entity is a declarative way to assign/bind scripting methods to DOM elements.

We can think that browsers have following declarations in their default CSS declarations:

input[type=text]   { binding: TextEditorImpl; }
input[type=button] { binding: ButtonImpl; }
select             { binding: SelectImpl; }
...

So when we define <input type="text" /> in our markup we declare that the element will behave as a text editor – it will have set of all needed methods and will generate all associated events.  

It would be nice if in script we would be able to define our own behaviors for classes of DOM elements too.

As an example: blog article may have hyperlinks inside and particular blog engine may require some special behavior/reaction assigned to all hyperlinks in the article. Ideally such declaration should like this:

#content div.article a[href][title] 
{
  color: orange; // ui style
  behavior: LinkWithSmartTooltip; // behavioral style
}

In Sciter [1] that is an embeddable HTML/CSS/TIScript engine I have a luxury to step beyond W3C specifications so I’ve implemented the Behaviors in the way as I think they should be:

Behaviors in the Sciter engine

I have added the prototype attribute to my implementation of CSS:

some-CSS-selector 
{
   prototype: SomeBehaviorClass [ url(of a script file) ];
   ...
}

When the engine assignes CSS styles to elements it also tries to find class named SomeBehaviorClass. If such class is found then the element gets "subclassed" by the class. Technically the subclassing means that for all DOM elements that satisfy some-CSS-selector both these statements are true:

element instanceof SomeBehaviorClass; 
element instanceof Element; // Element is a super class of all DOM elements.

The SomeBehaviorClass looks in TIScript like this:

class SomeBehaviorClass: Behavior
{
   function attached() {} // constructor, sort of
   ...
}

The attached method plays a role of a constructor function in realm of Behaviors. It is called when particular element gets the behavior with this variable referring to the element. All this is I would say is pretty human readable an transparent.

Ok, back to the reality of the Web. Below is my attempt to define similar functionality using jQuery:

Behaviors for conventional browsers,  jQuery extension.

First of all here is my initial implementation of the behavior functionality: jquery-behaviors.js. It is pretty simple – near 75 lines of code.

It allows to declare behaviors on elements by using (a) class DOM attribute like this (purely in markup):

<span class="behavior uix-slider" /> 
<input class="behavior uix-date" />

and/or by (b) declaration of selector rules in script code:

$.behaviors.selector("ul.ext-list > li", MyExtListItem );

Later case allows to add behaviors non-intrusively – to any existing markup.

The Behaviors implementation above introduces three methods:

  1. $.behaviors.add( name, behaviorObj ) – add named behavior that can be used in "a" case above – in class names.
  2. $.behaviors.selector( selectorStr, behaviorObj ) – add "CSS selector -> behavior" association – case (b) above.
  3. $.fn.behaviors() – that is a plug-in that extends jQuery object wrapping set of elements. It used after calls of DOM mutating methods to assign behaviors to DOM elements:
    $("#update-panel").html("....").behaviors();

The behaviorObj above is the behavior implementation per se. It is a plain JavaScript object that defines set of methods and properties that will be mixed into the DOM element property map.

Here is a typical structure of some behavior named "x-checkbox" (see it’s demo here …) :

$.behaviors.add( "x-checkbox", 
{
  $attached: function(params) { ... },
  $value: function(v) { ... },
  $clear: function() { ... }
});

Function $attached here has special meaning – it gets called by the Behaviors engine when the element gets this behavior attached. The params here is a parsed version of the params DOM attribute that allows to parametrize instance of the behavior for the element. For example particular instances of a slider may have different initial settings:

<span id="first" class="behavior uix-slider" 
     params="min:0, max:100, values:[15,50]" />
<span id="second" class="behavior uix-slider" 
     params="min:10, max:200, value:50" />

Input behaviors, concept of the value. The "x-form" behavior.

In principle there are two distinct types of behaviors:

  • input behaviors – behaviors of elements that have a concept of the value. Input elements have at least these two methods:
    • method $value(v) – getter/setter of the value.
    • method $clear() – clear the value – revert it to the initial, markup declared state.
  • UI behaviors – behaviors implementing various UI effects like "click here – expand/collapse there".

The $value and $clear methods are used by the x-form behavior for gathering and setting values of input elements it contains. The x-form element is by itself is an input element (compound one). Its value is a map of name/value pairs – values of standard inputs and elements that have input behaviors attached. Behavior x-form can be assigned to any container that has inputs and call of its method $("#my-form")[0].$value() will give collection of values that are e.g. ready to be send over the AJAX.

The x-form and individual input behaviors may also implement concept of $validate() – that is not implemented yet but planned.

Demos

Here is couple of demonstrations of the approach:

  • jq-ui.htm – demo of jQuery-UI widgets wrapped into input and UI behaviors (implementation: jquery-ui-behaviors.js).  Also demonstrates use of x-form to gather/set/clear form data and dynamic html loading with behavior assignment.
  • std-behaviors.htm – purely declarative sample. Demonstrates x-checkbox behavior – is a input and UI element that can be bound declaratively with show/hide of "buddy" elements. Uses std-behaviors.js – implementation of the x-form and x-checkbox.

References

  1. The Sciter – an embeddable HTML/CSS/Scripting engine;
  2. TIScript language – JavaScript++ if you wish. Used in Sciter.
  3. Behaviors in Sciter, part I, part II and part III