Cover by Sam Ruby, Leonard Richardson

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

O'Reilly logo

A del.icio.us Example

Back in Chapter 2 I showed clients in various languages for a REST-RPC hybrid service: the API for the del.icio.us social bookmarking application. Though I implemented my own, fully RESTful version of that service in Chapter 7, I’m going to bring the original service out one more time to demonstrate a client written in JavaScript. Like most JavaScript programs, this one runs in a web browser, and since it’s a web service client, that makes it an Ajax application. Although simple, this program brings up almost all of the advantages of and problems with Ajax that I discuss in this chapter.

The first part of the application is the user interface, implemented in plain HTML. This is quite different from my other del.icio.us clients, which ran on the command line and wrote their data to standard output (see Example 11-1).

Example 11-1. An Ajax client to the del.icio.us web service

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0
 Transitional//EN" "http://www.w3.org/TR/REC-html40/transitional.dtd">
<!--delicious-ajax.html-->
<!--An Ajax application that uses the del.icio.us web service. This
     application will probably only work when saved as a local
     file. Even then, your browser's security policy might prevent it
     from running.-->

<html>
 <head>
  <title>JavaScript del.icio.us</title>
 </head> 
 <body>
  <h1>JavaScript del.icio.us example</h1>

  <p>Enter your del.icio.us account information, and I'll fetch and
  display your most recent bookmarks.</p>

  <form onsubmit="callDelicious(); return false;"> 
    Username: <input id="username" type="text" /><br /> 
    Password: <input id="password" type="password" /><br /> 
    <input type="submit" value="Fetch del.icio.us bookmarks"/>
  </form>

  <div id="message"></div>
  
  <ul id="links"></ul>

My user interface is an HTML form that doesn’t point anywhere, and some tags (div and ul) that don’t contain anything. I’m going to manipulate these tags with JavaScript functions. The first is setMessage, which puts a given string into the div tag (see Example 11-2).

Example 11-2. Ajax client continued: definition of setMessage

  <script type="text/javascript">      
   function setMessage(newValue) { 
     message = document.getElementById("message"); 
     message.firstChild.textContent = newValue;
   }

And it’s not quite fair to say that the HTML form doesn’t point anywhere. Sure, it doesn’t have an “action” attribute like a normal HTML form, but it does have an onsubmit event handler. This means the web browser will call the JavaScript function callDelicious whenever the end user clicks the submit button. Instead of going through the page request loop of a web browser, I’m using the GUI-like event loop of a JavaScript program.

The callDelicious function uses the JavaScript library XMLHttpRequest to fetch data from https://api.del.icio.us/v1/posts/recent/. This is the URI used throughout Chapter 2 to fetch a user’s most recent del.icio.us bookmarks. First we need to do some housekeeping: get permission from the browser to send the request, and gather whatever data the user entered into the HTML form (see Example 11-3).

Example 11-3. Ajax client continued: definition of callDelicious

   function callDelicious() { // Get permission from the browser to send the request. 
     try {
       if (netscape.security.PrivilegeManager.enablePrivilege)
         netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
     } catch (e) { 
       alert("Sorry, browser security settings won't let this program run."); 
       return; 
     }

     // Fetch the user-entered account information 
     var username = document.getElementById("username").value; 
     var password = document.getElementById("password").value;

     // Remove any old links from the list. 
     var links = document.getElementById("links"); 
     while (links.firstChild) 
       links.removeChild(links.firstChild) 
     setMessage("Please wait...");

Now we’re ready to send the HTTP request, as shown in Example 11-4.

Example 11-4. callDelicious definition continued

     // Send the request. 
     // See "Working Around the Corner Cases" for a cross-browser 
     // "createXMLHttpRequest" implementation. 
     request = new XMLHttpRequest(); 
     request.open("GET", "https://api.del.icio.us/v1/posts/recent", true, 
                  username, password);
     request.onreadystatechange = populateLinkList; 
     request.send(null);

The third JavaScript function I’ll define is populateLinkList. I’ve already referenced this function, in the line request.onreadystatechange = populateLinkList. That line sets up populateLinkList as a callback function. The idea is that while api.del.icio.us is processing the request, the user can go about her business, surfing the web in another browser window. Once the request completes, the browser calls populateLinkList, which handles the response. You can do JavaScript programming without these callback functions, but it’s a bad idea. Without callbacks, the web browser will go nonresponsive while the XMLHttpRequest object is making an HTTP request. Not very asynchronous.

The job of populateLinkList is to parse the XML document from the del.icio.us web service. The representation in Example 11-5 represents a list of bookmarks, and populateLinkList turns each bookmark into a list item of the formerly empty ul list tag.

Example 11-5. Ajax client concluded: definition of populateLinkList

     // Called when the HTTP request has completed. 
     function populateLinkList() { 
       if (request.readyState != 4) // Request has not yet completed
         return;

      setMessage("Request complete."); 
      if (netscape.security.PrivilegeManager.enablePrivilege) 
        netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
      // Find the "post" tags in the representation
      posts = request.responseXML.getElementsByTagName("post");

      setMessage(posts.length + " link(s) found:"); 
      // For every "post" tag in the XML document...
      for (var i = 0; i < posts.length; i++) { 
        post = posts[i]; 
        // ...create a link that links to the appropriate URI.
        var link = document.createElement("a"); 
        var description = post.getAttribute('description'); 
        link.setAttribute("href", post.getAttribute('href'));
        link.appendChild(document.createTextNode(description));

        // Stick the link in an "li" tag...
        var listItem = document.createElement("li");
        // ...and make the "li" tag a child of the "ul" tag.
        listItem.appendChild(link); links.appendChild(listItem)
      }
    }
  }
  </script> 
 </body>
</html>

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required