Montag, August 22, 2005

JavaScript Behaviours

This technique has nothing (not yet) to do with AJAX because it is a general usable implementation for reusing JavaScript code for components. Also, this technique has also nothing to do with ASP.NET because it only uses the client-side (browser) available HTML objects and JavaScript. It will be the client side functionality for the upcoming AJAX controls and it fits perfectly into a server-side HTML controls framework that enables also the reusing of HTML code fragments.

General

HTML pages without any more than HTML offer only a limited functionality and allow only displaying information and filling out forms. As a result HTML pages are often extended by using JavaScript for handling input validation, reacting on clicks or bringing optical effects.

But when it comes to reuse once-written functionalities there is no built-in concept to HTML and JavaScript except the flat programming model of include files. Copying sourcecode around is the often used response to this weakness and leads to unsupportable huge web sites often too.

Proprietary behaviours

Both most used browsers, Internet Explorer from Microsoft and the Mozilla/Firefox from the Mozilla foundation, have both their own incompatible way to allow reusing JavaScript functions and HTML on a component level.

Common to both solutions is the big advantage over global script include files that the functionality is bound and accessible through a specific HTML object, can be bound to multiple objects and support specific methods, attributes and event handlers.

Lightweight, compatible behaviours

Building a cross-browser functionality that is very similar to the built-in behaviours of the browsers is not very hard to do.

It basically consists of defining new properties, specific methods and event handlers by building a JavaScript prototype object for each behaviour. Also a common binding functionality is needed that attaches these definitions to a HTML object after the page is loaded. Script include files can be used to bring the prototype objects into the pages.

A simple example

This is the HTML object

<div id="TimerSample" style="...">click here</div>

Here is a simple behaviour that is handling the onclick event and brings in a new update method that is changing the content of the bound HTML object:

var TimerSampleBehaviour = {
  onclick: function (evt) {
    evt = evt ||window.event; // get a compatible event object
    evt.srcElement.update();
  }, // onclick

  update: function() {
    var d = new Date();
    this.innerText = d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds();
  } // update

} // TimerSampleBehaviour

The behaviour functionality must be bound to the HTML object by calling one method only:

LoadBehaviour(document.getElementById("TimerSample"), TimerSampleBehaviour);

The "magic" work behind the LoadBehaviour() method is to loop though all elements of the given JavaScript object and assigning each of them to the HTML object.:

  • Methods. Starting with "on" are assumed to be event handlers and are attached using the browser specific methods for attaching events. Only the bubbling phase of the event is used because it is implemented by both browsers.
  • Other methods are just bound to the HTML object as function objects.
  • All the other objects are assigned if there is not already an assigned property existing on the HTML object. These objects are shared for all HTML objects that are bound to the same behaviour.

We might expect more functionality from behaviours but this is a set of functionalities that are available in all the supported browsers.

This simple sample can be found on the sample website:

http://www.mathertel.de/AJAXEngine/ in Samples Part 2.

The relevant code can be found in the html page itself and in the include file cb.js.

Writing event handlers

Event handlers use a naming convention to be distinguished from object specific methods by starting with "on". The name of the function should always be lowercase and the function must have a single parameter holding the event object.

Because the IE is not passing the event object through the parameter of an event method we always need a first line to get a compatible event object:

evt = evt || window.event; // get a compatible event object

The clicked HTML object is available by using the srcElement property of the event object.

This is not a native property of Mozilla/Firefox but is made available using a specific patch that is also included – beside other patches – in the common include file cb.js.

I think that it’s a good idea not to implement much in these handlers but to call another method soon because the event handlers always expect an event object and therefore are not reusable for being called from other events or methods.

Writing methods

Writing a method for a behaviour is as simple as writing compatible JavaScript.

Properties or attributes as well as other methods of the bound HTML object are accessible by using the "this" object reference to the HTML object. Never call any method of the prototype object directly, they all are also available through "this".

To make it easy to write compatible JavaScript methods there are some extensions implemented in the common include file cb.js. Mozilla/Firefox has a very powerful extensibility concept that allows easily to define new properties to built-in objects and to control their usage. IE is far behind this point so I use this extensibility to bring IE specific properties to the Mozilla/Firefox platform. Details can be found in the common include file cb.js inline comments.

Defining default values

New properties on the behaviour objects need not to be defined; they just can be used – but always through "this". The properties that are used as parameters to define a aspect of the functionality can be assigned default values in 2 ways:

  • An attribute can be set on the HTML object
  • A property on the JavaScript prototype can be set to an initial value and is used if no attribute is already defined on the HTML object.

When defining complex objects (arrays, structures) inside the JavaScript prototype you have to pay attention to the fact that these objects are shared among all HTML objects using this prototype. If individual complex objects are needed it is better to create and assign them in the "init" method.

The init method

A method named "init" can be defined in the JavaScript prototypes to implement special needs after the methods, event handlers and properties are bound to the HTML object. This method is automatically called by the LoadBehaviour method.

When the "init" method is called it is not guaranteed that the whole page is already loaded and that all other behaviours are bound to their HTML objects. If you need this point in time you have to attach a special handler to the onload event of the page.

Links

The Mozilla/Firefox behaviours: http://www.mozilla.org/projects/xbl/xbl.html

The IE behaviours: http://msdn.microsoft.com/workshop/components/htc/reference/htcref.asp

Search for behaviours using Google: http://www.google.com/search?q=htc+filetype%3Ahtc

Keine Kommentare: