Web Development for the Blackberry Pearl

We had a potential client which wanted to use our web application on their Blackberry Pearl devices. I figured "How hard can it be?", downloaded an emulator and got cracking :) I wanted to make the standard pages support the Pearl, I didn't want to write a whole new web app, without changing how they worked on desktop browser to avoid confusing existing customers.

The tips below are things I specifically ran into on the Pearl, I imagine they'll apply pretty well to any low end mobile browsing device.

Tables make layout inflexible - the Blackberry has a fairly narrow screen when compared to a desktop. If your form laid out is in a table which is several hundred pixels wide the chances are it's not going to fit in the width. Since your page is most likely already too long for the display this is going to leave users having to scroll in two axes to complete the form. To avoid this I changed all the forms I expected to get used on the Pearl into a tableless layout which then used CSS to achieve the same display on the desktop, and then add a mobile stylesheet to override this:

<link rel="stylesheet" href="style/handheld.css" media="handheld" type="text/css">

This meant they lay out in a grid on a desktop browser but in a linear column on mobile devices

No javascript by default - the web app I was working with has been in production for more than five years, so it has it's share of hairy code particularly in the javascript department - a mixture of inline and external. One of the main issues for me was that so much of the supporting functionality depended on JS - for instance the search form could be filled out and submitted, but the functionality for scrolling through the results depended on onclick events on buttons. I re-wrote the forward and back buttons to be wrapped in little forms of their own which submitted to the correct URLs to solve that fairly easily (and that worked just as well for full desktop browsers too).

The more difficult situation was the input form, which, although it allows free text input, also allows you to select from a list of available options. Unfortunately the way this has always worked is for users to click on a button which launches a pop-up window, then double click on the item they want out of the resulting select list. The value is then inserted into the main form and the window closed, and the whole process is driven by javascript.

So, obviously it's not going to work at all without any javascript. I should point out this represents a bad design decision, I should have started with a form which worked without javascript and layered the enhanced behaviours on top (a technique known as progressive enhancement, but way back when the decisions were made I didn't know any better and neither did anyone I worked with. So I was re-writing the page in my ASP era web app, but I wanted to keep visually identical (close enough, at least) to the previous version. Here's an example of what the form components looked like before I started (names have been changed to protect the innocent):

<tr>
<td>
  <input class="standardWidth" value="Service Group" onclick="openPopup('Default.asp?WCI=listItems','PopUp','300','680');" type="button">
</td>
<td>
  <input autocomplete="off" name="txtITEM" id="txtITEM" size="25" maxlength="20" title="Click button to display list" value="" type="text">
<div style="display: none;" class="auto_complete" id="txtITEM_complete">
</div>
<script type="text/javascript">
new Ajax.Autocompleter('txtITEM', 'txtITEM_complete', 'Default.asp?WCI=listItemUL', {minChars: 2});
</script>
</td>
</tr>

A quick note here so you don't get lost - I'm using scriptaculous for the auto complete, openPopup is a fairly standard popup function, all the server side functionality is encapsulated in a WebClass, basically a VB6 DLL embedded in an ASP page, so different pages are called up by varying the WCI= parameter.

After I'd switched to a tableless layout (see above), my first step was to comment out all the javascript, this broke everything &#58;&#41; Next, I changed the input element to be a submit. Every button on the form would submit it and I planned to then detect which button had been clicked on the server side. This is relatively straightforward, just give all your submit buttons a common name (but a unique id so you can reference them individually in script):

<div>
    <span class="colLeft">
        <input type="submit" name="butLogForm" id="subITEM" class="standardWidth" value="ITEM">
    </span>
    <span class="colRight">
        <input type="text" name="txtITEM" id="txtITEM" size="25" maxlength="25" value="" title="Click button to display list">
    </span>
</div>

Then, on the form target page you check the value of butLogForm, so in VB6/ASP it's Request( "butLogForm" ), and its value will be the whatever you assigned to the button which was clicked (ITEM in the above example). So if a button other than the 'main' submit button has been pressed it's easy to detect this and redirect to the appropriate selection page for the field (which would be the same page as was originally appeared in the popup window summoned by clicking the button). I then added some plumbing to direct the popup page to either submit the value as a form or populate with javascript into opener depending on how it was called and to capture all the values behind the scenes once the user had selected them.

So now the form worked fine with javascript disabled, the only task left was to make it work as it did before in a desktop browser, popup windows and auto-completes, when javascript was enabled. This was slightly complicated by the need for the javascript to know the URLs for all the pages, and these could be changed at runtime, so I decided to pass them all in as parameters to the onload function (there is a URLFor) utility function available within the webclass which calculates them). To reduce the number of URLs to be passed in I used a naming convention so that the URL for the auto-complete function could be easily generated from the popup URL by appending 'UL' to it:

if ($('subITEM')) {
    $('subITEM').onclick = function () {openPopup(urlITEM + '&IsForPage=Log','PopUp',width,height); return false;};
    if (!$('txtITEM').readOnly) {
        var elTxtITEM = $('txtITEM');
        acDiv = document.createElement('div');
        acDiv.className = "auto_complete";
        acDiv.id = "txtITEM_complete";
        elTxtITEM.parentNode.appendChild(acDiv);
        new Ajax.Autocompleter('txtITEM', 'txtITEM_complete', urlITEM + 'UL', {minChars: 2});
    }
}

The code is fairly simple. First I check to see if the relevant submit button actually exists (there are configuration settings in the app to turn each field on and off) and, if it does, adds the old popup code to the button. Next I check to see if the text field is editable (another configurable option) and add both the div required by the Ajax.Autocompleter and then initialise the control itself.

The <button> element is useless - well it might not be completely useless, I didn't try too hard, but I decided I was only using it in the first place to show off my l33t HTML skills so I just switched them back to regular input elements.

No CSS by default - the browser on the Blackberry Pearl will not use CSS by default, though you can change the configuration to enable it and it will then respect the mobile stylesheet. The main problem this posed for me was that, in a lot of places, I was relying on padding and borders to provide spacing between text elements, eg:

<div><span><strong>Status:</strong></span><span>Active</span></div>

So when CSS is turned off you end up with tall the text running together with no spaces in between, making it hard to read. Since in this situation it's impossible to control the presentation with CSS I resorted to using markup for it and added &nbsp; glyphs inside the spans in every place where the text needed a space.

Turning on javascript leads to memory errors (slowly) - just like CSS, the browser on the Blackberry Pearl will not use javascript by default. This leads to the issues I already covered above, but a more amusing issue occurs if the user happens to enable javascript. The Pearl is a low memory device, even compared to other smart phones, and if your web app has several hundred kilobytes of javascript for it to download it will use up all of that memory in a vain attempt to parse the file. Since all the javascript gets downloaded in a standard header this led to a long wait and then an error message when you even tried to access the login page on my app. I made an extremely cut down javascript file, basically the standard field validation and date formatting functions, the openPopup function and some empty function stubs for all the onload functions (to avoid error messages). Since I didn't have the time or resources to implement WURFL or DeviceAtlas and this is only ever likely to be used in controlled corporate environments, I made a user configuration setting in order to send the cut down version to the Blackberry instead of the regular JS .

Only onchange on inputs, no onblur or onfocus - the final thing that caught me out was to do with my validation and formatting helpers on text inputs, these were all hanging off onblur and were not getting fired on the Pearl. The quick solution was to change everything to onchange instead, though the reason I'd used onblur in the first place was because I'd experienced some unreliability in the desktop browsers so this was not ideal. Unfortunately I had to wrap up this project before I had chance to get into it in more detail.