Wednesday, July 9, 2008

Cross framework javascript - coding for portability

Imagine that you have written a useful javascript widget using your preferred library (dojo), but at work you must use another framework (jQuery), and a customer needs that you code with Prototype.
Now, you can modify your component by hand, replacing the ajax calls (eg from dojo.xhrGet to $.get), the event handling (from dojo.connect to obj.observe...), the effects... What a boring job!

Or you can write a wrapper who dynamically identifies the js library you are using and maps the ajax calls (and the event handlers, etc...) to the correct form for you.
We can write code like this:

var engine = com.nicolarizzo.utils.runtime.currentEngine;
var showMessage = function(){
window.alert("that's all!");
};
var startup = function(){
engine.byId("currentEngine").innerHTML = com.nicolarizzo.utils.runtime.engineName;
engine.connect(engine.byId("clickMe"), "onclick", this, showMessage);
};
engine.addOnLoad(startup);
without the knowledge of the underlying frameworks!

VoilĂ , here a proof of concept, incomplete and inaccurate as usual, using jQuery :)

The mapping is very simple:

// jQuery mappings
com.nicolarizzo.utils.runtime.currentEngine = {
addOnLoad: function(fnToExecute){
return jQuery(document).ready.call(jQuery, fnToExecute);
},
connect: function(trg, evt, context, method){
if(evt.indexOf("on") == 0){
evt = evt.substring(2);
}
context = context || trg;
jQuery(trg).bind(evt, function(){method.call(context)});
},
byId: function(id){
return jQuery("#" + id)[0];
}
};

Isn't it nice? ;)

Labels: , , , ,

Sunday, June 15, 2008

(Very) lazy loading in javascript

Using the "lazy loading" in javascript is a common technique to minimize the startup time of a web application.
Usually a single object is retrieved from the server with its own members and methods: but why not use instead of the methods a stub which loads the method source when is called the first time?
For example, a singleton object like this, having two methods:
var application = {
sum: function(){
return arguments[0] + arguments[1];
},
product: function(){
return arguments[0] * arguments[1];
}
};

could be written as (you can use your preferred ajax framework/library; remember: use a synchronous call):

var application = {};
var names = {
"sum" : "sum.js",
"product" : "product.js"
};
for(var i in names){
application[i] = function(x){
return function(){
dojo.xhrGet({
url: names[x],
sync:true,
handleAs:"text",
load: function(data){
application[x] = new Function(data.replace(/\n/g, ""));
},
error: function(err){
window.alert("[error] " + err);
}
});
return application[x].apply(this, arguments);
}
}(i);
}
Oh yes, this is a stupid example, the stub method is greater than the real method, but it's only a proof of concept ;)
You can find a live example here

Labels: , , , ,