Mobile Widgets – Persistence Cross-Platform Wrapper

This is the second post in our series on building Mobile Widgets. The first post was an introduction to Mobile Widgets.

Mobile Widgets – a primer

In this post we will build a persistence library that works across multiple platforms and abstracts away the differences of those different platforms into a common set of methods.

Seeing that we are also about to release our Ripple Emulator, we will be using it for our testing to showcase the built-in persistence view and platform switching capabilities of the Ripple Emulator.

Lets get started…

The different platforms:

Persistence is handled differently by each of the platforms that we would like to support here. Sometime the differences are subtle, and sometimes no so much. Let’s first expose the different methods that each of the platforms use to save, retrieve, and remove preferences from their respective local storage.

JIL API 1.0.x to 1.1

The first release of the JIL framework exposed two methods for dealing with persisting preferences. Here are the methods with their signatures:

Saving ====> Widget.setPreferenceForKey(key, preference)
Retrieving ==> Widget.preferenceForKey(key)
Removing ==> Widget.setPreferenceForKey(key, null)

JIL API 1.2.x

In the 1.2 release of the JIL API the same methods mentioned above still exist, however, a change was made to the setPreferenceForKey method signature (notice that key and preference have been reversed). The methods dealing with persistence are below:

Saving ====> Widget.setPreferenceForKey(preference, key)
Retrieving ==> Widget.preferenceForKey(key)
Removing ==> Widget.setPreferenceForKey(null, key)

Note: to see the differences between the different beta releases, you can visit our public JIL-API repository here: http://wiki.github.com/tinyhippos/JIL-API/api-change-log

UPDATE: Based on some extra testing in the JIL SDK Emulator, we have discovered a bug in the emulator. the preferenceForKey() method seems to return an object instead of a string. This causes our use the JavaScript “===” comparison to fail. This does work correctly on the actual mobile devices. We have raised this issue with the good folks at JIL.

Opera Widgets

The persistence mechanism for Opera Widgets is very similar to the JIL API 1.2. The main difference is that Opera Widgets use a lower case “widget” object. The methods are as follows:

Saving ====> widget.setPreferenceForKey(preference, key)
Retrieving ==> widget.preferenceForKey(key)
Removing ==> widget.setPreferenceForKey(null, key)

HTML 5 Local Storage

This is pretty straight forward, just using the localStorage object. Here are the methods:

Saving ====> localStorage[key] = preference
Retrieving ==> localStorage[key]
Removing ==> localStorage.removeItem(key)

Using Cookies

Should none of the storage options mentioned above be available, we’ll also add support for plain old cookies. To make our lives easier, we just used jQuery for saving and retrieving values using cookies.

The persistence wrapper

Rather then go line by line to show you how we’ve written this helper library, we’ll direct you to our open source github repository so that you can download it, play with it, and perhaps contribute to it should you think of any enhancements you’d like to add.

github repository: http://github.com/tinyhippos/MobileWidgets the persistence library can be found in the “lib” directory and is named Persistence.js

For convenience, our persistence library is dependent on jQuery and json2. All the info can be found in the source file :-)

The testing widget

In order to see the persistence wrapper in action, we need to build a little testing widget. I’m not going to show the process of building the entire widget to save time and space. you can however get the full source code for it here in the DemoWidget repository: http://github.com/tinyhippos/ripple_demo

We have created a very simple form that allows us to specify a key and value to be saved or deleted if it’s already in storage. Below is the very simple HTML for the form:

<form id=”persistenceForm” onsubmit=”return false;”>
<table>
<tr>
<td><label id=”persistenceKeyLabel” for=”persistenceKey”>Key:</label></td>
<td><input id=”persistenceKey” name=”persistenceKey” type=”text”></td>
</tr>
<tr>
<td><label id=”persistenceValueLabel” for=”persistenceValue”>Value:</label></td>
<td><input id=”persistenceValue” name=”persistenceValue” type=”text”> </td>
</tr>
</table>
<button id=”persistenceSaveButton”>Save Preference</button> <button id=”persistenceDeleteButton”>Delete</button>
</form>
 

For simplicity, we’ll use jQuery to bind the events to each of the buttons “onmousedown” events. We are using “onmousedown” since some of the widget frameworks have a documented issue with handling the onclick event properly. Once we execute the save or remove functions, we’ll also display a message to the user. Here is the code for the event binding:

jQuery(“#persistenceSaveButton”).mousedown(function() {
$.Persistence.save(jQuery(“#persistenceKey”)[0].value, jQuery(“#persistenceValue”)[0].value);
jQuery(“#persistenceResult”).removeClass(“irrelevant”);
});
jQuery(“#persistenceDeleteButton”).mousedown(function() {
$.Persistence.remove(jQuery(“#persistenceKey”)[0].value);
jQuery(“#persistenceResult”).removeClass(“irrelevant”);
});

The shell of for our global Demo object looks something like this:

var Demo = {};
(Demo.Persistence = function ($){
return {
save: function(key, value){
// do save here
},
remove: function(key) {
// do remove here
}
};
}(Demo));
 

Now, you might notice that the notation seems a little odd, that’s because we’re using an auto invoked function passing in our global Demo object into it and using the $ to denote our global object. This notation is used so that we can get proper JS closure as well as to avoid polluting our global namespace with all of our functions.

Now, let’s see it in action

Now that we have both our persistence library and our demo widget, let’s load them into the Ripple Emulator and see it all in action. The Ripple Emulator isn’t available publicly just yet, but you can sign up here to be the first to get the details once we launch into beta (April 27th).

We will point Ripple at the directory that contains the demo widget, enable it and go to the form. It only takes 1 second to load and we will see this:

The Persistence Form

Please click on the image to expand

Once it’s loaded we can enter some values into the form we created and hit the “Save Preference” button in the widget. You will notice on the bottom left panel in Ripple that you can now see the key and it’s value as they would have been saved on the mobile device. Our persistence library adds an optional prefix to the key, this is a feature we found useful, but please feel free to remove it if it doesn’t suite your needs.

Persistence Form with saved value

Please click on the image to expand

Now, we can click on the “Delete” button and we’ll see that the key and it’s value have been removed from storage.

Persistence key removed

Please click on the image to expand

And for our final trick, we’ll change our platform from JIL API 1.2.1 to the Opera widget platform. You can do this seamlessly in the Ripple Emulator by selecting the platform you wish to test on at the top right of the screen (we’ll cover this in more detail in a later post). You’ll note in the screen shots below that once we save a preference it will show up in preferences table on the bottom left as before. The screen shots also shows the Chrome Web Inspector console, and you’ll note the console message showing that we saved a preference using JIL (in the first screen shot) as our current framework  and Opera (in the second screen shot)

Presistence on JIL

Please click on the image to expand

Persistence on Opera

Please click on the image to expand

What’s next

Stay tuned for more articles in this series where we’ll explore other parts of the Ripple Emulator and provide more open source libraries and information on Mobile Widget development best practices.

Your feedback is important to us

Your feedback is very important to us. Please feel free to comment on the Ripple Emulator, our sample code, or anything else for that matter. We’ve open sourced the sample code and encourage the community to contribute so that all mobile widget and mobile web developers can benefit.

About these ads

5 Responses

  1. Hi Dan,

    How about the W3C Widget Interface API methods?

    These have the same method signatures as the HTML5 Storage API (localstorage etc), but invoked off the widget object – I guess JIL will eventually migrate them.

    S

    • Hi Scott,

      Thanks for the comment. We are keeping a close eye on it and will update the sample widget once things settle a little bit. Looks like JIL is now WAC and they have released the first draft of their spec. So… we’ll be seeing some changes from them soon. W3C spec will also continue to evolve and we’ll do our best to keep up with them for our demo widgets.

      Not sure if I’ve answered your question, but it’s very hard to give a definitive answer while things are still in flux.

      Best regards,

      Dan.

      • Thanks Dan. I think the W3C Widget Interface is now stable, certainly on the preferences/storage API side of things.

        I can see why JIL/WAC adopted the first draft spec rather than waiting until the spec settled down, but it does make things a bit more err… interesting … now!

        We’ve implemented the W3C TWI spec in Apache Wookie, but we’ll probably need a similar (or same?) wrapper to let users add JIL or Opera widgets without requiring too much tinkering.

      • Hi Scott,

        I will have to take another close look and update our cross-platform persistence lib as needed. Thanks for letting me know. I would very much like to have a conversation with you (via email) to find out more about what you’re doing. Sounds really interesting!

        Expect an email from me shortly. Thanks for reaching out and commenting on our blog, very much appreciated!

        Best regards,

        Dan.

  2. [...] Mobile Widgets – Persistence Cross-Platform Wrapper Mobile Widgets – a primer [...]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: