HTML 5 Offline data storage

One of the most anticipated features of HTML 5 and all it's consequential technologies and APIs are the «offline storage» APIs. In this post I'll take a "real world" approach to using the HTML 5 Web-Database and the «HTML 5 Offline application cache». I will take you through an example where a complete elephant gets stored on your computer. That's right! A pink one as well! The point of this demo is to investigate how to store both static data as well as dynamic data which might not be known at design time. For this occasion I have created a demo which you are free to download and inspect. It is fully commented and somewhat verbose for easier reading. What this application does in essence is to store a HTML and a JavaScript file on your computer, then it will go on to store a picture (which could be dynamic data) in a local database, hence making the application usable when not online. Let's have a look!

So, our goal is to store both static data and some dynamic data. To achieve this we'll need to use two approaches as mentioned above. The first one, called «HTML 5 Offline Application Storage» is almost automatic once you have it configured. We will utilize this method to store our main JavaScript file so that it will work when you're not online. Cool!
This approach uses a simple text file, called a «manifest file» which tells the browser which data to store locally. In order for this file to be interpreted by the browser correctly you'll need to (1) configure your web-server to serve this file with the «text/cache-manifest» mime-type. It doesn't matter what kind of extension you use, but I prefer either «.manifest» or «.cache». Now that thats out of the way we need to create the «manifest file». Mine looks something like this.

CACHE MANIFEST
# Cache manifest version 1.0.5
# If you change the version number in this comment,
# the cache manifest is no longer byte-for-byte
# identical.

main.js

NETWORK:
# All URLs that start with the following lines
# are whitelisted.

http://web.kinderas.com/

The first line MUST be the text «CACHE MANIFEST». After that you'll go on to specify the files you'll like to be cached. Here you'll put stuff like JavaScript files, HTML pages, CSS files and so on. Mine only has the one «main.js». Note that you do NOT need to specify the HTML file which declares the manifest file. This will typically be your «index.html» file or something like that. More on that later. The next section is the «NETWORK:» section. In this section you specify a "white list" containing URL's from where your application is allowed to get it's data. If you don't specify this your app will not download any data, not from the server it's hosted on or from anywhere else. I have specified my own domain since this is where the elephant is hosted.
You declare the manifest file in your HTML file like so:
<html manifest="cache.manifest">
That is it for the manifest file actually. If you are simply going to host a static site, a game or something like that, this will work just file as is. Note that to update your files, you do need to make a change in the manifest file itself, like incrementing the version number.

Next we need to add some sexy JavaScript in order to make the pink elephant available for your viewing pleasure in locations the WiFi gods have forsaken. There are three main steps to this: (1) Opening and creating the database and the table if it's not already present. (2) Reading the image from the database or saving it to the database if it's not already in there. (3) Displaying the image. I will not be explaining every line of the code in this post, you'd rather take a look at the JavaScript file and read the comments. However I will discuss some of the more important points briefly.
Not all browsers will support the HTML 5 database APIs, so we need to check for this before we can do anything. To do this we check for the existence of the «openDatabase» method on the «window» object, like so:

if(!window.openDatabase){
// No support for HTML 5 db
return;
}

This will detect if the browser has support for the methods we need. If not, give the user a message or some alternative content.
Then, to open / create the database we would we simply write:
db = openDatabase('testdb','1.0','Offline Elephant DB',1024*1024);
We have just created a 1MB database or opened one if it already existed. Now it's ready to execute SQL queries using transactions.

var sql = 'CREATE TABLE IF NOT EXISTS offline_image (id INTEGER ....);';
db.transaction(
 function(transaction){
  transaction.executeSql(sql,[],
  function(transaction, result){
   //The table was created
  },
  errorHandler);
 }
);

The database table has now been created if it wasn't already there. We now need to check if there is an image already saved in the database, this happens on line 56 in the «readImage()» function. If there is an image with the matching filename saved, we use that, if not we go on to loading and serializing the image, as follows.

var canvas = document.createElement('canvas');
var ctx    = canvas.getContext('2d');
var img    = document.createElement('img'); 
img.onload = function(){
 canvas.width  = img.width;
 canvas.height = img.height;
 ctx.drawImage(img,0,0,img.width,img.height);
 var base64Image = canvas.toDataURL();
 showImage(base64Image);  
}
img.src = sImgURL;

To be able to save the image we need to create a text version of it's data. We can accomplish this by loading the image and then rendering it in a canvas element. The Canvas element has a method called «toDataURL» which will create a base64 representation of the Canvas content. Base64 images, also referred to as data urls can easily be saved to the database. Base64 data can also be read directly by the «img» element, so there is no need to decode the base64 string again once it's encoded. But, do note that the canvas element will give you the png base64 version of the image, and it's quite a bit larger than the original binary file.

That's the gist of it, but you do need to take a look at the demo and the JavaScript in order to really understand what it going on here. Once you get the hang of it, this is a really powerful approach to making web-applications much more accessible and more interesting.

Further reading:

9 things I've learned about web-development

I've been a developer for quite some time now, meddling with both the web-centric and the native side of things. As of lately, that is for the last 3 months or so I have focused more in depth on "standards" based web development. Meaning HTML, CSS and JavaScript. Even if I've been writing HTML since 1996 (yeah, I'm getting old), I have never really bothered to really focus in depth on the basic building blocks of HTML, CSS and JavaScript, until now. 4 books and many many hours of training videos later I feel that I've learned something, which is that an iPad make for a lousy pillow if you keep trying to sleep on it! But more than that, I found 9 things that I have learned, which may be blatantly obvious to you if you are a fancy pantsy web-developer, but then again, maybe you'll learn something new?

1. Web-designers and web-developers think differently.
What do I mean by that? Consider of how you're tagging your HTML with classes and id's. The designer approach to this would be classes all the way, then using the clever selector syntax of CSS to reach the nested areas of the document. This makes sense when working with formatting. Developers tend to view the HTML as a framework with components. Classes are used for formatting while id's are used to identify areas of the markup one would need to reach via JavaScript. Designers will prioritize the "flow" of the «document» whilst developers don't consider it a document at all. I don't think either approach is «correct» or «wrong», it's just two ways of approaching the same challenge.

2. CSS is not a layout language.
Almost all layout in modern HTML based webpages are done using CSS, so how can anybody claim that it's not a layout language? I too was somewhat surprised when time and time again the "people who knew what they are talking about" kept repeating this. From the WHATWG to W3C and several books on the topic kept driving this home..«not a layout language». Turns out, CSS is a formatting language with some layout features. Semantics? Well, not really. If you compare CSS 2.1 to a "real" layout language like MXML you'll soon notice a big difference. Layout languages, or UI markup languages have special layout components to group element, flow elements, sort elements both horizontally and vertically. CSS 2.1 does not have this, it's totally reliant on either floats or absolute positioning. This will better with the introduction of the flexible box model in CSS3, but still it will remain a formatting language at heart.

3. CSS selectors are incredible powerful...stuff
This is one of the areas on which I have discovered most new stuff. CSS 2.1 embodies most of them, but with the introduction of the CSS 3 standard, selectors can now do some amazing stuff. Conditional child selection, substrings within attributes while traversing child elements are just some examples. And the best part is that they are largely supported in all modern browsers, including Internet Explorer 8. If I where to recommend one area on with to focus you attention, if you don't already know this, it would be CSS selectors. It's not complicated or hard to understand, there are just so much under the hood which can make your CSS writing a lot more enjoyable.

4. Things will look different in different places.
If you try to create pixel perfect designs across all browsers and platforms you will go bonkers, that is unless you are a technophile machochist whom derives enjoyment from banging your head up against the gigantic wall of Internet Explorer inconsistency. You're much better off using either the progressive enhancement or the graceful degradation approach where you serve different users the same content, only wrapped in a slightly different presentation. This way Internet Explorer users can sit and stare at that black and white page of rich text all day long, while us WebKit fanboys can swim in the loveliness that is a modern browser with animations and shit.

5. A position is not the same position elsewhere, or everywhere.
Since this is more or less an extension of point 4, I can't be bothered to find a pretty picture for this one. (As a side note, if you use Google image search for the term "position", turn safe search on!) What this point is concerning, what I've found is: Firefox and Chrome (or any other browsers) does not have the same interpretation when it comes to rendering a point at, say x: 100, y: 100. Since it's up to the user agent (browser) to parse your CSS and HTML and then draw it on the screen, you will at certain points end up in a situation where an absolute point in the top left coordinate system will differ from user agent to user agent and even on the same user agent on different operating systems. This can be avoided by using floats and containers instead of using absolute positioning. But, it's better to accept that things might not look exactly the same everywhere.

6. Modernizer Rocks!
If you ever need to use conditional CSS 3 or HTML 5, Modernizer is by far the best solution I've found. The way Modernizer works is actually twofold. You can first use it with CSS directly. Lets say you want to take advantage of the RGBA color model found in CSS 3, but you also need to support those pesky Internet Explorer users. All you need to do in your stylesheet is to prefix your class or id selector with ".rgba". Let's say I wanted to apply a style via the selector «h2[class*="onkey"]», but only for browsers supporting RGBA. It would look like this: «.rgba h2[class*="onkey"]». The RGBA class simply adds itself as a ascendant class. This style would then only apply if RGBA was supported. The other way of using Modernizer is with JavaScript. To check for support for H.264 video playback abilities, simply use «Modernizer.video.h264» and it'll return false, "maybe" or "probably". Yep, that is the HTML 5 spec for video format detection..

7. jQuery selectors are convenient, JavaScript is fast!
If you don't know what jQuery is, you should go find out! Someone once wrote that jQuery is Gods gift to JavaScript. Where God is of course John Resig and I was the one that wrote that, just now in fact. jQuery is seriously awesome, it allows for fast and easy cross browser development. Underscoring cross browser, which is what it does really really well. It is just a JavaScript framework, a tiny one at that, but crammed with neat functionality, from animations, ajax loading and the usage of CSS selectors to get a hold of DOM elements. You can say things like: «jQuery('div.donkey')» which would give you all the donkey divs in the page. This is really convenient, because you can find stuff in the DOM with the same syntax used in the CSS. There is a downside however. When using CSS selectors in a CSS file or in the HTML file, the user agent takes care of all the heavy lifting required to traverse the DOM and find those elements. This is fast because the user agent does this natively using a compiled language such as C. However, jQuery is not written into the native part of the browser and will therefore need to use JavaScript to traverse the DOM to find the elements based on the CSS selector. Hence using the build in JavaScript functions «getElementById», «getElementsByTagName» or the spanking new «getElementsByClassName» is much faster than using the jQuery selectors. What you can do is combine them like so «jQuery(getElementById('id-name'))». Then you would get the speed of the native JavaScript functions while keeping all the jQuery goodness as well.

8. There are datatypes in JavaScript!
!!Nerd alert!! Even if you don't explicitly declare datatypes in JS, there is a difference between for example «"2"» and «2». If you where to add these two values together «"2" + 2», you'd get «"22"», while «2 + 2» returns «4». Now, what if «a = [2,3,"a"]» and «b = 2». What would «a + b» give you? That's right «a + b => "2,3,a2"». JS has a lot of functions for dealing with this. You have «toString()» to convert a number to a string, «parseInt(strNum)» to convert a string into a whole number and so on. The important thing is to be astutely aware of it, even if you can't declare a strict datatype.

9. The WebKit Web Inspector is your most important tool
If you're in any WebKit browser, Safari, Chrome so on you have access to the build in "Web Inspector". This tool is your best friend when working with HTML, CSS and JavaScript. It will do anything the more famous Firebug does and more. Don't get me wrong, I'm not railing on Firebug which is an awesome tool, I am however highly recommending the WebKit Web Inspector because of it's speed, advanced profiling tools and unsurpassed JavaScript debugger. Try it and you'll see why I'm praising it!

So that's it, or more likely, that's some of it. If you have actually read all the text down to this I truly hope that this post have contributed in some small way to your blah blah blah blah..you know the drill. Now get back to work, those recursive functions won't be creating themselves ;-)