So, Apparently I'm an iPad Developer Now colorful lead photo

Last week my boss stopped by and dropped a brand spanking new iPad on my desk. "Make our application work on this," he commanded. "You have two days before we demo it at the trade show."

Madness? No, these are web apps! You see, for the last couple years we've been working exclusively on AJAX applications: web pages stuffed with so much JavaScript they look and feel like desktop apps. It's harder than writing desktop software, but if you pull it off you get an application that can be run anywhere, instantly.

So, I'm not a "real" iPhone/iPad developer; I've never even seen the dev kit. I just do web apps. Although maybe "just" isn't the right word. We had a 60,000 line application running on a completely new platform the same week it launched.

Can your app do that?

We already supported Safari, so you'd expect it to work on the iPad too... and it did, mostly, except for a couple of bugs. Flipping the iPad on its side would mess up the layout, double clicks didn't work, stuff like that. Here are the problems we hit, and what we did to solve them.

Browser Detect

To fix a browser-specific JavaScript bug you need to know when you're on that browser. Detecting the iPad is easy: the iPad user agent contains the unique string "iPad", so we checked for that.

// a function to parse the user agent string; useful for 
// detecting lots of browsers, not just the iPad.
function checkUserAgent(vs) {
    var pattern = new RegExp(vs, 'i');
    return !!pattern.test(navigator.userAgent);
}

if ( checkUserAgent('iPad') ) {
    // iPad specific stuff here
}

Simple enough.

Orientation Change

Flipping the iPad would also mess up our layouts. iPads use an accelerometer to detect if they're being held vertically or horizontally (or upside down.) From the browser's point of view it looks like the window was resized from 1024x768 to 768x1024; and you get the normal window resize event you'd expect.

We use ExtJS, and their Layout framework usually does a great job handling the window resize event on normal browsers. It knew that something had happened but didn't recalculate all the sizes correctly. (To be fair, we use some pretty complicated layouts.) This is probably do to subtle timing issues or some such. I didn't waste much time figuring out what was going on, because there's a way to cut this Gordian knot: the iPad specific orientationchange event.

window.onorientationchange = function() {
    alert(window.orientation);
}

window.orientation is one of 0, 90, -90, or 180. 0 and 180 are portrait; 90 and -90 are landscape. The onorientationchange event fires whenever it changes. For us, it was sufficient to say viewport.doLayout() on orientation change; that gave ExtJS the hint it needed to get the sizes right.

Double Click

Safari on the iPad co-opts the double click event for its own use (a local zoom.) You can listen for the dblclick event in JavaScript... it just never fires. That was a bit of a problem, because we'd consistently allowed the user to double click stuff (a row in a grid, for example) to jump to a more detailed view.

We settled on a two finger touch gesture to emulate the double click: touch an item in one place and tap it in another.
Diagram of a two-finger simultaneous tap Tapping with two figures simultaneously also works. When I say emulate, I mean that literally: when we detect one of these double touches, we actually tell the DOM to fire a dblclick event. That way, the solution worked everywhere and we didn't have to track down every single place we registered a dblclick listener.

document.body.addEventListener('touchstart', function(e) {
    touch = e.touches[0];
    if ( !touch ) return;
    var me = document.createEvent("MouseEvents");
    me.initMouseEvent('dblclick', true, true, window,
        1, // detail / mouse click count
        touch.screenX, 
        touch.screenY, 
        touch.clientX, 
        touch.clientY, 
        false, false, false, false, // key modifiers
        0, // primary mouse button
        null  // related target not used for dblclick event
    );
    touch.target.dispatchEvent(me);
});

Unfortunately, this code is too simple. You see, both the iPad and iPhone use "two finger scrolling" for scrollable regions (elements with CSS overflow: scroll;) within a website. Diagram of a two-finger scroll There's no way to turn this off, and it doesn't even show a scrollbar: it's two finger scrolling or nothing.

If you use the above code as is, the dblclick event will fire as soon as the user tries to use two finger scrolling. We ran into this because we have grids with thousands of rows to scroll from where the user can double click a row to go to a detailed view. To fix this problem, we had to make sure we only fired an emulated dblclick event if the user quickly double tapped a row, not if they pressed and dragged. So instead we only set up a timer in the touchstart event and actually fired the dblclick from touchend. This requires more code, but lets us handle "double clicking" inside of scrollable regions.

Nitpicking

Pretty much every reviewer has mentioned the iPad's "gorgeous screen," but it's just a 1024x768 display at fairly low DPI, so I'm not sure what that's about. We test everything down to 800x600 so we were ok, usability-wise, but it sure looks a lot better on a large monitor.

We also embed Google maps, using them as backdrops to display geographic data, and the web experience for Google maps is somewhat diminished compared to the full fledged Google Maps iPad app. They still work, though.

Safari on the iPad and iPhone doesn't fire mouse events on elements it doesn't consider "clickable". Registering a click event listener, even if it doesn't do anything, will allow the element to receive the full set of mouse events.

Aftermath

We made the two day deadline.

Did it work? Man, people were stopping by our booth just for the chance to touch an iPad. This was less than two weeks after it launched; there was a lot of curiosity. We use a bunch of data visualization like Google maps and charts, and it was just stunning. It was like a thick, juicy slice of future, served of a piece of future toast. I can't say for sure it generated a sales lead, but it sure brought in some serious foot traffic.

But what do you expect? Web apps can and should run anywhere, even on stuff that hasn't been invented yet.

- Oran Looney April 28th 2010

Thanks for reading. Please subscribe to the RSS feed and remember that future readers will thank you for leaving your comments and criticisms. Subscribe to RSS Feed

Comments (12)

September 28th 2012

Dave Sumner said:

Wow. That is awesome. As a old fat client developer making the leap, thanks for helping my pitiful fledgling web site pages work on my iPad. I can see the power of the run-anywhere web app and I agree, write once run everywhere simply rocks. Thanks again.

September 13th 2012

mmdpwx said:

TnaweK , [url=http://buvklztjnnya.com/]buvklztjnnya[/url], [link=http://pwjmwztwaeel.com/]pwjmwztwaeel[/link], http://wbjqywzawupa.com/

September 12th 2012

fmachydea said:

ZALS36 <a href="http://yfoneonrejuf.com/">yfoneonrejuf</a>

September 12th 2012

lujjfiyy said:

arCb3n , [url=http://cjnuqtyihkej.com/]cjnuqtyihkej[/url], [link=http://uyimmtrjwqju.com/]uyimmtrjwqju[/link], http://ykbnmcjuweyz.com/

September 11th 2012

fpkialxoimy said:

shne4g <a href="http://hebrgrwdesqi.com/">hebrgrwdesqi</a>

September 11th 2012

Deshawn said:

This shows real expertise. Thanks for the anwesr.

June 6th 2012

robot said:

how can i scroll on modal window?? :p

December 12th 2010

Many said:

Hi Oran, Nice post, I would like to know how do you prevent the zoom event on dblclick?

October 17th 2010

Jamie said:

Hi Oran, Nice post, I've done something similar too but a slightly different approach. Firstly I chose not to use the viewport layout as it resizes the layout when you zoom in, on resize the iPad/iPod is slow to resize the layout. So instead I used a Panel and set the width and height. I'm still to code a resize on window orientation. Double click, I chose to just port everything over to single click and pop it all in a context menu. Nitpicking, one fine day Sencha should be the interface of choice for iPod/iPad, but realistically why bother, if you have a full blown app and only 2 days to get it going :) Unfortunately grid features don't all work on the iPad/iPod i.e. resize, column re-ordering.

May 31st 2010

Luke said:

Hi Oran, Great post, Got the rotation resize on our web-app running great. one note is that if you do not wish the alert to appear, but still want the window resized, it seems the javascript (will sometimes) still want a function, so a donothing() seemed to fix it. ( this behavior was very hard to replicate. Alos would you be able to clarify if the doubleclick code you have given should work without modification (even if it causes issues with scrolling). As we are unable to determine if it is a conflict with icefaces, or wether the code itself needs editing to work. cheers for the great post

April 30th 2010

Oran said:

Jeff - unfortunately that's proprietary code owned by the company I work for, and too complex to reproduce from scratch. Most web pages don't use double clicks at all, and usually not in a nested scroll region. So I hope the code in the article will be enough.

April 30th 2010

Jeff said:

Could you give the code for double clicks with scroll please?

Leave a Comment

Your Name:
Comment:
Enter this phrase:
captcha