Mobile Webapps – iUI Framework Extensions
// August 3rd, 2009 // 9 Comments » // Mobile, Web
As I explained in my earlier Masabists post, I’m finally able to show off some of the work I’ve been doing recently on local mobile webapps. We’ve based our webapps on the rather excellent iUI framework, which has a great philosophy:
- Clean, standard HTML markup;
- Very lightweight – one CSS stylesheet and a single Javascript file;
- Built-in AJAX support, so form values can be submitted and HTML fragment responses pasted into the document structure;
- iPhone native-style look and feel, including slick screen to screen transitions and screen rotation support.
The screens are all embedded inside a single HTML file, which has two advantages:
- You get very rapid movement around the app, with no need for a reliable network connection and none of the slowdown associated with downloading every page;
- You can cache the app using an HTML 5 manifest, so even when the user has no network signal they can access the site.
This is great as far as it goes, but there were a number of screen types not supported. I have added an optional extension script, following the same philosophy, to add them – this ost is just a reference point to describe what the extensions do, when discussing merging them into the framework.
Structure
The extensions are in a seperate script and CSS file, which creates the window.iui_ext object, much like the core iUI framework itself.
To work, iUI has been extended in one key way – it now fires off Javascript events to screens, specifically:
onFocus()is called whenever a screen is made visible;onBlur()is called whenever a screen is left.
Both events are called at the point where the link is clicked and the sliding transition begins.
Adding the events gives the developer a huge amount of extra scope for controlling the webapp, which is then used to create the additional webapps without breaking away from clean markup.
Form Handling
The iUI extensions automatically add focus and blur event handlers for every form, which store all field values in a name/value store whenever a form is left and restore the values whenever a form is visited again. These are added inside the iUI code, and once finished they will call any explicitly defined onFocus="..." / onBlur="..." attributes within the markup.
The map follows the same basic semantics as the HTML 5 sessionStore object, which I wanted to use but sadly it isn’t implemented on the iPhone yet (the latest desktop Safari seems to have it though). The methods are exposed through the iui_ext object, for example window.iui_ext.getItem('key').
The purpose of this store is to allow the movement of values between screens, which enables a number of tricks – by declaring inputs on seperate forms (displayed as seperate screens) with the same name attribute, you can make sure they always mirror each other’s values. If for any reason you don’t want this behaviour for some fields, you can declare an onBlur event and remove them from the store.
Option Lists
I needed a form screen which listed a number of fields which could be changes, such as railcard type in the screenshot below, and by tapping on the field the user would move to a list of all the possible options from which they could select one. A few examples of this UI pattern from my iPod Touch Settings app are:
- Settings > Music > Audiobook Speed (list of 3 options)
- Settings > Video > Start Playing (list of 2 options)
- Settings > Safari > Accept Cookies
Visually, it looks like this:
I implemented in two stages. Firstly, I generated CSS to render a radio input (with label) as a block with the tick if it is selected, using a bit of custom Safari CSS (-khtml-appearance:none;) to suppress the native style of a checkbox – which interestingly changes from relatively nice on an iPod Touch v2 to quite nasty on an iPhone 3GS.
Next up, I tried to think of a natural way to express the options in HTML, and ended up with the idea of getting a script to rewrite any select in a form which has the CSS class of ‘panel’ into a seperate linked panel. The markup you write looks like this:
<div class="row"> <label for="buy_railcard">Railcard</label> <select id="buy_railcard" name="railcard" class="panel"> <option value="rc_none" selected>None</option> <option value="rc_youth">Youth</option> <option value="rc_family">Family</option> <option value="rc_senior">Senior</option> <option value="rc_disabled">Disabled</option> <option value="rc_network">Network</option> <option value="rc_hm">HM Services</option> </select> </div>
By default, it would render like this (taken from desktop Safari, just to make my life easier):

The script rewrites the above HTML on the original form like this:
<div class="row"> <a href="#select__buy_railcard">Railcard <input type="hidden" name="railcard" value="rc_none"/> <var id="railcard-rc_none" class="_lookup rc_none">None</var> </a> </div>
Points to note:
- The original form will submit in exactly the same way to the server
- the new hidden field within the link has the same
nameas theselectand thevalueof the selectedoption.
- the new hidden field within the link has the same
- The textual label of the selected option is copied into the var tag, which actually visually shows the selected option to the user
- the var is also given the option value as a css class, which allows us to do the funky icons on all labels if we want (using
:beforegenerated content, in this case).
- the var is also given the option value as a css class, which allows us to do the funky icons on all labels if we want (using
The script also creates a new form.panel screen containing the options as a radio group, like this:
<form id="select__buy_railcard" class="panel" title="Railcard">
<fieldset class="radiogroup">
<div class="row">
<label class="rc_none" for="buy_railcard_option_rc_none">None
<input id="buy_railcard_option_rc_none" type="radio" value="rc_none" name="railcard"/>
</label>
</div>
<div class="row">
<label class="rc_youth" for="buy_railcard_option_rc_youth">Youth
<input id="buy_railcard_option_rc_youth" type="radio" value="rc_youth" name="railcard"/>
</label>
</div>
<div class="row">
<label class="rc_family" for="buy_railcard_option_rc_family">Family
<input id="buy_railcard_option_rc_family" type="radio" value="rc_family" name="railcard"/>
</label>
</div>
<div class="row">
<label class="rc_senior" for="buy_railcard_option_rc_senior">Senior
<input id="buy_railcard_option_rc_senior" type="radio" value="rc_senior" name="railcard"/>
</label>
</div>
<div class="row">
<label class="rc_disabled" for="buy_railcard_option_rc_disabled">Disabled
<input id="buy_railcard_option_rc_disabled" type="radio" value="rc_disabled" name="railcard"/>
</label>
</div>
<div class="row">
<label class="rc_network" for="buy_railcard_option_rc_network">Network
<input id="buy_railcard_option_rc_network" type="radio" value="rc_network" name="railcard"/>
</label>
</div>
<div class="row">
<label class="rc_hm" for="buy_railcard_option_rc_hm">HM Services
<input id="buy_railcard_option_rc_hm" type="radio" value="rc_hm" name="railcard"/>
</label>
</div>
</fieldset>
</form>
Date Selection
One of the greatest things in HTML 5, to me, is also one of the simplest – the input tag has now been extended to allow all sorts of new types, such as dates, telephone numbers and even colours. The idea is that browsers will then handle these specially with funky calendar drop downs etc that curretly have to be implemented in Javascript – and on mobiles, they can use a more appropriate native solution optimised for the keypad, with address book access etc.
Obviously, no mobile browser has bothered to implement these – today you’ll have to look at Opera desktop if you want to see a browser starting to do it correctly.
In the absence of a native widget, I implemented a date selector myself. On the iPhone itself, this is implemented in a style similar to HTML drop-downs in Safari – difficult to achieve in HTML alone, and not actually that natural for selecting travel dates. I opted to support date selection with a calendar reminiscent of theiPhone calendar app’s instead:
As before, this is implemented with a standard piece of HTML that is rewritten by the script. To add a calendar you add an input like this to your form:
<div class="row"> <label for="buy_travelDate">Outbound Date</label> <input name="travelDate" id="buy_travelDate" type="date" class="date" value="1/1/2009"> </div>
The type you choose to assign can be either date or text. If you set the input’s type to text by hand, the script will always replace it with a custom calendar. Currently, Safari rewrites any type it doesn’t understand to text when the page loads; if and when date support is added, this will presumably cease and the script will stop handling dates for you and leave selection to the browser. Your choice which you want!
When the form is first loaded, your markujp is rewritten like this:
<div class="row"> <a href="#select__buy_journeytype">Journey Type <input type="hidden" name="journeytype" value="tt_single"/> <var id="journeytype-tt_single" class="_lookup tt_single">Single</var> </a> </div>
There will also be a (singleton) extra screen created for the date picker like this:
<form id="_datepicker" class="panel">
<p>
<span id="_dpback" class="back"> </span>
<span id="_dpmonth" class="month"/>
<input id="_dphidden" type="hidden"/>
<span id="_dpfwd" class="fwd"> </span>
</p>
<table id="_dptable" cellspacing="0" cellpadding="0" border="0">
<colgroup>
<col class="sun"/>
<col class="mon"/>
<col class="tue"/>
<col class="wed"/>
<col class="thu"/>
<col class="fri"/>
<col class="sat"/>
</colgroup>
<thead>
<tr class="days">
<th>Sun</th>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thu</th>
<th>Fri</th>
<th>Sat</th>
</tr>
</thead>
<tbody>
<tr class="wk1">
<td> </td>
<!-- etc -->
</tr>
<tr class="wk2">...</tr>
<tr class="wk3">...</tr>
<tr class="wk4">...</tr>
<tr class="wk5">...</tr>
<tr class="wk6">...</tr>
</tbody>
</table>
</form>
The screen is a singleton, which means it will only be created once, and reused for every date picker in your app (which saves on memory). Month and day names are taken from arrays which could be externalised and internationalised easily if required (CSS class names on cols are hardcoded though).
Every time the date picker is selected, the script refreshes the calendar, working out the date from the hidden field on the original form and copying over the relevant details. Table cell contents are updated with the relevant date, and onClick events set to make selections work.
There are a few options, which can be passed in using CSS classes applied to the date field:
- If the
todayclass is specified, then any selection of today’s date will be stored on the form (and shown visually) as ‘Today’ instead of the date; - If the
futureclass is specified, only today and future dates are visible and selectable; - If the
pastclass is specified, only today and past dates are visible and selectable; - A date pattern can be specified using the following syntax:
- Parts of the date:
dfor the date eg. 28Dfor the day’s abbreviated name eg. Mon or Frimfor the month’s number eg. 1 (for January)Mfor the month’s abbreviated name eg. Jan or Decyfor the year as two digits eg. 09Yfor the year as four digits eg. 2009
- Other symbols:
_underscore is converted to a spacecis converted to a comma- Hyphens and slashes are also allowed.
- Examples:
d/m/ygoes to 3/8/09d-M-ygoes to 3-Aug-09Dc_d_M_Ygoes to Mon, 3 Aug 2009
- Parts of the date:
If a date format is set, then only that format can be used to specify the value of the field.
That’s basically it for my extensions – having documented them, I’ll now see if anyone wants them merged in to the main iUI framework!













