Charles Engelke’s Blog

January 1, 2012

Chrome Web App Bookshelf – Part 5

Filed under: Uncategorized — Charles Engelke @ 6:21 pm

Note: this is part 5 of the Bookshelf Project I’m working on. Part 1 was a Chrome app “Hello, World” equivalent, part 2 added basic functionality, part 3 finally called an Amazon web service, and part 4 parsed the web service result. This part will actually reach the point of usefulness!

The app so far isn’t really useful because it doesn’t remember books to buy later. And that was the whole point. So instead of just displaying the response I’m going to save it persistently using the localStorage capability of HTML5. That’s simply an object (a property of the global window object) that retains its value even when a web page (or the browser as a whole) is closed. Each web site has its own localStorage area. There’s an API for it and it also can work pretty much like a regular JavaScript object. So I’m going to keep all the response data in it.

localStorage does have some pretty severe restrictions. The biggest one is that it can only store strings. At one time it was supposed to be able to store any object that could be serialized into a string, but as of now Chrome seems to only want strings there. So I’m going to have to serialize and deserialize all my objects to store them.

localStorage gives me a solution for my other problem, too. I can’t distribute the app with my Amazon Web Services credentials in it, but I can save the proper credentials persistently and let each user save his or her own values. So the app will have to have two faces now. One is the main app I’ve been working on, and the other is a simple one to use to enter the credentials. If there are no credentials in localStorage I’ll show the settings screen, otherwise I’ll show the main app.

So the main.html page now needs a body with two divs, one for each situation:

   <div id="settings">
   </div>
   <div id="application">
   </div>

It also needs to add a link to a stylesheet in the head of the document, as follows:

   <link rel="stylesheet" type="text/css" href="main.css" />

And, of course, it needs a stylesheet. It will start out very simple, just a rule to hide both divs. The JavaScript will show the proper div once it examines localStorage:

#settings, #application {
   display: none;
}

So, what about the main.js program? It starts out by again waiting for the document to be ready, declaring “global” variables, and setting up event handlers for buttons, but then it immediately checks localStorage to see whether to show the settings page or not:

   if (localStorage.accessKeyId && localStorage.secretAccessKey) {
      showApplication();
   } else {
      showSettings();
   }

The showSettings function is very simple:

   function showSettings(){
      $("#settings").show();
   }

All that is in that div are a couple of labeled data entry fields and a button to save the values entered into them. When that button is clicked, the handler just saves them in localStorage and starts the application:

   function saveSettings(){
      localStorage.accessKeyId = $("#accesskeyid").attr("value");
      localStorage.secretAccessKey = $("#secretaccesskey").attr("value");
      $("#settings").hide();
      showApplication();
   }

And showApplication just shows the proper div and creates an AWS object. The rest of its functionality happens when the button is clicked to add a new book to the list.

   function showApplication(){
      aws = new AWS(localStorage.accessKeyId, localStorage.secretAccessKey, "engelkecom-20");
      $("#application").show();
   }

That “engelkecom-20″ is my AWS associate ID. I’ll hard code that so that any URLs created by the application include it. That way, should anyone ever use this app I have a chance to make some commissions from Amazon sales.

The remaining big difference is that the result from looking up an item at Amazon will be saved in localStorage, and the results div will be replaced by a results unordered list. When the app first starts up and each time a book is looked up that list will be redrawn. This is accomplished by first replacing the reference to insertResponse in the aws.itemLookup function call with a reference to a new function called saveResponse:

      function saveResponse(response){
         localStorage.setItem("asin_"+response.asin, JSON.stringify(response));
         displayBookList();
      }

I’m naming each item with the prefix asin_ followed by Amazon’s ASIN for the item. That serves two purposes. It lets me look up a book directly by Amazon’s unique ID when I need to, and it lets me recognize which fields in localStorage hold book data and which don’t. Since I can only reliably store strings, I use the build-in JSON.stringify function to convert the object to a string without losing any information.

The displayBookList function will also be called at the end of the new showApplication function. In each case, it clears out all the items in the results unordered list and adds all the saved items back to it:

   function displayBookList(){
      var books = [];
      var i, key;

      $("#results li").remove();

      for(i=0; i<localStorage.length; i++) {
         key = localStorage.key(i);
         if (key.substr(0,5)=="asin_") {
            books.push(JSON.parse(localStorage.getItem(key)));
         }
      }

      books.sort(byReleaseDate).forEach(function(book){
         insertBook(book);
      });
   }

This first removes all the list items in the results list, then builds an array of all the books found in localStorage, and then calls insertBook to insert each book in the (by now sorted) array into the results list. insertBook is pretty much the same as the old insertResponse function shown before, with just a bit different HTML markup in it, so I’m not going to include it here. Note the use of JSON.parse to convert the string back to a JavaScript object.

Does it all work? Let’s see. First, when first launched it should show the settings panel, and it does:

Settings panel

After credentials have been saved, it should show pretty much the old application:

App screen with no books

And, once a few books have been added, it should show a list of them:

App showing a list of books

And even if the browser is closed and later re-opened, it still shows the list of books.

This was my core goal for this app. It’s ugly in a lot of ways (not just appearance; the code could use a lot of cleaning up, too). But I’ll see to that later. Now it’s time to move on and look at how to distribute the app. First, I’ll package it and try that out. Then I’ll try hosting it at a known address. Finally, I’ll put it in the Chrome Web Store. I’ll also put up a zip file of all the code created so far, so anybody who likes can try things out.

All of that will start in my next post.

About these ads

2 Comments

  1. [...] 3 finally called an Amazon web service, part 4 parsed the web service result, and part 5 actually was somewhat useful. The series is almost done now. This post will cover packaging and [...]

    Pingback by Chrome Web App Bookshelf – Part 6 « Charles Engelke’s Blog — January 7, 2012 @ 3:53 pm

  2. [...] 3 finally called an Amazon web service, part 4 parsed the web service result, part 5 was useful enough to publish, and part 6 covered publishing it at my own website. This post [...]

    Pingback by Chrome Web App Bookshelf – Part 7 of 7 « Charles Engelke’s Blog — January 8, 2012 @ 1:37 pm


RSS feed for comments on this post.

The Rubric Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 47 other followers

%d bloggers like this: