OpenAjaxHub Ideas 20060719

From MemberWiki

Jump to: navigation, search

Contents

About this document

This document contains proposals about the OpenAjax Hub as discussed around 20060719. This wiki page should not be considered active any longer and is retained as a historical snapshot of early thinking. For more current information, see:

Terminology

  • Library - A collection of JavaScript runtime logic that provides Ajax services.
  • Ajax markup processing - The transformations performed by a library upon source markup to produce appropriate changes to the browser DOM to achieve the desired visual and behavioral results.

20060719-JF: During the 19July Interoperability committee meeting, the above definitions were discussed. People agreed with the use of the term library as defined above. People also felt it was necessary to add a definition for toolkit, which is added below.

  • 20060719-JF: Toolkit - A collection of technologies, products, and other supporting materials such as documentation, that help a customer to produce an Ajax-based solution. In some scenarios, a toolkit might just be a library, but in other cases will consist of some combination of libraries, server components, authoring components, associated utility software, and supporting materials such as documentation.

Overall approach

  • OpenAjax-compliant web applications must include a <script> element that loads "OpenAjax.js" before any other Ajax JavaScript runtime library. For example:
<html ...various attributes...
<head>
<!-- All OpenAjax-compatible web pages would have to use a JavaScript
  library that implemented the feature set we define for our hub.
  The hub would have to be listed in the html:head before any references
  to any OpenAjax-compatible toolkits. -->
<script src="...URL to JavaScript for OpenAjax hub..." />

<!-- Each OpenAjax-compatible library typically would load its bootstrapping
  JavaScript logic within the html:head after the OpenAjax hub were loaded. -->
<script src="...URL to bootstrap JavaScript for foo-library" />
<script src="...URL to bootstrap JavaScript for bar-library" />

</head>
  • If the OpenAjax Hub is present, OpenAjax-compliant libraries must register themselves with the OpenAjax Hub as part of the initialization process that occurs when the <script> element(s) load and evaluate the startup logic for the given library. Details about the toolkit registration process is described in the sections below. Part of the registration process is identification of callback functions. One important callback function is the method to invoke when the OpenAjax hub handles the 'load' event.
  • If the OpenAjax Hub is present, OpenAjax-compliant libraries must not directly add their own event listeners for the document load event and must not directly scan the document for elements upon which to perform their transformations; instead, the OpenAjax Hub will invokes the callbacks that they have registered.

20060719-JF: During the 19July Interoperability committee meeting, this was discussed. The general approach used above had been discussed at multiple prior meetings and there were no new objections raised.

Library registration, loading and unloading

Here are some proposed APIs that libraries invoke to register themselves with the OpenAjax Hub. (Note: subsequent sections below describe other topic-specific registration APIs.)

OpenAjax.register-library(libid, liburl, version)
OpenAjax.register-load-handler(libid, load-callback-function)
  • libid - string holding the unique identifier for this library (e.g., "dojo" or "rico"). The value must conform to the syntax allowed for namespace prefixes in XML.
  • liburl - string holding a namespace URI that serves as a globally unique identifier for the library. The value must conform to the syntax allowed for namespace URIs in XML.
  • version - a decimal value holding the version number for the library. Typically, the integer part of the value is the major version number, the first fractional digit the minor version number, and subsequent digits used for minor update identification.
  • load-callback-function - the library-specific function that is called during document load event processing. Note that an OpenAjax-compatible library must not traverse the document tree itself, but instead must wait for invocation of its registered markup callback functions (see markup discussion below).

To achieve both backwards and forwards compatibility across legacy HTML4 and proper XHTML, OpenAjax-compability web applications must include an xmlns:libid="liburl" definition on the root element of the document, thus equivalencing the library's libid with the namespace prefix for any namespaced-qualified markup entries.

It is recommended that libid and liburl stay constant across different releases of a given library to enable other libraries to promote easy recognition of the presence of other particular Ajax libraries for which they may include special interoperability logic.

20060719-JF: During the 19July Interoperability committee meeting, it was pointed out that APIs cannot use a hyphen. (How embarrassing!) There was a resolution that we would attempt to establish load event listeners via the general event hub mechanism, such as a publish/subscribe engine within the hub, instead of via a special load event API as shown above.

JavaScript collision detection

One of the key problems encountered when attempting to use multiple Ajax libraries on the same page are collisions between the objects that the different libraries create, particularly objects at the global (i.e., Window object) level. In trying to come up with a good technical solution to this issue, the following goals apply:

  • 1: Adequately address the collision issue
  • 2: Minimize impact on existing toolkits to become OpenAjax-compliant

The proposed approach is to rely primarily on a registration scheme where each OpenAjax-compatible library must register the changes that it makes to the JavaScript runtime environment so that the OpenAjax Hub can see if two libraries are colliding with the changes that they are making.

For production-delivery performance reasons, the OpenAjax Hub will have runtime flags that control whether runtime-checking is on or off. If on, then the hub will verify each registered change to the JavaScript environment to see if it collides with any previously registered change. Any collisions will fire an "error" event. If off, then no checks will be performed.

The proposed API is that the "OpenAjax" object supplies the following method:

OpenAjax.register-env-changes(libid, env-changes)

where

  • libid - string holding the unique identifier for this library (e.g., "dojo"). See above for more about library unique identifiers.
  • env-changes - an array of strings that identify, using JavaScript dot notation the objects within the JavaScript environment that are modified by the library. If a prototype object is being changed, then the given string must include ".prototype", as in "Function.prototype.bindAsEventListener".

To illustrate, here is a (very) partial list of what prototype.js might register:

  • ["$", "$F", "$A", "$H", "Try", "Ajax", "Object.extend", "Object.inspect", "Number.prototype.toColorPart", "Number.prototype.succ", "Number.prototype.times", "Function.prototype.bind", "Function.prototype.bindAsEventListener", ...]

20060719-JF: During the 19July Interoperability committee meeting, the general ideas from the text above were generally well-received as addressing an important interoperability problem. One bit of necessary clarification: it is only necessary to register the rootmost objects that are added to the environment and not all of their associated methods and properties. Thus, Dojo only has to register the two or three objects it adds to the window object, as in ["Dojo", ...one or two additional strings...], and not register all of the subordinate objects on the "Dojo" object.

20060719-JF: During the 19July Interoperability committee meeting, this is as far as we got.

Markup registration

(These issues are primarily the domain of the Markup committee)

The OpenAjax Hub is solely responsible for direct traversal the document tree to search for which markup is handed off to which library for Ajax markup processing.

The traversal method used by the hub can be controlled by the application developer. Exact APIs for controlling traversal are TBD, but the traversal options will include:

  • One-time, top-down traversal starting from the <html:body> element. Each element is evaluated to see if a library has registered a markup-search-pattern that matches the given element; if so, the corresponding callback function from the library is invoked.
  • Search for elements by ID. Probably the ordering of elements-by-id happens in the same order that the application registers the IDs to search. For each ID match, the corresponding callback function from the library is invoked.
  • Search by toolkit by invoking a library's callback to invoke its own custom document tranversal logic. (This is an escape valve to allow arbitrary custom traversals by a particular library, but it is still controlled by the hub since the hub controls when this callback gets called versus the other markup handler callbacks.)

Here are some proposed APIs by which a library or developer can register the above options:

OpenAjax.register-elements-by-pattern(libid, markup-search-pattern, markup-callback-function)
OpenAjax.register-elements-by-id(libid, id, markup-callback-function)
OpenAjax.register-elements-by-toolkit(libid, markup-callback-function)

The syntax for markup-search-pattern represents a tradeoff between standards-compliance and efficient implementation with the hub's JavaScript logic. The allowed syntax is a highly restricted subset of XPath:

  • //tagname - All elements with the given tagname (e.g., "//combobox" matches all <combobox> elements)
  • //tagname[@attrname] - All elements with the given tagname that has the given attribute
  • //tagname[@attrname="value"] - All elements with the given tagname with the given attribute having a particular value
  • //* - All elements
  • //*[@attrname] - All elements that have the given attribute
  • //*[@attrname="value"] - All elements with the given attribute having a particular value
  • //id("value") - The element found by getElementById("value")
  • //class("value") - All elements that have the token "value" within their 'class' attribute. (Note: this function represents an XPath extension function that is a necessary addition to XPath because of its widespread use within Ajax applications.)


Event management across toolkits

(This is the most speculative part of the wiki page)

Event management is central to any UI system, and thus it is not surprising that many Ajax libraries include their own event system that sits on top of the browser's event system. Sometimes the libraries have a thin layer, such as prototype.js, which has the low-ambition goal of providing a browser-independent API for attaching event listeners for events supported in browsers (e.g., click, keypress, change). In other cases, libraries might provide a thicker, more powerful, event system. Often, the event system is central to the operation of a particular library, and thus not easily changed.

Taking the above into account, here is a proposed approach for how the OpenAjax Hub would deal with cross-library event issues:

  • 1. Don't attempt to get in between existing libraries and the browser event system. Allow the toolkits to hook up UI event listeners to the browsers directly. (Versus trying to get all of the libraries to change their code to use some sort of OpenAjax event system.)
  • 2. Require that OpenAjax-compatible libraries register a callback with the OpenAjax hub which allows foreign logic to register event listeners on elements that are managed by that library. To illustrate by example, suppose <div id="div-a"> is managed by LibA and <div id="div-b"> is managed by LibB, and that the application developer wants to listen for change events on both. Instead of having to learn each library's APIs, the developer can invoke an OpenAjax API for registering an event listener. The hub would then invoke the given library's callback function. When the event occurs on either div-a or div-b, his handler will be invoked.

The proposed APIs for the OpenAjax event system would follow the W3C DOM3Events model ([1]) as much as possible, thus allowing future direct mapping to native browser implementation of these APIs. The exact proposal is that the OpenAjax object would have a child object called "Events" (i.e., OpenAjax.Events) which would have methods modeled after the W3C DOM Events spec, such as OpenAjax.Events.addEventListener(observer, type, listener, useCapture). (Note that it is necessary to add an observer argument because the DOM events spec puts addEventListener on the EventTarget interface.)

This approach to event marshalling can grow to support custom events within components leveraging DOM3 namespaced events. Let's assume there is a charting component provided by library LibF and a communications component provided by library LibG, and the application developer wants to listen for "new data" events on the communications component so that he can update the view on the charting component. The communications component could define a "foo:NewDataArrived" event. To make this work, the application developer would simply have to invoke OpenAjax.Events.addEventListenerNS(observer, namespaceURI, type, listener, useCapture, evtGroup). (Where evtGroup is almost always null because it is an overkill feature in the DOM3 Events spec, says Jon).

Personal tools