Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX

By submitting your information, you agree that devx.com may send you DevX offers via email, phone and text message, as well as email offers about other products and services that DevX believes may be of interest to you. DevX will process your information in accordance with the Quinstreet Privacy Policy.


DHTML Interfaces: Taking The Next Step : Page 4

A new kind of DHTML toolkit can provide developers with a better approach to code and widget reuse.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Widgets, Widgets Everywhere
Now that you know about the objects providing registration and lookup, you can explore how the example ties everything together to create dynamic user interface components. You should be able to bind components to both data and behavior at creation time (and subsequently modify those bindings) while simultaneously shielding end developers from the complexity of creating the component or specifying its structure and formatting. To accomplishing this goal, the widget object definition must encapsulate its behaviors, and its visible representation, and the component's code representation (the HTML DOM nodes) must be created dynamically at runtime.

Before you can create a widget, you must first link it to the parent class defined earlier so that it can make use of the lookup and tracking functions. The file button_widget.js defines the sample widget and is the only top-level function/class definition in the file. JavaScript does not provide (good) native inheritance support; therefore you need two steps to subclass from the parent class. The first step is something of a hack, but if repeated several times would allow you to import variables and methods from several parent classes. The first three lines of the class illustrate this.

this.parent = ComponentClass; // set inheritance this.parent(); // call parent constructor // remove parent reference, avoid namespace pollution. delete this.parent;

You need a link to the "primary" parent class so that JavaScript can add the class to the scope chain for the buttonWidget class. You create the link with the prototype property. This allows classes that subclass buttonWidget to still be able to "see" its parent classes in the scope chain, which is useful when building composite widgets or when creating highly abstracted interfaces that require hierarchical organization.

//deep inheritance support buttonWidget.prototype = new ComponentClass;

You must examine two more methods of the class buttonWidget before you'll have a firm grip on how the framework enables truly generic widgets. The generate function is the factory that creates the visible DOM nodes that represent the widget. Separating the code that creates a widget's visible HTML and the code that models it is important because it lets you change the look and feel of the widget without modifying any calling code. That calling code often contains the most browser-specific code and workarounds, so encapsulating it helps improve portability by limiting the changes needed to provide broader client compatibility. The member function generate provides this factory, creating the HTML element and giving it style. The code to create and style the element used for the button is:

this.compNode = document.createElement("span"); with(this.compNode.style){ border = "1px solid black"; padding = "2px 5px 2px 5px"; backgroundColor = "#CCCCCC"; color = "black"; letterSpacing = "1px:"; fontFamily = "helvetica, arial, sans-serif"; fontSize = "12px"; lineHeight = "15px"; }

The "with" block simply shortens otherwise repetitive code. Since the code creates the button in the context of the buttonWidget object, you can simply assign the created element to the compNode member. Thus, when you add the compNode member of a button widget in the sample page, you are adding the DOM node created and styled by this code. Later, the function calls setID, which ties the compNode element to the unique ID given to the object, which facilitates speedy lookup via DOM nodes.

The next important section of the generate function assigns an event handler to the DOM node. A lookup function (compReg.getByNode) ties the handler back to the parent object, which then fires a member method of the buttonWidget object.

this.compNode.onclick = function(evt){ var src = null; // get a reference to the node that fired the event // IE specific method if(document.all){ // use implicit event reference in IE src = event.srcElement; // stop event bubbling in IE event.cancelBubble = true; } // standards-compliant method else{ src = evt.target; //stop event bubbling on Moz evt.stopPropagation(); } compReg.getByNode(src).doAction(); }

To some this may seem like far too much indirection than is strictly necessary, but to provide a scalable widget framework that avoids namespace or object collision, you must implement reference and lookup via a central object. Approaches that attempt to provide uniqueness in widget-specific ways often wind up relying on properties that cannot always be assumed to be unique or duplicating code (providing further opportunity for error). Using a single lookup and reference mechanism for all widgets lets you avoid both hard-to-debug collisions and bloat.

The doAction method of the buttonWidget is also interesting, because it shows how you can build event handling mechanisms that do not depend on assigning specific events to DOM (HTML) elements, but rather on catching an event with a general handler and then calling other functions from that handler. You can use this approach (with a bit more sophistication) to provide dynamic eventhandlers that know nothing about the widgets' internal structure. Here's the code for a simplified doAction method that fires actions to be performed when a user clicks the buttonWidget:

// perform the action registered on the widget this.doAction = function(){ if(this.fp!=null){this.fp();} if(this.evalStr!=null){eval(this.evalStr);} }

The buttonWidget members named fp and evalStr are the second and third arguments passed to the constructor in the example page. If either exist, then they are fired. These properties could just as easily be arrays of strings or function pointers to be called when an event is fired on the widget. The current generic event handling system for the netWindows framework API uses just such an approach. The cut-down framework sample in this article derives from that approach as well.

The approach taken by this system differs from that of other DHTML APIs because it creates widgets and components when they are requested rather than at page-load time. Neither does the sample page create a "pool" of objects which are then selectively hidden and made visible as some DHTML coders tend to do. Instead, the framework defines a component "template" from which new widgets and components of a given type are then "stamped" when needed, and not before. If DHTML interfaces are ever to handle interface state management, this type of behavior is essential. Moving interface state management to the client frees server-side resources to manage session state and perform data manipulation.

The simple API presented in this article for creating generic, reusable widgets and components is just a first step in creating a toolkit that provides DHTML developers with robust tools for creating long-lived event and data-driven interfaces rather than page-refresh driven interfaces. Using DOM-based DHTML and a bit of common plumbing you can create DHTML interfaces with the same level of abstraction currently enjoyed by mature interface toolkits aimed at compiled languages such as C++ and Java.

If you are interested in either developing interfaces using this approach or contributing to the development of the type of robust client-side interface toolkit needed to make the next generation of DHTML applications a reality, check out the netWindows project.. The netWindows API provides a rich set of pre-built widgets, and supports themes and out-of-band content loading, which allows applications to add or change data without losing interface state.

Alex Russell is a Web and security application developer. He is the primary developer and maintainer of the netWindows.org project, an Open Source component framework for DOM DHTML interfaces. Alex is currently looking for full time work in computer security engineering or back-end Web development. You can visit his weblog at http://alex.netWindows.org or reach him via email at alex@netWindows.org.
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date