A (dojo.)mixin configuration approach to XAgents in XPages

Continuing my XPages theme from yesterday I also wrote an XAgent base-class in JavaScript to make XAgents easier to do. Part of the base class is that it allows me to pass in a JSON object to configure the XAgent based on the need. Since the information I pass in should override the built-in defaults I needed a way to easily allow the user supplied values to override the defaults. The easiest way to do this would be to use the dojo.mixin.

"dojo.mixin is a simple utility function for mixing objects
together. Mixin combines two objects from right to left,
overwriting the left-most object, and returning the newly
mixed object for use."

Unfortunately Dojo isn’t available in SSJS I needed to do it myself. To my luck it was surprisingly easy as the below code illustrates.

// create function to allow mixin' two objects
var mixin = function(target, source) {
   if (!source) return;
      var name, s, i;
      for (name in source) {
      s = source[name];
      if (!(name in target) || (target[name] !== s)) {
         target[name] = s;
      }
   }
};

My XAgent base class looks something like this:

function XAGENT(args) {
   // create mixin function
   var mixin = function(target, source) {
      if (!source) return;
         var name, s, i;
         for (name in source) {
         s = source[name];
         if (!(name in target) || (target[name] !== s)) {
            target[name] = s;
         }
      }
   };

   // define default arguments
   this._args = {
      download: false,
      filename: "default.json",
      charset: "iso-8859-1",
      contentType: "application/json"
   };

   // mixin user-supplies arguments
   mixin(this._args, args);
};
XAGENT.prototype.run = function(command) {
   ...
};

What’s super neat is that now, in my run-method I can access the this._args object and all values that the user supplied have overridden the default values because we used the mixin-function. Very cool and an easy and flexible way to have default values but allowing them to be overridden by the caller. Also you know that the variables you need have been defined so no checks are necessary.

Calling my XAgent class is very easy allowing me to override the defaults. The run-method accepts a function which is called when the XAgent stuff has been set up supplying the Writer and the parameters supplied in the URL as a JSON object.

var xa = new XAGENT({
   filename: "feed.json",
   download: true
});
xa.run(function(w, params) {
   ...
});

XPages JavaScript utility function of the day

Yesterday and today I’ve been spending some time doing some XPages coding for a customer project and after spending quite some time doing Java plugin development I’m amazed of how easy XPages are. Don’t get me wrong – there is still work to do for the XPages team but it’s a joy to work with XPages and coding in JavaScript is just – well – flexible and fun.

One of the real joys of JavaScript is it’s dynamic nature and that it allows one to really cut down on the boilerplate and repeated code. For one I spent a lot of key pressed getting field values from backend documents in server side JavaScript. Instead of repeating the same ol’ Document.getItemValueString(String) over and over again I did a neat little shortcut. Since I needed all items from a document I just created a utility function to JSONify a document to make it easier to access. The method is below.

var jsonifyDocument = function(doc) {
   var result = {};
   if (!doc) return result;
   var item;
   for (item in doc.getItems().toArray()) {
      result[item.getName().toLowerCase()] = item.getText();
   }
   return result;
};

So now instead of writing doc.getItemValueString all the time I can now just do property-like access to field values (“Heading” and “Description” are fields on the document).

var jsonDoc = jsonifyDocument(doc);
jsonDoc.heading + " (" + jsonDoc.description + ")";

I also wrote a nice little Dojo-like mixin function to make my XAgents easy to configure. But that’s for another day.

ext.js moves to a commercial license

I first heard of this on some TWIT podcast so I went to see for myself but it appears that the ext.js Javascript framework has gone from an open source to a commercial license. This means that you have to pay if you use ext.js in an application that isn’t compatible with the GNU license. All of the applications I do fail this requirement.

This is too bad and effectively removes ext.js as a framework I will even consider. With dojo being the framework of choice come Domino 8.5 this will however not be too much of a loss.

Citrix and AJAX – one bad combo?

Anyone using AJAX type-ahead controls under Citrix? I have been working on a customer solution using the select-widget from the dojo toolkit but it doesn’t work correctly in Internet Explorer under Citrix (you can type ahead but cannot use the arrow keys to select from the choices). Just checked script.acolou.us and their autocomplete widget doesn’t work either under Citrix either (same issue). Previously I have been using a solution I developed myself but really want to go mainstream…

script.aculo.us autocompleter example.

JSONMap class

I’m starting off with converting some inhouse developed AJAX stuff to using DOJO and for that reason I needed to convert my XML responses to JSON. Using the JSON Java classes this was pretty straight forward but I really needed an easier way to convert a java.util.Map instance to JSON. Extending JSONArray this was easy. Provided here for those who might need similar code…

package org.json;

import java.util.Iterator;
import java.util.Map;

public class JSONMap extends JSONArray {
   public JSONMap(Map m) {
      for (Iterator ite=m.keySet().iterator(); ite.hasNext(); ) {
         String key = (String)ite.next();
         String value = m.get(key).toString();
         JSONArray a = new JSONArray();
         a.put(value);
         a.put(key);
         this.put(a);
      }
   }
}

Code like this

Map m = new HashMap();
m.put("AL", "Alabama");
m.put("AK", "Alaska");
m.put("AR", "Arkansas");
JSONMap jm = new JSONMap(m);
System.out.println(jm.toString());

will output the following JSON

[
    [ "Alabama", "AL" ],
    [ "Alaska", "AK" ],
    [ "Arkansas", "AR" ]
]