Donnerstag, Dezember 27, 2007

Useful OpenAjax Event Logger

While working on further adopting the OpenAjax event mechanism I wrote this small JavaScript include file that helps inspecting the current OpenAjax events.

It is implemented by using a single JavaScript include file that can be found at http://www.mathertel.de/AjaxEngine/controls/OpenAjaxEventLog.js (view source).

It is easy to include this file into ANY web page by using a small JavaScript link (a.k.a. bookmarklet) that you can type into the address bar or save as a link in your favorites:

Create any Link in your favorites, or the link bar and name it for example like this:

Here is the url that you can paste into the url field in the property dialog of the link.

javascript:void(document.body.appendChild(document.createElement('script')).src='http://www.mathertel.de/AjaxEngine/controls/OpenAjaxEventLog.js')

There will be one dialog that warns you about the fact that the url is using JavaScript (an unregistered program - what means that ?) and that this may be unwanted. But in this case it is what we need.

You can open any of the sample pages from the http://www.openajax.org/member/wiki/InteropFest_1.0 and try it.

If you click on the link you just created a extra area will be appended at the bottom of the page and all OpenAjax events will be shown in there.

 

If you like to know more about bookmarklets you can google this term and you will find a lot more tricks.

My favorite is:

javascript:'<xmp>'+document.documentElement.outerHTML+'</xmp>'

Mittwoch, Dezember 19, 2007

Passing values around with OpenAjax events

When publishing and receiving OpenAjax events there is the built-in mechanism of passing a payload a.k.a publisherData around together with the event. When implementing applications based on OpenAjax events there are some more things you should care about when using the publisherData feature. In the specifications you can also find some guidelines.

1. Don’t change the publisherData when handling an event.

That’s already said in the specification. Another and not so explicit mentioned argument for not doing so is the fact that there may be multiple subscribers to the same event. Because the sequence of the elements that receive the event is not determined you do not know whether a control gets the original or the modified publisherData. Anyway these situations are hard to debug – another reason to avoid them.

2. Don’t use objects – use strings instead

Right now the OpenAjax hub implementation is client side only but you can expect that events can also be spread other windows on inner iframes. In both cases direct object references are a problem because they cannot pass completely. If you need more than simple values consider using a proprietary format like "29.0016;18.5337", a JSON or an XML string.

And don’t assume when passing a numeric value that the subscribers get them as a JavaScript Number object.

It seems that strings are fine. :-)

3. Don’t use language specific formats

Users like to enter values into fields by using their culture or national language specific notations. Most keyboards here in Germany have a comma in the numeric keypad and a many people would not agree in typing dots when filling out fields for example with prices.

If you pass a "1.777,88" around you must assume that all subscribers can understand this specific notation. You can’t assume that if you like to live in meshup scenarios where the connected components come from different world wide vendors or sites. You even can’t assume that when writing a web application for the German speaking market: the Swiss people like the format: "1'777.88".

A good idea is to pass the values as defined by JSON and make them directly useable by scripting.

4. Don’t pass date values

Passing date values is somewhat problematic because there is no JavaScript constant definition (a.k.a. JSON) for that datatype. :-(

I recommend using the XML notation that is based on ISO 8601 date and time formats: "2007-12-24T18:00:02", but I must admit that that's my personal preference based on the fact that I prefer XML and SOAP.

Mittwoch, Dezember 12, 2007

Using OpenAjax events for building data-centric and forms based AJAX applications

Most of the business web applications on the Internet are HTML forms based applications where html elements are bound to data is the core functionality. I am talking about registration forms, dialogs and pages to display and modify records of a server side relational database system like in ERP or CRM systems.

Usually there is not a lot of drag & drop activity or popping visual effects here but the most active elements deal with data that comes from databases or other data sources. We need to display, edit and control records from a company's database and implement transactions on these entities.

Here is an approach to use the OpenAjax event mechanism to implement this kind of web applications. The beauty of it and the reason why I implemented this for the AjaxEngine open source project is that using events and namespaces is a far more open approach then the mechanism that I introduced some time ago and has a neat extensibility model.

Typical data-centric web pages

Using OpenAjax events for building data-centric and forms based AJAX applications

From a high level viewpoint onto pages that implement data-centric applications you see that the elements on the page can be categorized into the following cases:

  • Fields and other elements where values are shown and edited by the users (Input fields, checkboxes, ...)
  • Buttons that help editing these values (calendar popup, drop-down lists, ...)
  • Foreign key Lookup mechanisms (checking against a list of countries, ...)
  • Buttons that offer a way of navigation through huge data sources (|< first, next >>, ...)
  • Buttons that commit a current state to the backend system ([Update])
  • Buttons that trigger special transactions or back-end calculations

Forms in this kind of scenario are just a collection of html elements that together can be used to display or edit a single record of a given schema.

Where to use OpenAjax events

Events can help in these situations where a direct connection between components is not desired or otherwise problematic:

1. events on the field-level

On the field-level (inside the form) data is passed around when the value of a field or another data control is changed. This happens either by a user interaction with a field or another data control or as part of a situation on the record level for example when a new record is displayed.

If a field exists it can subscribe to the appropriate event and can display the value passed around. On the other side it can also publish a new event if the user changes the value.

It doesn’t matter if a real field is used or a slider, a calendar popup or a 3d spin control. Even multiple controls that subscribe to the same event can coexist side by side without knowing from each other.

Conclusion 1: Using OpenAjax events gives us the advantage of having a simple plugin mechanism that is extendable.

2. events from the menubar

Clicking a button already publishes the HTML built-in onclick event. However this event is only passed to those elements that are clicked directly or are part of the control hierarchy of the html object model. The menubar catches these events and transfers them into OpenAjax events that are passed to all elements that are interested because they have subscribed them. These events in contrary to the html DOM events are carrying a semantic by using the full eventname and eventually by carrying some data with them.

Conclusion 2: Using OpenAjax events can add semantic statements to events.

Conclusion 3: OpenAjax events are independent from the html DOM layout and therefore can help separating the UI model from the event model.

These 2 scenarios fit well into the OpenAjax event standard.

Antipatterns to OpenAjax events

1. events between tight coupled components

The datasource controller and the form element are 2 components that share some information flow. However every situation in this scenario is started by the datasource controller. The case where a user wants to “update” the datasource controller has to request the current form data from the form. Using is not practical because the form element that would receive the event will not be able to “attach” the current form data. A direct connection is more adequate approach by sharing a common interface like the 3 methods.

Conclusion 4: Using OpenAjax events to retrieve information is not a practical solution. Tight coupled components are still an option.

Note: Maybe some other control is interested in the fact that new data is available in the form which is done through a write() call. This can be the reason for publishing an event by the datasource controller that expresses that.

2. events between passed between client and server

The datasource controller also has to exchange data with the server. This is a direct end to end communication that happens every time a record is fetched from the server or a record should be updated. OpenAjax events can’t cross this boundary (yet) and again there is return data that is not available immediately when using asynchronous calls (I hope you do for reasons of robustness).

Conclusion 5: Remote Procedure Calls situations should be implemented by using a high level AJAX protocol.

Using attributes on controls to define the event names

One design convention that is used within the DataControls is that the eventnames that are used by controls can be split into 2 parts: the namespace and the local name.

The event “de.mathertel.datasource.search” that is used by the search button in the menubar has the namespace “de.mathertel.datasource” and the local name “search”. The eventname can be specified on the button itself ion 2 ways.

  1. When the eventname attribute contains a dot character it is assumed that the value already contains a full qualified event name.
  2. When the eventname attribute contains no dot character the parent elements are scanned for a “eventnamespace” attribute ant the effective event name is built by combining them.

Here is the sample of the html code:

<div id="datamenubar" class="VEMenuBar" eventnamespace="de.mathertel.datasource">
  <span hover="true" class="VEMenu" tabindex="1" eventname="search">Search</span>
  ...
</div>

This convention helps writing short html attributes and allows an easy changing of the namespace that is used for a collection of controls.

Currently the menubar control and the ajax form control both use this mechanism for building the full qualified even names from the eventname / eventnamespace attributes.

That’s the blue print of the current changes that took place in the AjaxEngine project. The even simplified the way Ajax Forms can be implemented and helps minimizing the code that we usually need to connect all the elements in a typical data-centric web application.

Have a look at the sample: http://www.mathertel.de/AJAXEngine/S06_AJAXForms/SimpleReader.aspx. If you scroll down the page you can also see a region with a protocol of the raised events.

Dienstag, November 20, 2007

AjaxEngine is now full based on the OpenAjax specification

During the last weeks a lot of work was done to remove the old DataConnection implementations in the Ajax Engine open source project. Now it's done. You can find a first version of it in the repository on  Sourceforge: http://sourceforge.net/svn/?group_id=200182

and the sample web site http://www.mathertel.de/AJAXEngine was also published with this version today.

The current version will be tagged 1.5.nnnn.beta1 and a donwloadable zip file will also be available soon.

 

The OpenAjax hub specifications seems to be almost finished so not much work will be left until a final full compatible version.

Freitag, November 09, 2007

A alternative to JSON is available: web services

The discussions about the security concerns of JSON coming up again. Are you looking for alternatives ?

I am not used to advertise for my web site but there is an alternative cross browser solution available since 2005. It's robust code and it's running inside many web applications on Java and ASP.NET.

  • standard web services on the server.
  • SOAP (XML) used on the network.
  • JavaScript proxies on the client to allow RPC style calling of the server.
  • AJAXEngine layer that solves the typical timing problems.
  • No eval() !!! - no evil from eval !!!

One approach for multiple platforms.

By using the standard protocol on the server side you don't need to incorporate any special new interfaces for you AJAX solutions and take the full advantage to the stable and secured server ports.

On the client all the coding is plain JavaScript. That's why the communication part of this project works on Java as well as on ASP.NET ad PHP should not be a problem too.

Have a look at http://www.mathertel.de/AjaxEngine/

It's Open Source using a BSD style license and available on http://sourceforge.net/projects/ajaxengine/

Samstag, Oktober 13, 2007

Calling web services with structured parameters from JavaScript

In many situations it is better to use structured parameters when calling SOAP based web services then using a long list of simple parameters. The proxy layer of the AjaxEngine now also supports these parameters by converting JavaScript Objects to the XML notation used in the transferred SOAP message.

Parameters

Using methods with structured parameters using JavaScript Objects is directly supported, just pass them with the right properties.
Here is a partial sample for a web service definition in C#:

// Define a point in the 3D space. public class Point3D {
  public double x, y, z;
} // Point3D

[WebMethod(Description = "Calculate the distance of 2 points in the 3D space.")]
// Test function passing structured objects.
public double CalcDistance3D(Point3D p1, Point3D p2) {
  Point3D v = new Point3D();
  v.x = p2.x - p1.x;
  v.y = p2.y - p1.y;
  v.z = p2.z - p1.z;
  double dist = Math.Sqrt((v.x * v.x) + (v.y * v.y) + (v.z * v.z));
  return (dist);
} // CalcDistance3D 

Calling this method from JavaScript by using the generated proxy method is easy by using JavaScript Objects:

var p1 = {x:3, y:2, z:-4};
var p2 = {x:1, y:1, z:1};
var dist = proxies._types.CalcDistance3D(p1, p2);

If you like to use XmlDocuments ???

Structured return values

Methods of web services may also return structured values. Here is a sample of a method for calculating a vector in the 3D space:

[WebMethod(Description = "Calculate the vector between 2 points in the 3D space.")]
// Test function returning a complex object.
public Point3D CalcVector3D(Point3D p1, Point3D p2) {
  Point3D v = new Point3D();
  v.x = p2.x - p1.x;
  v.y = p2.y - p1.y;
  v.z = p2.z - p1.z;
  return (v);
} // CalcVector3D

Structured values that are returned by methods are available as XmlDocuments when you call a method like this. If you prefer to have the value as an JavaScript Object there is a function available in the proxies namespace that you can use:

var p1 = {x:3, y:2, z:-4};
var p2 = {x:1, y:1, z:1};

var xmlVector = proxies._types.CalcVector3D(p1, p2);
var v = proxies.xml2json(xmlVector);
alert(v.x + "/" + v.y + "/" + v.z);

Limitations

Objects used as parameters cannot be too complex. JavaScript Objects that have native values
(not Arrays nor Objects) are supported.
The data must be available in the format that can be de-serialized on the server
so take care of decimal points and date values.

Up to now the only way to use complex parameters with SOAP methods
was to use a server side XmlDocument Object and to extract the given values by using the appropriate methods.

Download

This addition was done in the current version under development. Because ajax.js is almost independent from the other current changes you can download it to existing projects from the sourceforge repository at http://ajaxengine.svn.sourceforge.net/viewvc/ajaxengine/trunk/ajaxcore/ or from the website http://www.mathertel.de/AJAXEngine/ajaxcore/ajax.js.

Montag, September 03, 2007

The plan for Q3/2007

I've got some mails that have asked about the future of the AjaxEngine framework and here are some statements on that topic:

I will support and extend the framework in the future so companies and other open source projects that reuse it will have the support I can give. Some of the current topics that I'll hope to finish this month are:

  • OpenAjax compatibility for all controls including a InterOp fest compatibility test case.
  • Extending the functionality and the documentation of the Ajax form and the data controls.
  • Writing some more input helpers.
  • Writing about all of it...

I will make a beta version then and have some weeks to get the new functionality stable before publishing a new version.

You can always see the current implementation state in the svn based OpenSource repository at Sourceforge: http://sourceforge.net/svn/?group_id=200182

as well as the demo site that will also be based on the current version under development.

If anyone wants to add some core directly to the project instead of sending me mails let me know. 

Dienstag, August 14, 2007

Extending the OpenAjax hub

Extending events over the network by using an OpenAjax hub compatible approach.

The current version of the OpenAjax hub implementation (Hub 1.0) is focusing on a client-side solution for integrating components into a web application. But it doesn't address any needs that might come with the scenarios where events have to cross the boundaries of the current client side window.

However the hub specification does not explicit exclude these scenarios and is extendible without changing the API itself by introducing a OpenAjax compatible extender component.

Another approach is currently discussed in the OpenAjax member wiki at http://www.openajax.org/member/wiki/OpenAjax_Hub_1.1_Roadmap that is designed by extending the API of the hub itself.

Building an OpenAjax hub extender

The idea behind building an extender is to capture the events in one window and pass it over to other windows.

When the windows exists in the same frameset and share a common top window the message just needs to cross the boundaries. If the window is on another computer the client has to capture the event, and pass it to a server where other clients can then attach and retrieve the events.

1. capturing events

For the local hub implementation the part of the hub extender that captures the local events is just another subscriber. It can register to any local events or can just listen to some of the events that come around. The attribute "capture" is used to specify what events are sent to the server by specifying a semicolon separated list of namespaces using the same syntax as the subscribe method.

The other attribute that we need is the name of the service where the events can be send to using the server site publish method.

// registering for the local event.
OpenAjax.hub.subscribe(this.capture, "_catchLocalEvents", this);

// this function is called whenever a local event was published
_catchLocalEvents: function(eventName, eventData) {
  if (! this._replay) {
    // it's a real local event so publish it.
    var a = [eventName, eventData];
    a.multi = true;
    this.lastLocalAction = eventName + ":" + eventData;
    ajax.Start(this.sendAction, a);
  } // if
}, // _catchLocalEvents

The _replay flag is taking care about the fact that the events that are coming from the server should not be repeated back to the server.

The sendAction is the description how the server should be called. The call should be started at once and multiple calls for publishing an event to the server can be queued. There is no return value in this case. 

// The Ajax action to send an event to the server
sendAction: {
  delay:0,
  queueMultiple:true,
  prepare: function (a) { return(a); },
  call: "proxies.OpenAjaxChat.Publish",
  finish: null,
  onException: proxies.alertException
}, // sendAction

2. listening to events

Listening to events that come from the server is somewhat more complicated because the normal http interaction schema for web applications is client side initiated. The server just has no chance to send messages to "all" or "specific" clients but has to wait until a client asks for an update.

So the client loops by using another Ajax action that is specified with a small delay and calls the server to retrieve new events. The server will return all newer events that have been recorded since the last call of this client that is determined by using a marking counter that can be passed from the client.

// this function is called after retrieving all the events from the server.
_republish: function(events) {
  this._replay = true;
  var aList = events.split('\n');
  for (var n = 0; n < aList.length - 1; n++) {
    if (aList[n] != this.lastLocalAction) {
      var a = aList[n].split(':');
      OpenAjax.hub.publish(a[0], a[1]);
    }
  } // for
  this._replay = false;

  // remember the current marker
  this.marker = aList[aList.length-1];

  // start another pollAction
  ajax.Start(this.pollAction, this);
},

The action is calling the serer by passing the current marker of the client and the asynchronous result will be passed to the _republish method.

// The Ajax action that polls the events from the server
pollAction: {
  delay:200, // wait 200 msec before calling the server (just to be smart).
  prepare: function (obj) { return(obj.marker); },
  call: "proxies.OpenAjaxChat.PullEvents",
  finish: function (ret, obj) { obj._republish(ret); },
  onException: proxies.alertException
} // pollAction

The action and the _republish method will be called repetitive to poll the server.

One thing is left to do in the implementation of this action is the fact that local events already have been published on the client and should not be republished when the server returns them again. To stop publishing an event twice the hub extender records the last event that has been captured locally and sorts this event out.

The Server API

Calling the server for publishing and retrieving the latest events is implemented by using a real SOAP based webservice with the 2 methods Publish and PullEvents.

The communication layer is not as complex as the one defined with Bayeux from the Dojo Foundation but it helps in most scenarios. It is restricted in some way because complex objects cannot be used by the eventData.

The return value of pullevents method is complex object that contains an array of eventname and eventdata and the value of the current marker that is transported using a string too by using the following format:

[namespace.eventname:data\n]*

marker

A sample application

A small sample is showing how all together can be used. It is a kind of chat application where anyone can participate in the same conversation by just opening the url: http://www.mathertel.de/AjaxEngine/S06_AJAXForms/OpenAjaxChat.aspx

You can change your current alias in the configuration section of the page. The large textarea is used to display all the events as the arise and the small textfield beneath can be used by you to type some text. Feel free top open another window and see that your written text also appears on the other side and maybe you can see others typing too. (I suggest talking about animals).
The data itself is a combination of the user's name and the typed text.

The first component is the one that is used for entering a new message and it publishes the event de.mathertel.chatsample.message whenever a line is finished by using the return key. The implementation is quite simple:

<fieldset style="width: 424px"><legend>new message:</legend>
  <input id="newmessage" style="width: 390px;" />
</fieldset>

// the functionality of the new message field.
var newmessageBehavior = {
  onkeypress: function(evt) {
    evt = evt || window.event;
    // send the message when pressing <enter>
    if (evt.keyCode == 13) {
      OpenAjax.hub.publish("de.mathertel.chatsample.message", document.getElementById("username").value
        + " - " + this.value);
      this.value = "";
    }
  } // onkeypress
} // newmessageBehavior
OpenAjax.hub.registerLibrary("newmessageBehavior", "http://www.mathertel.de/OpenAjax/newmessageBehavior");
jcl.LoadBehaviour("newmessage", newmessageBehavior);

The next component implemented is the larger textarea where the all the events will be logged:

<fieldset style="width: 424px"><legend>Chat log:</legend>
  <textarea rows="10" cols="50" id="chatlog" disabled="disabled">
  <textarea />
</fieldset>


// the functionality of the chat log area.
var chatlogBehavior = {
  // registering for the event.
  init: function () {
    OpenAjax.hub.subscribe("de.mathertel.chatsample.**", "_log", this);
  }, // init

  // append another line to the log text and cut the first one if there are too many.
  _log: function(eventName, eventData) {
    var txt = this.value.split('\n');
    if (txt.length > 9)
      txt = txt.slice(-9);
    txt.push(eventData);
    this.value = txt.join('\n');  
  } // _log
} // chatlogBehavior
OpenAjax.hub.registerLibrary("chatlogBehavior", "http://www.mathertel.de/OpenAjax/chatlogBehavior");
jcl.LoadBehaviour("chatlog", chatlogBehavior);

Implementing these 2 components a "local" chat applications ready to run.

The third component is the hub extender that is invisible and is introduced above. The complete source code of the page can be seen here:

http://www.mathertel.de/AJAXEngine/ViewSrc.aspx?file=S06_AJAXForms/OpenAjaxChat.aspx

and you can see the sample live at:

http://www.mathertel.de/AJAXEngine/S06_AJAXForms/OpenAjaxChat.aspx

 

If you are interested in the web service implementation the source is available here:

http://www.mathertel.de/AJAXEngine/ViewSrc.aspx?file=S06_AJAXForms/OpenAjaxChat.asmx

Discussion

The sample above shows how easy it is to extend a hub into other browser windows by not extending the API but by adding a component that does the job.
The huge advantage with this approach is that the additional functionality is strictly separated from the core implementation is and encapsulated into it's own JavaScript file. Therefore it is an optional component and will be not part of the download if not needed in a specific application.

Sonntag, August 05, 2007

Using the OpenAjax hub

What's the problem ?

On the client side it is a common scenario that multiple independent developed controls have to be linked together.

Let's think about a web application that consists of several pages that all should share some common functionality, let's say a button that pops up a calendar to pick up a date.
Its a good idea to separate this kind of functionality into a separate JavaScript include file and a web control or tag library to make it reusable.

Well it's not always the same implementation we need because sometimes the field, that holds the that is named "shipping day", "birthday", "reply until" or any other and sometime there is more than one field on the same page.
Coding the name of the field into the common files seems not to be a good idea.
And it can be worse if there is not only a calendar button and a single field that needs to be connected but there might be also other fields foe example showing the duration between the 2 dates or even some validation functionality. All these "components" need to be linked together.

How links components ?

Hard-coding the IDs of the html elements into the JavaScript code is a bad idea that you can see often in JavaScript . A better idea (for the first sight) is to use attributes on the html elements that contain the IDs of the other elements. For example you can add a "targetControlID" to the calendar popUp and set it to the id of the field.
Sounds good, but it's still limited to be used for the scenario where more than one component needs to be attached to another.

Another idea is to link these components together by using a global available eventing mechanism where it is possible to publish events with values and to register for events on the other side.

Firing events means that one component that has detected a new situation or data constellation can make this available to all other listening components but without knowing if there are any. This results in scripts that are really independent of each other and can be reused in other pages where other constellations are present. Every component that is part of a specific use case can plug itself into the scenario.

That's the idea of the OpenAjax hub specification.

Using the OpenAjax hub to loosely couple components

The 2 main methods the hub specification offers are publish and subscribe -- simple but powerful. (The third defined method is unsubscribe).
Publishing is just as easy than calling a method of another component and the result is that all components (if there are any) that are interested in the event will be called.
To separate different events from each other and to specify the meaning of an event, each event needs a unique identifier that is build by using a namespace and local name.

OpenAjax.hub.publish("de.mathertel.openajax.tasksample.startdate", "2007.08.05");
OpenAjax.hub.publish("de.mathertel.openajax.tasksample.enddate", "2007.08.12");

These samples will tell all subscribers that the values have been changed. The new values are sent together with the event notifications.

OpenAjax.hub.subscribe("de.mathertel.openajax.tasksample.*", "calc", document.getElementById("duration"));

Using the subscribe method this way will cause that the calc method of the duration field will be called each time a event of the namespace de.mathertel.openajax.tasksample is published.

This sample only shows some main aspects about the OpenAjax hub only. You can find the complete specification on the OpenAjax web site (see links below).

Implementing a sample page

To show how to work with the OpenAjax hub implementation a sample page with a hypothetic task definition is used. The only aspects we have a look at are the start and end dates of this task and some more components around.
To keep the sample as simple as possible only one date notation is allowed: "yyyy.mm.dd". Keep that in mind, if you play around with the sample.

First of course we need a OpenAjax hub implementation. You can get the one from the reference implementation (see links below) or use the smaller one that comes with the JavaScript Common behavior library of the AjaxEngine Open source project. This one is also used in the samples implementation you can try out at 
http://www.mathertel.de/AJAXEngine/S06_AJAXForms/TaskSample1.aspx

Here is the include statement:

<script src="../controls/jcl.js" type="text/javascript"></script>

The sample also contains 2 fields (startdate and enddate).
Another readonly field (duration) is used to display the duration of the hypothetic task.
A third and invisible component is also included in the page and this component will take care of the fact that the start date cannot be in the past.

Implementing the input fields

The fields we use here are just regular input fields that are extended by some JavaScript:

var fieldBehavior = { // after loading the page the other components should know about the current value.   afterinit: function () {     OpenAjax.hub.publish("de.mathertel.openajax.tasksample." + this.id, this.value);   }, // init

// when leaving the field the new, changed value must be published. onchange: function (evt) { OpenAjax.hub.publish("de.mathertel.openajax.tasksample." + this.id, this.value); }, // onchange

 

} // fieldBehavior jcl.LoadBehaviour("startdate", fieldBehavior); jcl.LoadBehaviour("enddate", fieldBehavior);

After the page and all components have been loaded the current value of each field is published around so all other components know about it. When the value is changed through editing the event is published again.
I hope it is understandable what how the script works.
The way the script is bound the the 2 fields is part of the JavaScript Behavior mechanism that is not part of the OpenAjax specification. You can find how it works in some older posts on this block.

Implementing the duration field

Again a regular input field is used to display the duration of the hypothetic task. The script for this field is a little bit different and also uses the OpenAjax hub mechanism.

var durationBehavior = {
  _startDate: null,
  _endDate: null,
    
  init: function() {
    OpenAjax.hub.subscribe("de.mathertel.openajax.tasksample.*", "calc", this);
  }, // init
    
  calc: function (propName, propData, regData) {
    if (propName == "de.mathertel.openajax.tasksample.startdate")
      this._startDate = propData;
    if (propName == "de.mathertel.openajax.tasksample.enddate")
      this._endDate = propData;

    if ((this._startDate != null) && (this._endDate != null)) {
      var da = this._startDate.split('.');
      var sd = new Date(da[0], da[1], da[2]);
      da = this._endDate.split('.');
      var ed = new Date(da[0], da[1], da[2]);
      this.value = (ed - sd) / (60*60*24*1000);
    }
  } // calc
} // durationBehavior
jcl.LoadBehaviour("duration", durationBehavior);

The init method subscribes to all events that are published in the namespace I use in this sample. In this case the specific name of an event must be analyzed within the subscription method and because of that is passed as a parameter too.  

Implementing the validation

The validation code is just registering the for startdate event and is checking the date value. If it's not a date an alert box is shown - that's all.

// a validator function to the startdate
function validate(propName, propData, regData) {
  var da;
  if (propData != null) {
    da = propData.split('.');
    if (da.length != 3) {
      alert(propData + " is not a date value formatted yyyy.mm.dd");
    } else {
      var d = new Date(da[0], da[1], da[2]);
      if (d.valueOf() < (new Date()).valueOf())
        alert(propData + " is not a date in the past.");
    } // if
  } // if
}; // validate
OpenAjax.hub.subscribe("de.mathertel.openajax.tasksample.startdate", validate);

 

Extending the OpenAjax hub

As you've seen the mechanism of the OpenAjax hub is really powerful and helps connecting components on a page without hard-coding the ids into the JavaScript code.
But there are still some minor topics undone.

1. initial events

After loading the page every component might have to publish the initial value to all the other components to make them know about the value. This cannot be done in an onload script because then it will depend on the initialization order of the components what components will receive the event.

The current OpenAjax hub specifications seems to have the understanding that events are used after the page has been loaded. I think the mechanism is also good to be used in the phase of the page loading but there is no suitable specification for this right now. The init and afterinit methods in the JavaScript Behavior implementation can help on this.

2. saving latest values

When events are published a component that needs to know about the values of several other events and has to combine them always has to collect this information on its own as you can see in the implementation of the duration field.

I think that this is a common scenario and can be supported in a general way too.

3. nesting events

The third issue I see is that the code that is started by a published event should not start another event.
Think about the validation functionality above. If a start date in the past is detected it would be easy to publish the current date as a substitute. The problem then is that other components will get the event once with the older value and once with the newer value. The order of these events is not deterministic and it might occur that the older value will be published to a component after the newer value.

Links:

http://sourceforge.net/projects/ajaxengine
  The open source AjaxEngine project, including a public subversion repository.

http://www.mathertel.de/AJAXEngine/

  The AjaxEngine project live with samples and documentation.

http://www.mathertel.de/AJAXEngine/controls/jcl.js
  The JavaScript Common behaviors library containing a second source OpenAjax implementation.

http://www.openajax.org
  Here you can find all the white papers and the specifications.

http://sourceforge.net/projects/openajaxallianc
  Here you can find the reference implementation of the hub.

Donnerstag, Juli 26, 2007

Tree view Ajax control update

The tree view control was introduced some time ago and some details of its implementation can be found at http://ajaxaspects.blogspot.com/2006/01/tree-view-ajax-control.html or in the book at http://www.mathertel.de/AJAXEngine/documentation/AJAXeBook.aspx.

Now there is an update available and also a step by step sample how to use this control inside your web application.

The sample page can be found at: http://www.mathertel.de/AJAXEngine/S03_AJAXControls/TreeView.aspx.

1. Building a web service

Using Ajax with a tree view control is based on the idea that the full data that builds a complete tree might have a size that cannot be downloaded to the browser in one time. The server therefore has to offer a method that enables downloading fragments of a hierarchic data structure exactly in that moment when the user opens a new sub tree.

The tree view Ajax control binds to a webservice with only one function GetSubNodes(string path) that has to be built for your specific solution. If you like you can also use a different name for the method.

The structure of the XML node that must be returned by this method looks like this:

<tree> <folder name="AK" title="Alaska">
<file title="Aguila" name="ZIP85320" link="http://weather.aol.com/main.adp?location=USAZ0001"/> <file title="Ajo" name="ZIP85920" />
<file name="Redmond" img="redfile" />

<file name="Alpine" /> <file name="Yuma" /> </tree>

The outer element must be a <tree> node that contains <folder> and <file> nodes.

As you can see the name attributes do have a special purpose in this structure because the values of these nodes together and separated by slashes will build a path to each available element for example "/AZ/Ash Fork".

When clicking onto folders and files this path will be used for loading a subtree or for the events that are published when a final <file> node is clicked.

The title attribute is optional. Its text will be displayed behind the icon. If it's not present the name will be used instead.

The link attribute can be used when a click on a final node should just open a regular hyperlink.

When there is no link present on a file node an OpenAjax event "de.mathertel.treeview.click" with the path of the node in the data is published. You can register to this event for catch all clicks if no navigation is required.

You can find a webservice implementation here and here.

Having built such a web service most of the work is done.

2. importing the webservice

The webservice must be made available on the page containing the Ajax tree view control by using a simple JavaScript include:

<script type="text/javascript"
src="../ajaxcore/GetJavaScriptProxy.aspx?service=../S03_AJAXControls/TreeView.asmx"></script>

Now the webservice is available through the proxies.TreeView object and the GetSubNodes method can be called by using the generated proxies.TreeView.GetSubNodes() function.

3. embedding the Ajax tree view control

The control is implemented as a user control in the file ~/controls/TreeView.ascx. If you use Visual Studio 2005 you can drag this file onto a page and the control will be registered for this page or you can register the control by using a @Register tag at the beginning of the page:

<%@ Register Src="../controls/TreeView.ascx" TagName="TreeView" TagPrefix="ajax" %>

The other way to register a user control is putting an option into the web.config file. This is the better solution if you want to reuse the control on multiple pages and like to use the same prefix all over the web application.

<configuration>
  <system.web>
    <pages>
      <controls> 
<add src="~/controls/TreeView.ascx" tagName="TreeView" tagPrefix="ajax"/>

The control itself can be used now: 

<ajax:TreeView ID="TreeView1" runat="server" 
  service="proxies.TreeView.GetSubNodes" title="Cities in the USA" />

You can see the complete source of the page by using this link: [view source of TreeView.aspx].

4. CSS and specific icons

Some tree view might not only use folders and files so there is a special feature for that too.

The CSS code that is used by the tree view control is shown here:

div.TreeView .du {height:18px;overflow:hidden;cursor:hand; 
  background-image:url(controls/images/dc.png);background-repeat:no-repeat} div.TreeView .do {height:18px;overflow:hidden;cursor:hand;
  background-image:url(controls/images/do.png);background-repeat:no-repeat} div.TreeView .dc {height:18px;overflow:hidden;cursor:hand;
  background-image:url(controls/images/dc.png);background-repeat:no-repeat} div.TreeView .de {height:18px;overflow:hidden;
background-image:url(controls/images/de.png);background-repeat:no-repeat} div.TreeView .fl {height:18px;overflow:hidden;
background-image:url(controls/images/file.png);background-repeat:no-repeat} div.TreeView .ft {padding-left:40px} div.TreeView .subframe {margin-left:18px;}

Using these short classnames for attaching the style results in small html code fragments and you can link to the right images just by modifying the style rules. I put this baseline definition into the main css include file of the web application.

By specifying the img attribute on a file node in the data that is returned from the server another classname can be included for the ft-class elements. To avoid individual image tags in the tree view this classname extension also is handled by using a style rule that you can add:

div.TreeView .fl.redfile {background-image:url(../controls/images/redfile.png)}

This definition can be found in the sample page itself but you can also put it into the mail css include file if you like. Search for Redmond(WA) to see it work.

5. handling the events

If you just like to show information in a tree fashion and like to use hyperlinks on the file nodes you don't need to have a look at the eventing system that is also built in.

When clicking a file node and if there is no hyperlink set then the tree view controls publishes an event that event handlers can catch. The eventing system that is used here is the OpenAjax compatible event hub. You can find the documentation about it on the http://www.OpenAjax.org site and the implementation is part of the ~/controls/jcl.js file that is included automatically.

To register for such an event you need a little bit of JavaScript code:

// a function that will catch the tree events by listening to de.mathertel.treeview.**.
function showTreeEvent(name, data) {
  alert("click on " + data);
} // showTreeEvent

OpenAjax.hub.subscribe("de.mathertel.treeview.**", showTreeEvent);

The OpenAjax.hub.subscribe is registering the showTreeEvent function and this function will be passed the name of the event and the path in the data payload.

About the updated features

New to the current implementation is the support for the link attribute in the <file> elements and the publishing of events when clicking final nodes.

If you want to see more features or want to have more supported scenarios then let me know by using the feature request function on http://sourceforge.net/projects/ajaxengine/.

Samstag, Juli 07, 2007

AjaxEngine is now on sourceforge.net

You can now find a repository with the current version of the AjaxEngine, including the samples on

sourceforge at  http://sourceforge.net/projects/ajaxengine/.

There are some real great advantages by using a public community site:

discussions and bug tracking

I plan to use the bug tracking and forum tools and hope you'll find this helpful too.

repository

I was using subversion all over the last years on my local site so it was easy to switch to a public server.

You can now find the latest stable version (1.2) and the current work in progress also there:

tsvn:https://ajaxengine.svn.sourceforge.net/svnroot/ajaxengine

collaboration

Another big advantage of an open community platform is that it makes working together really easy.

New Developers for the project are welcome !

Of course the existing web site http://www.mathertel.de/AJAXEngine will remain active so you still can see all the samples live there.

Freitag, Juni 29, 2007

The fade effect and the DataFade control

Here is a nice visual effect for data fields:

When a page contains multiple values that might change from time to time it is a good idea to bring the users attention to the updated value. The DataFade implements this by changing the background color of a field and fading it from yellow to the original background color that defined by the regular style.

The fading effect takes about a second and this is enough time for a human reader to focus the new field and reading the new value. The effect even seems to work if there are more values that are changed at the same time and it seems that the eyes can remember for some short time what fields have changed.

Here is a simple implementation using a horizontal scrollbar and a simple field.

http://www.mathertel.de/AJAXEngine/S04_VisualEffects/FadeDemo.aspx

When the DataFade control is initialized the actual background color is detected and stored in the local orgcolor field.

If the DataFade control detects that the value has changed it sets the background color to yellow and by starting a timer the background color is changed by smoothly adopting the red, green and blue to the original color that was found when the control was initialized.

The DataFade control is implemented using a JavaScript Behavior so it can be used inside AjaxForms for displaying, but not entering values. This is because it is inheriting the DataOutput Behaviour it implements a setData(newValue) method that is detected by the ajaxForms implementation and is used for setting the new value.

Dienstag, Juni 19, 2007

Aspects of OpenAjax

You know I like standards.

Even if it is some kind of more complex to implement a solution based on a standard than using a direct and efficient but proprietary way, there are benefits on the long way that I just don't want to miss: the ideas and thoughts of others materialized in APIs, specifications and best practices.

That's why I use the SOAP standard webservice protocol for my Ajax implementations.

OpenAjax

Now OpenAjax Alliance is another try of a group of about 75 companies and organizations to define standards in the Ajax hemisphere. There are a lot of ideas and some good ideas too in the current discussions. We all know that it is hard to define a standard specification that gets agreed by the majority of the members. And it can take a long time until a standard proposal is adopted.

Right now a version 1.0 of the specifications are on their way and they contain some good stuff that I like to bring into the Aspects of Ajax framework and support an probably upcoming standard this way.

http://www.openajax.org/member/wiki/OpenAjax_Hub_Specification 

Libraries and Namespaces

There is only one world we live in and there is only one global namespace in JavaScript. The problem is that multiple frameworks when used simultaneously in one page MUST use different global variable names, different namespaces when implementing XHTML and different prefixes and aliases for the namespaces. Especially the global names might cause a lot of problems.

Did you try to use 2 libraries that both register the $() function but implement it differently?

The OpenAjax registerLibrary and unregisterLibrary methods that can be used to help mastering this problem space.

The ajax, the proxies and the jcl prefix will be used by the Aspects of Ajax framework because these are the names of the global variables I use (beside minor important stuff). I hope and pray that nobody else will use this prefix in any other AJAX framework. (I am the first - I won! :-)

No, and seriously: I don't like the global ajax variable being registered by any framework and right now I am not happy about this early (2005) decision any more.

The namespace used by the Aspects of Ajax frameworks will be de.mathertel because http://www.mathertel.de/AJAXEngine/ is the URL where the documentation and the samples can be found on the web.

... but maybe it's time to register a product name related web address :-)

When implementing a standalone AJAX framework you do not have to care about these problems. Being compatible (and friendly to other frameworks) can open a wide space in combining functionality from different sources.

Events - inter controls connections

Connecting multiple controls on a page by using JavaScript can be a nightmare because many little scripts will have to know about the existing other elements on the page. If you want to reuse generalized controls this situation becomes worse and if you like to reuse components of different manufacturers ...

So it's a good thing to define a common functionality that does the job and that controls can use to talk to each other using the well known subscribe and publish pattern and the idea of events.

The Aspects of Ajax framework has a small implementation since almost 2 years (see http://ajaxaspects.blogspot.com/2005/09/connecting-controls.html) called "page properties" or data connections that also allows this kind of connectivity through the DataConnections object but compared with the event system of the OpenAjax hub specification there are some pros and cons.

  1. The OpenAjax hub has defined an idea of namespaces and namespace notation like the namespace ideas known from .NET, Java and other environments. Events that are published are prefixed by a namespace so different providers of the same event name can be distinguished. The page properties of the Aspects of Ajax framework only had one global namespace (the page).
  2. Using the OpenAjax hub specifications it is possible to subscribe to specific events by specifying the long name of the event and by using a wildcards for registering to multiple events. In the Aspects of Ajax framework it was possible to subscribe to all events.
  3. The Aspects of Ajax framework has a mechanism that allows to poll for a current value of a prior published property change / event. The OpenAjax hub has no such methods defined but it is easy to implement an invisible control that logs all changes and offers some methods for getting the latest values.
  4. The Aspects of Ajax framework has some specific controls that helped while developing. One of them is a log of all events and the new values. Beside the changed implementation they also have a new parameter to specify what specific namespace they should watch.

Overall the OpenAjax implementation has some big advantages over the older DataConnections and the additional functionality can be added.

Implementation

The OpenAjax Alliance provides a reference implementation is available in an early version and other implementations of the specification are welcome. After reading the available specs and noticing that it is "just" better then my prior codings I decided to implement the specific details on my own and make them available in a standalone JavaScript file. Some requirements are implemented different than in the reference implementation and maybe you find the time to have a look at the difference if you like.

The size of the implementation

As of this writing the (unfinished) reference implementation is about 2801 bytes. The (current) implementation available on my side at http://www.mathertel.de/OpenAjax is about 1300 bytes. Maybe my implementation is a little bit slower because I rely on regular expressions but I have not done any detailed measures yet. Both sizes are calculated by comparing a shrinked version using the tool from the dojo framework that is available online at http://alex.dojotoolkit.org/shrinksafe/. This is because I don't want to compare the comment lines or different programming styles.

 

The same implementation is also embedded into the jcl.js implementation that also implements the JavaScript Behavior mechanism.

Future planning

I will have a look for the specification of the OpenAjax Alliance hub and I will post a compatible version. It is just good to have a second source.

The Aspects of Ajax framework. including the SOAP client for web services in JavaScript will register itself and will use the hub implementation as a substitution of the older DataConnections implementation that will be removed completely.

Sonntag, Juni 17, 2007

A simple page for displaying a record

Building a page with a form to display and change a record is a common scenario and it should be easy to implement. Some of the basic ideas where already published last week and here is a concrete implementation. The page that can be found at http://www.mathertel.de/AJAXEngine/S06_AJAXForms/SimpleReader.aspx is  built by a combination of the 3 components:

  • The Form contains DataInput fields and other Data Contol elements that are used to display the values.
  • The Menubar is used to offer the typical buttons for searching and navigating through the dataset.
  • The DataSource control controls the binding between these controls and the server side web methods.

The Form element

Many web applications need to display and modify relational data by using a form and a offering a single record at each time. The form itself contains input fields to display the columns of the record and other html elements like labels or other static text around them.

All these elements together are held together by using a html container element that is called the form element. Because we handle all data mechanisms by using AJAX functionality we do not need a real <form> element but use a <div> element instead.

The functionality that is attached to the form (the <div> element) of the page handles getting and setting values by respecting the correct formats for several datatypes and converting them to regular xml data formats.

The great benefit from this approach is, that the server has to support only the standard xml format for the known datatypes and not any country or language specific formats. More on that in another post.

The functionality of the form element is implemented by using the DataForm JavaScript Behavior that is built reusing the functionality that was built in the early days in ajaxForms.js. By using a behavior the code was simplified and reduced.

The Menubar element

This element contains the typical buttons that enable the navigation through a set of records.

These buttons and icons will trigger the corresponding methods of the datasource control by publishing events. 

The DataSource control

This element is not visible to the end user and is containing the main functionality to transfer the data from the server to the form element. It also contains a client side cursor model that help keeping state information away from the server.

The following commands are available:

clear: This command will just clear all the values inside the form.

search: A call to the server is started to retrieve the keys of the found records. The current values of the form before the search is started are used as a template so you can easily find a specific record or a set of records. The retrieved keys are used to form the cursor.

first: The first record in the cursor is retrieved from the server and is displayed inside the form.

next: The next record in the cursor is retrieved from the server and is displayed inside the form.

previous: The previous record in the cursor is retrieved from the server and is displayed inside the form.

last: The last record in the cursor is retrieved from the server and is displayed inside the form.

(future extensions: add, update, delete, ...)

The DataSource element also publishes an event when the data of the form was changed to inform other elements on the page that a new situation is existing.

Searching and the AJAX calls in the background

The "search" button in the menubar must be used first to build the dataset. This is done on the server by searching for all the records that match the criteria given by the current values in the form fields. This is done by using the SearchAction that is passed to the AJAXEngine to call the search method of the webservice. This method is returning a list of unique keys, each one representing a record.

Here is a sample how to search:

You can write "UK" into the country field and press "search" to search all records that have "UK" in the country colum. The database provider also offers the possibility to search using wildcards. If you enter "U%" into the country field you will find all the records with a country starting with "U".

After finding some data the dataset control automatically will fetch the first found record and will display in in the given form fields. This is done by using the DisplayAction that is passed to the AJAXEngine to call the fetch method of the webservice and passing the retrieved record data to the form.

Using the arrow buttons you can step through the dataset. The clear button will clear the form without freeing the dataset but by loosing the current cursor position.

Events between the controls

Connecting elements on the page might be done by using scripts in one element that direct address the other element or by using events.

Events like onclick and onload are already well known in the web development but they are limited to those events that are built into the DOM (Document Object Model). It is not possible to reuse this mechanism for other, self-built events and another mechanism is needed for tasks like this.

The OpenAjax Alliance is targeting this problem with the hub implementation that is still under development for version 1.0.

Inside jcl.js (view source) you can now find a (almost) compatible version of the OpenAjax specification that has only about 1300 bytes of real code. When the specification is finished I will release a compatible version and will follow the idea of a common functionality and compatibility of the Ajax frameworks. More on that in another post... 

Montag, Juni 11, 2007

Building data-centric and forms based AJAX applications

Most of the business web applications on the Internet are HTML forms based applications where data, bound to html elements, is the core functionality. I am talking about registration forms, dialogs and pages to display and modify records of a server side relational database system, ERP or CRM systems. There are not a lot of drag & drop elements or popping visual effects here but most active elements deal with data that comes from databases or other data sources.

Many developers do not build E-Mail applications, portal frameworks, maps or mashups but we need to display, edit and control records from a company's database and implement transactions on these entities.

This part of the framework and the upcoming posts are about the aspects and coding the client side of this kind of web applications and here is my blueprint of the ongoing work that will extend and consolidate the framework in this direction.

The server side is kept minimal for now and you can adopt any data binding layer on the server you like as long as you implement the small ITableDataService interface on the web service that handles the AJAX calls.

Inside the archive file Ajax_new.zip download you can follow the development of this part of the framework in the S06_AJAXForms folder.

Typical data-centric web pages

From a high level viewpoint onto pages that implement data-centric applications you see that the elements on the page can be categorized into the following cases:

  • Fields and other elements where values are shown and edited by the users (Input fields, checkboxes, ...)
  • Buttons that help editing these values (calendar popup, drop-down lists, ...)
  • Foreign key Lookup mechanisms [check against a list of countries]
  • Buttons that offer a way of navigation through huge data sources  (|< first, next >>, ...)
  • Buttons that commit a current state to the backend system ([Update])
  • Buttons that trigger special transactions or back-end calculations
  • Tables that display mass data by paging or scrolling
  • Tree Views that display hierarchical (mass-) data

Some of these features where already shown here on the blog but it's time to rearrange these features a little bit and make them working together. Here are some aspects about the major features.

Forms and binding data

A core functionality of this kind of business application is a data binding functionality that connects elements of the form to the corresponding data source. Because we want to keep the page loaded while navigating through many records coming from the server we need a client-side mechanism for moving data into html elements and back. The core of this mechanism was introduced in an early post using the ajaxForms.js include file. This mechanism will be extended and tuned a little bit.

Supporting national language specific notations

Of course we need some functionality to convert non-text datatypes to a string representation that can be read by the user and this frameworks goes further by converting values to human readable strings with the typical national language specific notations in decimal numbers and date values.

Because this is done on the client we need no conversion on the server and therefor have a server that must not care about the specific formats out there in the world. Supporting these notations is done by using a plugable mechanism that delivers the right conversion routines to the client based on the language settings of the browser.

Input Helpers

These elements are bound to a standard input field. They are built to help entering some specific datatypes by offering an alternative input method . This might be small dialogs like a calendar popup, drop-down buttons that open a list of possible values or sliders that can be used to adjust a value.

Some of these controls do already exist in the controls collection of this framework but again they have to be adjusted and extended a little bit.

Navigating through table data

In many cases the data comes from a data source on the server that stores many records in a table format. On the client we will need some elements that help us navigating through this kind of data. The most common used user interface elements are buttons that allow positioning to the first, previous, next and last record and support searching and modifying the current record.

By implementing a webservice on the server that implements a common interface and a set of controls on the client that use this webservice there will a set of basic functionality available without the need for scripting on the client.

Tree Data

A data bound tree sample has already been published at http://www.mathertel.de/AJAXEngine/S03_AJAXControls/TreeView.aspx

but we will see how to integrate it into the scenario by reusing the same web service interface for the Ajax call.

Common data interface on the server

Serving data from the server and some more functions is provided to the client by using several methods of a webservice. This webservice has to support several simple methods that will bring the databinding to the client through ajax calls. To support an easy development of these web services the ITableDataService interface is defined with the minimal set of methods.

AJAX Controls for AJAX forms

AJAX Form Controls are very similar to the PropXXX controls I had introduced some time ago. AJAX Form Controls are made to bind data from an external data provider and from web services using elements on a html page. The AJAX Form Controls are AJAX Controls that implement the Data Interface functions.

(The PropXXX Controls are using primarily the Page Properties storage mechanism and are used to control the state of the view of the page. This is typically something different than the data, but we will see some changes in this scenario too in some time to make it OpenAJAX compatible).

 

Technorati tags: , , ,

Sonntag, Juni 03, 2007

A simple menubar

By using the hover effect it is possible to realize a simple menubar that will be used by an upcoming control that allows rich text editing. Here I focus on the implementation of the menubar that is implemented as a separate control and can also be used with small changes for other purposes.

Building the html code for the menubar

The html code for building a menubar is implemented by using an outer <div> element with a classname "VEMenuBar". This element is used as the wrapper for all parts of the menubar and is displayed in the background.

The inner elements and menu items can be implemented using <img> images or <span> elements with text content.

The third type of an inner element is a vertical line or separator that can be used to group elements.

Here is a small sample:  

<div class="VEMenuBar">
  <span class="VEMenu" tabindex="1" onclick="datasource.search();">Search</span>
  <img class="VEMenuSeparator" alt="" src="../controls/images/white.gif" />
  <img class="VEMenu" alt="show first record" tabindex="1" src="../controls/images/first.gif" /> 
</div>

The hover effect

When positioning the mouse over any enabled item of the menubar the individual item for starting a specific command is highlighted. For implementing this effect the already known hover behavior is reused. All that we need to implement it is to include the hover.js include file in the head of the page and setting the hover attribute on every element.

<script type="text/javascript" src="../controls/Hover.js"></script>

The menubar behavior (MenubarBehavior)

This behavior implements all the basic functionality for menubars. When bound to a html element it also loops through all the children of the outer element an sets the hover attribute to true for those elements that have a classname "VEMenu". This allows to enable the hover effect without implementing the hover attribute for every menu item.

If you set the tabindex property on menu items another functionality is enabled. By setting tabindex to a value greater then 0 the element can get the focus. When pressing the space bar while the focus is on a specific menuitem the onclick method of the menuitem will be called. This allows you to use the keyboard instead of clicking with the mouse.

The HTML elements that build the menubar 

First of all the outermost element of the menubar that will get attached the behavior is a div element with a classname "VEMenuBar". This element is used as the wrapper for all parts of the menubar and is displayed in the background.

The icons or other images are placed in the menu by using <img> elements as children inside the VEMenuBar element

and will have a classname "VEMenu". They will automatically get an attribute hover="true" to enable the hover effect.

CSS definitions 

Some classnames need to be defined:

.VEMenuBar { background-color:#eeeeee;padding:2px 8px 2px 8px;height:20px;overflow:hidden;}

This defines the background color of the menubar. The padding definition will keep the inner icons away from the border.

.VEMenuBar * { vertical-align:top;}

All elements will be vertically aligned by the top.

.VEMenuBar span {display:-moz-inline-box;display:inline-block;}

<span> elements inside the menubar can be used to create buttons with a text caption. This rule is used to position span elements by using the padding.
The IE will use the inline-block rule and Mozilla/Firefox will use the -moz-inline-box rule. They both don't understand the other syntax and will just ignore it.

.VEMenu { border:0px;padding:2px}

This rule is used for the state of a icon that is not hovered or pushed. In my layout it has no border and is padding the graphic by using 2 pixels on every side.

.VEMenuHover { border-style:solid;border-width:1px;border-color: #acc1e4 #203050 #203050 #acc1e4;padding:1px}
This is the state of a icon when the mouse is over it but is not pushed. In my layout I use 1 pixel of border on every side with some colors that makes the icon look like being raised a little bit. I reduce the padding to 1 px to avoid the shifting and flickering of the graphic.

.VEMenuPushed { border-style:solid;border-width:1px;border-color: #203050 #acc1e4 #acc1e4 #203050;padding:1px}
This is the state of a icon when the icon is pushed down. In my layout I use 1 pixel of border on every side but with different colors and I reduce the padding to 1 px to avoid the shifting and flickering of the graphic.

.VEMenuSeparator { display:inline-block;height:20px;width:1px;border-left:solid 1px #203050;}

Separators between groups of symbols are included by using a 1x1 white pixel image with a classname "VEMenuSeparator" that is displayed with a darker border on the left side.

Attaching functionality

The MenubarBehavior implementation has no special implementation for the onclick event on VEMenu items. The functionality of the menubar item should attached by using the onclick events directly.

 

You can find the state of the current implementation here:

http://www.mathertel.de/AJAXEngine/S04_VisualEffects/InlineEditDemo.aspx

(see the page source by using the view link in the upper right corner)

 

Download the current version under development

I've added another downloadable archive file to the site : Ajax_new.zip.

This Zip-File contains the current version of the ASP.NET 2.0 web project that builds this side.
The complete AJAX Engine and all samples and also unfinished samples and componente are included.
Use this download If you want to experiment with the Engine or if you want to have a look for the newest additions and features.

Montag, Mai 21, 2007

Using webservice calls with multiple parameters

The restriction that the AJAXEngine supported only methods with one parameter had been a topic to some postings in the blog and also to some good comments with good solutions.

Because the problem was only restricted by the AJAX Engine itself and not by the underlying JavaScript proxy layer I looked for a small and neat solution and finally found that the often overlooked Javascript method apply

helps here.

The implemented way of passing more than one parameter is (like suggested) to use an Array as a return value of the prepare function. Because arrays are also supported as a parameter to the called method itself a extra hint is used to distinguish these 2 scenarios.

Here is how to implement the prepare method for this case:

prepare: function (ds) { 
  var p = new Array();
  p[0] = ajaxForms.getData(ds.form);
  p[1] = "name";
  p.multi = true; // the hint for the ajax Engine
  return(p);
},

The changes in the AJAX Engine layer is only a condition check and a call using the apply method:

// start the call
ca.call.func = ajax.Finish;
ca.call.onException = ajax.Exception;
if ((data.constructor == Array) && (data.multi != null)) // 19.05.2007
  ca.call.apply(ca, data);
else
  ca.call(data);

If you want to use this feature, you can download the ajax.js file directly. A complete version will be available some day soon including new samples and features.

Montag, Mai 14, 2007

Accordion menu

I added another visual effect for HTML that is called an accordion menu by using a JavaScript Behavior.

An accordion menu is a collection of multiple, stacked panels.

Only one of them is visible and another can be opened by clicking the header of a closed one using a smooth transition of the heights of the content area of the panels.

Have a look at: http://www.mathertel.de/AJAXEngine/S04_VisualEffects/AccordionDemo.aspx

Mittwoch, Mai 02, 2007

A new version of the book "Aspects of AJAX" is online

Beside writing some more pages it also contains some corrections and the new posts on this blog where added also.

You can get it for free from http://www.mathertel.de/Ajax/AJAXeBook.aspx..

Donnerstag, April 05, 2007

Using Inheritance in JavaScript Behaviors

While working on some samples using (different) menubar, I found it helpful to inherit a JavaScript Behavior from a more general JavaScript Behavior. This would give me the chance to implement the common general Javascript methods only once and leave specific functionality in the derived Behavior.

Here is the sample:

// this is a basic behavior definition for menubars var MenubarBehavior = {   init: function () { // activate the hover effect on all menu items var allitems = this.getElementsByTagName("*"); for (var o in allitems) if (allitems[o].className == "VEMenu") {         allitems[o].hover = true;       }   },

 

onkeypress: function(evt) { evt = evt || window.event; var kc = String.fromCharCode(evt.keyCode); if ((this._attachedBehaviour.onclick != null)

&& (evt != null) && ((kc == " ") || (kc == "\r"))) { this._attachedBehaviour.onclick.call(this, evt); } // if } // onkeypressed } // MenubarBehavior

This is a basic implemenation that enables the hover effect for all VEMenu items found inside the menubar and to simulate a click event if the spacebar or return key is used while the focus is on a menuitem.

// this is a basic behavior definition for menubars var EditMenubarBehavior = {   inheritFrom: MenubarBehavior,

  init: function() {     MenubarBehavior.init.call(this);   },

onclick: function(evt) { evt = evt || window.event; var src = evt.srcElement; var cmd = src.name; if (cmd != null) { cmd = cmd.split(';'); HtmlEditBehaviour.Command(cmd[0], cmd[1]); } } // onclick } // EditMenubarBehavior

This is the implementation of the derived Behavior definition.

If you ask why I do not use the JavaScript inheritance mechanism, then you have a good question - i tried.

Using the new operator and the prototype mechanism does not work here because we attach methods to HTML elements and some other problems came up too.

The article of Nicholas C. Zakas at: http://www.sitepoint.com/article/javascript-objects also describes the topic.

You can find the state of the current implementation here:

http://www.mathertel.de/AJAXEngine/S04_VisualEffects/InlineEditDemo.aspx

(see the page source by using the view link in the upper right corner)

 

The only code I had to add to the LoadBehaviour method (that does something very similar to the extends method of Zakas) are these 3 lines of code to recursively bind the Behaviors starting with the base class.

 

if (behaviour.inheritFrom != null) { this.LoadBehaviour(obj, behaviour.inheritFrom); this.List.pop();

}

See controls/jcl.js (view source)

 

(I'll publish a new version of the framework as a zip here file when this sample is finished).