Thursday, January 12, 2012

jMaki UI Framework


UI Framework – jMaki

 Features
  • Ajax in a tag - jMaki wraps Ajax components into easy to use tags.
  • Normalize JavaScript toolkit APIs - jMaki has a single widget mode that wraps other APIs and can provide a standardized way of representing, documenting, and tooling widgets. In other words re-usable widgets can be created from various libraries where we can pick and choose which is best for our needs.
  • Server Integration - jMaki uses the server frameworks to accelerate and enhance the JavaScript experience by providing a way to use PHP, Java, or JavaScript on the server and have the correct data accessible to our jMaki widgets. jMaki doesn't prescribe a specific server data model but can be integrated well with existing environments.
  • Composition Support - jMaki provides a mechanism for page composition to enable the programming model know as the page as the application. All containers widgets such as the tabbed views and accordions provide the built in support for this model using an API called the Injector. This API is also available for reuse in our own widgets.
  • Standardizes Data Model - jMaki provides a common data model. It allows for many structures such as trees, tables, tabbed views, and accordions to be described in JavaScript Object Notation (JSON) format. Widgets from different toolkits can be used with the same data.
  • Unobtrusive JavaScript - jMaki provides publish/subscribe mechanism for inter-widget communication and a glue mechanism which allows us to define application specific behavior outside of the markup.
  • External Service Integration - JavaScript can not directly access content outside of the domain using XMLHttpRequests because of browser security constraints (which is a good things). jMaki provides a generic XMLHttpProxy for tying in external services in a generic way. Examples provided include Yahoo Geocoder Flickr Search, and RSS integration.
  • Layout Templates - CSS may and should be used to provide a layout for a web application. jMaki provides a set of layouts which may be used as templates for your web pages. These layouts may be easily customized and promote proper web design.
  • Designer Friendly - Not all toolkits promote a designer friendly way of web application design. jMaki promotes a clean separation of CSS/JavaScript/HTML.
  • Ajax Tooling Support - jMaki provides meta data for all widgets in a friendly manner where the tool enhances jMaki development. jMaki applications also can be designed outside of a tool.
  • Multi Server Support jMaki currently supports JSF/JSP/PHP/JavaScript. Other environments are planned (a certain gem-related language is being prototyped).
The jMaki Widget Model

A jMaki widget is a reusable component that is made up of an HTML template and a corresponding JavaScript file. An optional CSS file may be provided by the widget. This document details the jMaki widget model and what initialization parameters that are passed to each widget.

Template - component.htm

jMaki ensures that the HTML templates get rendered with unique and instance specific parameters. The following is a template of a simple <div> element with unique id.
<div id="${uuid}"></div>
component.htm Example
The ${uuid} token is replaced when jMaki processes the template as it renders the page.

Behavior - component.js

jmaki.namespace("jmaki.widgets.foo.bar");
 
jmaki.widgets.foo.bar.Widget = function(wargs) {
    // widget code here    
}
component.js example
Notice that the entire widget is placed in a namespace jmaki.foo.bar and that it is called "Widget". This is because all jMaki widgets are in essence packages and the Widget is the constructor which is passed an the widget arguments. Widget JavaScript code not conforming to this convention will not be loaded.

Widget Properties

The server-side runtime passes instance parameters for an individual widget to the jMaki JavaScript runtime as a function call with the instance parameters as an object literal. The JavaScript runtime then passes instance parameters to the widget as it is created. Following are the arguments that are passed and the token names that are replaced in the widget component.htm template.
Property Name
Template Token
Widget Arguments
Value
script
N/A
N/A
The URI to JavaScript for the widget.This is basically an override for the component.js.
template
N/A
N/A
The URI to the template.This is an override for the component.htm.
style
N/A
N/A
The URI to the styles used for this widget.This is an override for the component.css.
name
${name}
wargs.name
The name of the component. This is the only required argument.
id
${uuid}
wargs.uuid
The unique value associated to each component instance. This value is autogenerated by the server runtime and may be overriden using an 'id' argument.
args
${args}
wargs.args
A JavaScript object literal that may contain any number of JavaScript key value pairs.
service
${service}
wargs.service
This is the service value associated with each component instance. When a service is used, the data used by the widget is loaded asynchronously using an Ajax call after the widget has loaded.
value
${value}
wargs.value
The service value is an inline value given to the widget that needs to be in JavaScript object literal format.
The most powerful attribute is the args attribute as it can be used to map any set of generic properties to a widget as an object literal. These properties may then be accessed from the widget instance (via the widget.args property). Care must be taken to properly document the various properties as they can differ on a widget to widget basis.
With JSP and JSF, the properties are passed in using tag attributes on the tag matching the name of the property. In all cases the properties must be included in double quotes. All JavaScript properties used with the args and value are JavaScript object literals and should use single quotes or escaped double quotes.

Widget Initialization

jMaki will do the following after the page onload event fires.
  1. Lookup up the constructor function for each widget in the order they are defined in the page. Constructors must be named jmaki.[widget name].Widget. For example, in the case of a widget with the name "foo.bar" the constructor that is searched for is jmaki.widgets.foo.bar.Widget. Note that all constructors are required to be under the jmaki namespace to keep all jMaki JavaScript objects from cluttering the JavaScript global scope.
  2. Call new on the constructor passing the widget instance parameters as an object literal.
  3. Place the widget instance contained in the jmaki.attributes Map with the unqiue ID (uuid) as the key. You can later get a handle of this widget instance using the call jmaki.getWidget(uuid)

Post Load Event

If your widget requires post initialization you can provide a postLoad function which will be called following the widget initialization.
// define the namespaces for foo and bar
jmaki.namespace("jmaki.widgets.foo.bar");
 
jmaki.widgets.foo.bar.Widget = function(wargs) {
    this.postLoad = function() {
        var this = jmaki.attributes.get(wargs.uuid);
        // do something with this
    }   
}
component.js example with a postLoad function
Providing a public postLoad is a good place to register glue listeners and load data asynchronously.

Widget Destruction

You can provide a code that will unwire events and nodes that may lead to memory leaks by providing a destroy function on your widget. This function will be called when the clearWidgets function is called.
// define the namespaces for foo and bar
jmaki.namespace("jmaki.widgets.foo.bar");
 
jmaki.widgets.foo.bar.Widget = function(wargs) {
    var container = document.getElementById(wargs.uuid);
        
    this.destroy = function() {
        var this = jmaki.attributes.get(widget.uuid);
        // do something with this
    }   
}
component.js example with a destroy function
While not required, it is recommended you provide a public destroy method in your widgets to clean up widget resources.
  
The life-cycle of a jMaki Widget
Now that we know what widgets are and have seen how widgets names and types are used let's dig a little deeper and see how widgets are created and initialized. jMaki widgets are rendered in a two step process which spans both the client and the server. The following diagram details the lifecycle in more detail.
  1. jMaki Widget Defined Encountered
  2. Resource References for the Widget are Rendered to the Page - The JSP tag or JSF component renders the necessary HTML content with the proper linkages to the corresponding files that make up a jMaki widget. For example, the CSS styles defined in the component.css of a widget. If the widget is of a specific type, such as Dojo, the script tags for those dependent libraries will also be rendered to the page.
  3. Template Content is rendered to the Page - The template content from the component.htm file is rendered to the page. The template content contains tokens such as ${uuid} which represent a unique identifier of the widget. These identifiers are replaced on a per widget basis as the HTML is initially rendered. Content will be further rendered on the client after the page loads.
  4. jMaki Bootstrapper is Initialized - A script element containing the jMaki boostrapper (jmaki.js) is rendered to the page before any other script references are rendered by the JSP tag or JSF component. This script creates a globally scoped JavaScript object named "jmaki" which contains properties and functions to register, load and support jMaki widgets.
  5. Widget instance is created and registered with the Bootstrapper - After a widget's template text has been rendered, the widget along with its instance parameters is registered with the jmaki bootstrapper. Registration is done using the jmaki.addWidget function where the instance parameters used to initialize the widget are passed as object literals.
  6. Widgets are Initialized and Rendered to the Page - Following the JavaScript "onload" event the jmaki boostrapper will iterate through the widgets that were registered and initialize each instance. Each widget is evaluated using the JavaScript code from the corresponding component.js. A locally scoped object literal named widget containing the initialization parameters (properties) for the widget such as the the unique identifier of the widget, service name, and arguments that were defined for the widget is used to initialize the widget instance. These parameters correspond with those that were rendered to page for that widget instance.
  7. The Page is made available - Once rendered, the page is made available for further event processing.
The key steps for the the parameters getting passed by the server rendered code to the JavaScript instance are found in steps 3, 5 and 6 above. Parameters such as the widget identifier from template content in component.htm are rendered in step 5 and are passed to the JavaScript runtime (the jmaki.addWidget bootstrapper). The same parameters are then passed as properties in step 6 to the component.js script that initializes the widget instance. jMaki is all about parameterized JavaScript. Now that we have seen how the parameters are passed between the Java and JavaScript worlds lets look in more detail at what parameters may be passed.

No comments: