jMaki Glue

If you are new to glue we suggest you first review Intro to Glue which covers the basics on glue really well.

What is glue?

Glue is a mechanism that ties application functionality together and provide a great out of the box experience. In jMaki all widgets can be listeners or publishers of events on a common publish/subscribe bus. Glue provides timers, defaults topics along with conventions for publish subscribe events, and allows for function handlers not tied to widgets to provide application specific behavior. Glue promotes a clean separation of application behavior from content which is also commonly referred to as Unobtrusive JavaScript.

Let's first review glue handlers then timers.

Declarative Glue

Glue handlers may be described both declaratively or programatically in jMaki. After we look at the syntax we can talk about advanced topics including the use of regular expressions and wildcards.

Glue Includes

{"config": {
    "version": ".9",
    "glue" : {
       "includes" : ["/glue.js"],
      }
}

Glue Includes are declared in the config.json and are loaded after jmaki.js has been written to the page but before the page onload event has been fired. Glue includes are loaded after extensions are loaded. In the example above a single file glue.js is loaded containing any applicaiton logic.

You can include different page specific files containing application specific logic by using a object array with url and lib properties like the following:

{"config": {
    "version": ".9",
    "glue" : {
       "includes" : [
       { url: "*", lib : "/glue.js" },
       { url: "/foo", lib : "/foo-glue.js" },
       ],
      }
}

In the example above glue.js is mapped to all URLs using a wildcard. If the URL (starting from the web root is "/foo") the file foo-glue.js will be loaded after glue.js. Glue includes are in the order which they appear in the page.

Glue Include Wildcards

{"config": {
    "version": ".9",
    "glue" : {
       "includes" : [
       { url: "*.do", lib : "/do-glue.js" },
       { url: "/bar/*", lib : "/bar-glue.js" },
       ],
      }
}

In this example all urls starting with "/bar/*" will include bar-glue.js and all URLs ending with "*.do" will include do-glue.js. For larger applicartoions this should be very usfull.

Declarative Glue Handlers

jMaki Glue mappings between topic names and handler functions may be declaratively specified in the config.json as follows:

{"config": {
    "version": ".9",
    "glue" : {
       "includes" : ["/glue.js"],
       "listeners": [
          {"topic" : "/debug",
           "action": "call",
           "target": {
                    "object": "jmaki.listeners",
                    "functionName": "debug"
               }
          }
      ]
     }
}

In the example above the glue handler is added to the jmaki.listeners object. The jmaki.listeners object is the recommended namespace for glue handler but it is not required. In the case of the example above the topic "/debug" is mapped to call the function "debugHandler" on the jmaki.listeners object. Below is the glue.js file which defines the jmaki.listeners object.

jmaki.listeners = {
    
    debugHandler : function(args) {
        alert("debug: " + args);
    }
}

Glue handlers should have a single argument which is the payload of the published event. The contents of the payload are not fixed but it is recommended to use a JavaScript object literal. The widgets are responsible for creating the payloads in most cases. Later in this document we will further describe some recommended payloads.

Programatic Glue

Glue listeners do not have to be described declaratively in JSON. They can be added directly in the glue.js file as can be seen the example below.

jmaki.addGlueListener({
       topic: "/debug", 
       action: "call", 
       target: {object:"jmaki.listeners.Debug",
       functionName:"log"}});

jmaki.listeners.Debug = {
	
   log  : function(args) {
	  alert("Debug got : " + args);
   }
} 

Alternatively a more simplified way of defining listeners can done using anonymous functions like the following:

jmaki.addGlueListener("/debug",function() {
	  alert("Debug got : " + args);
   }
); 

In this case the first argument is the topic name (which may include a wild card) and the second argument is the anonymous function that is called when a matching event is published.

Programatic glue mappings as can be seen in the example above require you only modify one file (so long as the glue.js reference is included in the config.json). This makes it easy to add or share jMaki glue handlers with others.

Regular Expressions and Wildcards with Topic Names

Regular Expressions and Wildcards may be used topic names with both declarative and programtic glue.

Regular Expressions

Glue also supports regular expressions so you can match a set of events. This is important if you want to have a single handler mange the events published from multiple widgets. In essence you can create a controller.

jmaki.addGlueListener({ topicRegExp : "onSave$", 
       action: "call", 
       target: {object:"jmaki.listeners.Controller",
       functionName:"onSave"}});

jmaki.listeners.Controller = {
    onSave : function(args) {
        alert("glue.js : onSave request from: " + args.id + " value=" + args.value);
    }
}

A simplified way using an anonymous function is :

jmaki.addGlueListener(new RegExp("onSave$"), function(args) {
        alert("glue.js : onSave request from: " + args.id + " value=" + args.value);
});

The key for this listener is the topic which in this case has a regular expression onSave$. jMaki will check all events that are published to all topics and if it ends onSave function on thejmaki.listeners.Controller object will be called. The key to designing applications to jMaki glue is to publish events following a standard set of conventions. Bellow are a few events that are used in jMaki.

Wildcards

Alternatively a wildcard can be used for topic matching. Wild cards are declared using the characters '*' and '?' at any position of the topic name. '*' matches any number of characters, '?' matches a single character. The same example above may be written as:

jmaki.addGlueListener("*onSave", function(args) {
        alert("glue.js : onSave event from: " + args.id + " value=" + args.value);
});

A more specific handler may be defined as follows:

jmaki.addGlueListener("*/dojo/*", function(args) {
        alert("glue.js : dojo event from: " + args.id + " value=" + args.value);
});

The example above will match all events containing "dojo".

Suggested Naming Conventions and Payloads for Events

Following is of suggested topic names and payloads that we recommend for widgets.

EventTopic/Sample TopicEvent PayloadDescription
onSave /dojo/editor/onSave {wargs:wargs, value:value} Any widget that wants to save its state. The payload contains the widget arguments (wargs) and the value of what needs to be saved.
onSelect /dojo/fisheye/onSelect {wargs:wargs, value:value} A select event that emitted from a widget such as the Fisheye, Calendar, Menu, or a Tree widget where the value (such as a URL) is used to drive a change in another widget.
loaded /jmaki/runtime/widget/loaded {name : name, uuid:uuid, service : service} Called by the jMaki runtime when each individual widget is loaded.
initialized /jmaki/runtime/initialized {} Called by the jMaki runtime after the runtime has been initialized and before widgets have been loaded.
loadComplete /jmaki/runtime/widgetsLoaded {} Called by the jMaki runtime after the runtime has been initialized and after widgets have been loaded.
loadComplete /jmaki/runtime/loadComplete {} Called by the jMaki runtime after the runtime has been initialized and after widgets and timers have been initialized.

Cross Frame Communication

Events published to a topic in an iframe such as one created by a Dynamic container component will be published up to all parent frames using the same topic name unless otherwise specified using the optional publish arguments.

jmaki.publish(topic, payload, bubbleDown [optional], bubbleUp[optional]);

The jMaki publish function allows for two extra arguments that will allow you to allow of disallow events from being published to sub-frames that contain jMaki contexts. Events in sub-frames are only published to the parent jMaki context if it contains a jMaki client runtime (jmaki.js).

Example of bubbling up events:

All parent frame will get the event published to the topic with "global" prepended to the topic name as to notify the parent context the source of the event.

jmaki.publish("/jmaki/foo", {}, false, true);

The parent frame and it's parent frame will see the event with the topic name /global/jmaki/foo with the payload of the original event.

Example of bubbling down events:

Events published to a topic are published to sub-frames of that window. In order to prevent duplicate events from being published multiple times the topic names to which an event is published is prepended with the string "global/". For example a frame that has sub-frames containing jMaki runtimes publishes and event as seen below.

jmaki.publish("/jmaki/foo", {}, true, false);

All child frames will get the event published to the topic /global/jmaki/foo with the same payload.

Glue Topic Mapping Considerations

When mapping topic names to specific Glue action handlers be careful when using generic expressions for mapping. Using the regular expression onSave$ as a mapping for example could result in an event being fired in both the top window and sub windows. This occurs because it is the same glue.js file that is loaded by the topic window and all sub frames. Consider only events that do not start with "/global/" in such cases. The expression ^(?!/global).*onSave$ will not get called on topic names starting with "global" and will only get called at the top window.

Forwarding Published Messages

You can listen to one topic and then multiplex events to one or more other topics. This is all done in the configuration file.

{"config": {
    "version": ".9",
    "glue" : {
       "includes": ["/glue.js"],
       "listeners": [
        {"topic" : "/jmaki/menu",
          "action" : "forward",
          "topics" : [
            "/jmaki/urldispatcher",
            "/jmaki/debug"
          ]
         }
      }
    }
}

The configuration file snippet above takes and event published to "/jmaki/menu" and forwards it to both the "/jmaki/urldispatcher" and "/jmaki/debug" topics. The key is the action property which is set to "forward". Any listeners to these topics will receive the event.

Timers

Timers are global objects that will either call a predefined function or publish an event on a timed interval.

Function Call Timer

A function call timer is simply a JavaScript function called at an interval.

{"config": {
    "version": ".9",
    "glue" : {
       "includes": ["/glue.js"],
       "timers" : [
          {"timeout": 15000,
           "action" : "call",
           "target": {
                    "object": "jmaki.listeners",
                    "functionName": "sayHello"
               }
            }
        ]
     }
}

The key for a timer is the timeout property which specifies the interval which the code is called at. The action property specifies whether a function call on an object will be made or whether a message will be published to a topic. The example above calls a JavaScript function. See the JavaScript code below for the processing logic.

jmaki.listeners = function() {
    this.sayHello = function(args) {
        alert("hello from " + args.topic);
    }
}

Topic Publish Timer

You may just need an message published to one or more topics at a specific interval. This could result in other topic calls and could be used to do almost anything to sync up a set of widgets.

{"config": {
    "version": ".9",
    "glue" : {
       "includes": ["/glue.js"],
       "timers" : [
           {"timeout": 15000,
            "action" : "publish",
            "topics": ["/sync"]
            }
        ]
     }
}

The configuration snippet above will result in a message being published to the topic "/sync" every 15 seconds.

Further Reading

Intro to Glue which covers the basics on glue.

Arun's Blog on Using and Debugging jMaki Publish Subscribe is essential for development with glue.

Fun with jMaki: Using the Yahoo Geocoder service with the Dojo Combobox shows some of the potential of jMaki Glue to work as a controller.