Consuming external javascript services with Dojo

I want to include goggle’s GSbookBar in one dokjo application. Unfortunately this API doesn’t have a JSONP interface. I need to include one external js file and use GSbookBar object. It’s really simple but I want to so something different. The book bar appears only in one pop up of one tab in my application. It isn’t a main part so I don’t want to load the external script every time the user loads the application.

Dojo has dojo.io.script.get to load external scripts. Its a cool way to do the traditional:

var scriptElement = document.createElement("script");
scriptElement.setAttribute("id", "jsonScript");
scriptElement.setAttribute("src", "http://external/script.js");
scriptElement.setAttribute("type", "text/javascript");
document.documentElement.firstChild.appendChild(scriptElement);

dojo.io.script.get is an elegant way load external scripts. It provides us the same interface to consume JSONP and no-JSONP scripts. One important thing when we include some external js functionality in our projects is that we need to know when the external js script is loaded to use its functionality. To do it dojo.io.script.get fires load event. In scripts without JSONP interface dojo uses checkString. Dojo evaluates checkString
“typeof(” + checkString + “) != ‘undefined’ and fires load event when is loaded.

The trick I use to load external scripts is find one js object in the script and use it as checkString. In this example the checkString is GSbookBar js object

GSbookBar = undefined;
dojo.io.script.get({
    url:"http://www.google.com/uds/solutions/bookbar/gsbookbar.js?mode=new",
    checkString: "GSbookBar",
    load: dojo.hitch(this, function(){
    window._uds_bbw_donotrepair = true;
    var bookBar;
    var options = {
        largeResultSet : !true,
        horizontal : true,
        autoExecuteList : {
            cycleTime : GSbookBar.CYCLE_TIME_MEDIUM,
            cycleMode : GSbookBar.CYCLE_MODE_RANDOM,
            thumbnailSize: GSbookBar.thumbnailsSmall,
            executeList : [data.title, data.author]
        }
    }
    bookBar = new GSbookBar(this.bookBar, options);
    dialog.resize(); // hack because of a bug in dojo 1.3
    dialog.show();  // I have created dialog dijit widget previosly
})

Advertisement

killall firefox-bin

As a web developer firefox is my only choice. I need other browser to test my applications but I can’t live without firebug. I now there are other firebug-clone for other browsers but firebug is the number one.

But normally I have a console ready to type

killall firefox-bin

It’s really cool when one tab of your firefox becomes crazy and all firefox instance dies.Next generation of browsers will solve this problem. But at least now Chrome is not ready under Linux.

What can I do?, Only Cry? 😉

dojo.hitch

The first time I read about dojo.hitch I didn’t understand anything. I read in a book dojo.hitch is a very important function and widely used into dojo library but I didn’t understand why. I am using my learning of dojo to improve my skill in javascript. I remember the time when I hate javascript. I thought it was a very poor program language and everything I need to do with js was a nightmare. If browser was Netscape one way to to do one thing, if browser was IE other (of a other and a couple of hacks). But the times have changed. XHR and Ajax has reinvented the web. Web pages had became into Web Applications. Asynchronous request had opened our minds to a new generation of web applications, and all of it is thanks to javascript. Each day I spent learning js I see how much I was wrong.

Javascript literals are really powerful but the concept of scope is strange when you come from POO. this.foo in js sounds like $this->foo in PHP but its not the same.

For example in the following example:

dojo.declare("gam.desktop", null, {
    variable1: 1,
    foo: function() {
        dojo.xhrPost({
            url: myUrl,
            load: function(responseObject, ioArgs){
                console.log(this.variable1);
            }),
            handleAs: "json"
        });
    });

console.log(this.variable1); will not display 1 in firebug console. Its strange for me when I started with dojo. The problem is that here this points to the scope of the function foo and not to the scope of class gam.desktop. You can do strange tricky-hacks to solve the problem with global variables or something like that, or use dojo.hitch.

dojo.declare("gam.desktop", null, {
    variable1: 1,
    foo: function() {
        dojo.xhrPost({
            url: myUrl,
            load: dojo.hitch(this, function(responseObject, ioArgs){
                console.log(this.variable1);
            }),
            handleAs: "json"
        }));
    });

elegant isn’t it?

Dojo and custom widgets

I want to extend Dojo library with some custom widgets. Dojo widgets are really cool. You can use them from JavaScript and from HTML with the Dojo markup.

From js:

var dialog = new dijit.Dialog({
            title: title,
            href: href,
            preventCache: false,
            parseOnLoad: true
            });

From HTML:

<button DojoType="dijit.form.Button" type="submit" onClick='Desktop.login()'>Login</button>

Using Dojo widgets from HTML gives you errors when you validate your HTML files because Dojo attributes are non HTML attributes. If you are strict with HTML you have a problem using Dojo but its really easy to develop rich application with Dojo. so it’s your choice ;). But remember: validation tools are just that: validation tools

For my tests I use Dojo from CDN. Dojo library is very big so I don’ t want to upload all the library to my hosting. My hosting (a free one) has a monthly traffic usage limit so I want to limit the trafic to my hosting as far as I can (poor man techniques). Dojo library is in some CDNs (AOL and google for example). You only need to point your scripts to CDN and use cross domain (xd) of Dojo library and you are using the CDN. Really simple.

But If you create a custom widget you can’t upload your widget to the CD. If you paid for a CDN (akamai for example) you can do it but according my poor man’s techniques I use a free CDN so I can’t upload anything to the CDN.

For example when you use a dijit.form.TextBox with Dojo library pointing to google’s CDN you are using the following url:
http://ajax.googleapis.com/ajax/libs/Dojo/1.2.3/dijit/form/TextBox.xd.js
But if you are going to use your wonderfull custom widget gam.widget.coolwidget your browser will try to load:
http://ajax.googleapis.com/ajax/libs/Dojo/1.2.3/gam/widget/coolwidget.xd.js
and you will get a flaming 404 file not found error.

My first solution was upload all Dojo library to my hosting. With this solution I will can develop custom widgets without any problem but this is not the Dojo way. You can use xd version of Dojo and custom library in your server without problems. You only need to say Dojo in the configuration where are your widgets

djConfig = {
    parseOnLoad: false,
    modulePaths:{
        gam: './js/gamjs'
    },
    baseUrl: '/'
};

With this configuration Dojo will continue trying to get dijit.form.TextBox from http://ajax.googleapis.com/ajax/libs/Dojo/1.2.3/dijit/form/TextBox.xd.js but gam.widget.coolwidget from /js/gamjs/widget/coolwidget.xd.js.

Really easy. isn’t it?

Dojo series

I will start a new series of posts based on my experiences learning Dojo. This is not a tutorial of Dojo. Those posts want to help me to get new skills. The learning of Dojo is a bit frustrating sometimes. When you have written a dozens of source code and you realized all its wrong and that isn’t the Dojo way of doing this and you need to rewrite all. But you feel really happy when your widget appear on the browser. I have in my mind some post-project now and I hope I will post them soon

JSONP. JSON with Padding

JSON is a really good solution to send data from server to client in web applications. Almost every program language has his own json encode and decode. PHP allows natively to do this encoding from php arrays and objets to JSON. And Zend Framework implements Zend_JSON who also allows you to encode/decode from XML.

When I was developing a rss client to my personal home page. I discover JSONP services. Those services are really easy to use and really easy to integrate them into your projects:

If the following url gives you a json data

url: http://www.server.com/service {“identifier”:”id”,”items”:[{“id”:”18″,”title”:” Asterisk. The future of telephony”,”author”:”Jim Van Meggelen”,”bookyear”:”2008″,”why”:””}]}

It is very helpfully when

url: http://www.server.com/service?callback=myfunction
myfunction({“identifier”:”id”,”items”:[{“id”:”18″,”title”:” Asterisk. The future of telephony”,”author”:”Jim Van Meggelen”,”bookyear”:”2008″,”why”:””}]})

with this if you develop the function ‘myfunction‘ with a few javascrip lines you can consume those jsonp webservices.

This is the source code I use to read

function googleSearch(bibkeys) {
  var scriptElement = document.createElement(”script”);
  scriptElement.setAttribute(”id”, “jsonScript”);
  scriptElement.setAttribute(”src”, “http://books.google.com/books?bibkeys=” + 
    bibkeys + “&jscmd=viewapi&callback=googleCallback”);
  scriptElement.setAttribute(”type”, “text/javascript”);
  document.documentElement.firstChild.appendChild(scriptElement);
}
function googleCallback(booksInfo) { // do what you want with the booksInfo }

Adding my blog’s feed to my personal site

I have my personal web page hosted in a free hosting service. Basically it’s a dojo application working with a Zend Framework Backend. I had the idea of include a the last posts of my blog from the rss to the front page (original isn’t it?), and I start to develop it.

I started using Zend_Feed to fetch the RSS from my blog. The idea of my personal site was to develop a web application based on dojo framework so I decide to use the dojo way using dojox.data.AtomReadStore.That sounds cool but I faced with the first problem. Due to security reasons XHR requests can’t be done to a different domain. My personal page and the url of the blog’s feed were under different domain.

Problem 1: XHR with different domains.

To solve this problem I must create a proxy with PHP to RSS feed in my personal page. With this proxy XHR requests will be in the same domain, so dojox.data.AtomReadStore will work correctly. the proxy worked perfectly in my local computer but when I upload it to my hosting I realized that it didn’t work.

Problem 2: The hosting of my project doesn’t allow php’s socket functions

As I see in php.ini. some PHP functions (socket functions for example) are disallowed in the server. Because of that my code does not work. Surfing into Zend framework source code (open source is cool). I saw Zend_Feed uses Zend_Http_Client_Adapter_Socket. My hosting allows me to use curl extension instead of socket functions. But Zend Framework does not have a Zend_Http_Client_Adapter_Curl. So other problem.

Problem 3: Zend_Http_Client with Curl

As I read in some newsgroup my problem with my hosting, curl and sockets was not only mine. Zend Framework doesn’t not have a curl adapter in the production tree but they have a Zend_Http_Client_Adapter_Curl in the incubator. This adapter is not fully tested and it can crash behind proxies and things like that but it sounds good for my situation. Using this adapter the code works in my local server and in my hosting. that’s sounds good but there is other problem

Problem 4: CPU usage

Looking in the statistics of my site in the hosting I realized that the CPU usage was hight. The application is a client side application and this CPU usage graph shows me the problem. Curl functions are slow and my rss proxy is consuming too much cpu time. It sounds I am under a no-solution problem. I need a proxy to avoid XHR cross domain restriction but this proxy uses too much CPU in my poor-man- hosting. Solution: turn the logic to the client and and do all the job with javascript.

Finding some RSS reader with js I faced with GFdynamicFeedControl. Really easy to use. It also has a wizard to generate code to copy and paste. Of course the generated code didn’t work in my application but hacking a bit I have finally my RSS feeds in my personal page. GFdynamicFeedControl allow you to mix different RSS so y also include the rss of my github account with the source code.

<div id="feed-control">
    <span style="color:#676767;font-size:11px;margin:10px;padding:4px;">Loading...</span></div>
@import url("http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.css");

google.load('feeds', '1');
dojo.addOnLoad(function(){
    var options = {
        stacked : true,
        vertical : true,
        title : "Feeds"
    }
    new GFdynamicFeedControl(gamJs.feeds, 'feed-control', options);
})