Implementing WebStorage for PhoneGap + Windows Phone Mango ( Part 1 )

Implementing WebStorage for PhoneGap + Windows Phone Mango ( Part 1 )

Windows Phone 7 with the Mango updates includes the new IE9 which is a very capable browser, and has support for many new standard HTML5 APIs.

Some of the feature highlights (IMHO) include:

  • addEventListener : no more conditional event code
  • querySelectorAll : easily grab DOM elements by id/class/type etc.
  • WebStorage APIs : localStorage + sessionStorage
  • ES5 : Function.bind, Array.forEach, …

The reader: But wait, I thought this post was going to be about how the WebStorage APIs were added to PhoneGap for WP7, but you just said IE9 supports it, what gives?

The writer: I’m getting there just wait …

So, IE9 implements the complete spec for WebStorage as defined here: http://dev.w3.org/html5/webstorage/
Unfortunately, this implementation is only available to web pages that are loaded from a domain because of the way the data stores are sandboxed per domain. In the context of a PhoneGap application, our page is loaded from IsolatedStorage ( aka: file:// ) so we are not assigned a domain by IE9, so we do not have access to localStorage.

Okay, so having seen this I realized that I needed to polyfill here, and provide an implementation. However, upon attempting to set window.localStorage to my own object, I received an error stating that window.localStorage was read-only? oh crap! After a little more exploration, I remembered my ECMA. ECMAScript 5th Edition to be precise, and IE9 supports it. So after a quick test, I discovered that I could duck-punch/polyfill window.localStorage using Object.defineProperty(obj, prop, descriptor); Sweet!

You can look ahead to the JavaScript implementation here : DomStorage.js

The JavaScript implementation supplies the following interface to window.localStorage and window.sessionStorage :

interface Storage {
readonly attribute unsigned long length;
DOMString? key(unsigned long index);
getter DOMString getItem(DOMString key);
setter creator void setItem(DOMString key, DOMString value);
deleter void removeItem(DOMString key);
void clear();
};

Implementing this on the native side was a little different than a typical plugin. Many of the calls are synchronous, so I needed to have some data up front, and a method to call native code synchronously. Note: I could have implemented the entire interface using the FileAPI, but this would mean storing the entire key/value set in JavaScript so that it could be called synchronously. After some experimentation, I discovered that even though C# code cannot return a value to a JavaScript call to ScriptNotify, it can set a value from C# before execution is passed back to JavaScript, so we can mimic the behavior of a return value.

In this example, the value of this._result is set before window.external.Notify returns, so it is available as a return value from the JavaScript function.

var retVal = null;
if(this.keys.indexOf(key) > -1)
{
window.external.Notify("DOMStorage/" + this._type + "/get/" + key);
retVal = this._result;
this._result = null;
}
return retVal;

Note: While this works, perfectly, we do have to be careful that we don’t again call ScriptNotify in the callback to set the _result value, otherwise we could overflow the stack with multiple nested calls.

More to come soon, done a lot of blogging and not enough coding for today. Stay tuned.

    No Twitter Messages