The Little (&) Barely Documented) Things in WinJS & IE - Handling Basic Input

When I first started working with Windows 8 in August 2012 (a couple of months before Windows 8 released), I was excited to start writing native apps with my beloved web technologies. I didn't know what was really required other than Microsoft had some library called WinJS and a very much improved version of Internet Explorer. So I opened up my browser and started looking at documentation.

Only... this was next to impossible. There were a couple basic "Quickstart" tutorials and some bits of documentation, but finding information on these ListViews, Flyouts, and semantic zoom interactions was hard. Fortunately, a lot has changed in a year, and it's now a lot easier to find information about how WinJS handles something or what Internet Explorer 10 needs for a given CSS rule. Yet some concepts remain largely hidden or misunderstood. For my future reference as much as anything else, here I'm posting a series with some useful bits to remember when developing Windows 8 apps (which will translate to the browser as well since nothing below is specific to WinJS). This inaugural post focuses on the basics of handling input.

Pointer Events, not Touch Targets 

Apple and WebKit got developers used to handling event touches (or targetTouches/changedTouches) on touchstart, touchmove, and touchend events. Microsoft does not support this, and instead implemented what is now a W3C Candidate Recommendation - Pointer Events. There are similarities to the WebKit way - there are pointerdown, pointermove, and pointerup events, for example. But Pointer Events take a different approach in that they support all types of pointer input.

Mouse, touch, stylus - these are all covered by one event. There's no more worrying about handling touch one way and mouse another (and then worrying about if you properly disabled the corresponding mouse event when touch was used instead). If you need to distinguish, there is a pointer type inside the event to delegate different action paths.

I plan to write another post in detail about Pointer Events, but until then here are key articles to learn more.

CSS: -ms-touch-action 

More so than mouse and stylus input, touch has several default gestures that perform actions. Scrolling/panning, zoooming, and other actions are defined by the OS. So if you have a block of content that has overflow scroll, when you move your finger in that block, the content will pan. We expect this as a user. But as a developer, there are cases where we want to turn off the expected behavior and handle it on our own with JavaScript.

This is where the CSS property -ms-touch-action comes in.

Well, almost. First... an anecdote.

Our client for my first Windows 8 project wanted to turn our Semantically Zoomable ListView on the initial screen of the app to behave like the Windows 8 Start Screen. Seemed reasonable. Windows provided a ListView that looked like the tiles of the Start Screen. From there we just needed to add the abilities to toggle visibility and drag/reorder. Here's where we hit several walls. We finally found the early documentation of Pointer Events (not as thorough as it is now), but as our many unhit breakpoints made clear, our pointer event listeners were not triggering.

Finally we caught wind of a -ms-touch-action, which has a default value of auto. It sometimes seems backwards how this works, at least as it was originally presented. But once you understand the intent it becomes a lot clearer.

The default value of auto means if a user performs a standard OS gesture, do what the OS wants to do and do not fire Pointer Events. You can also specify none or one (or more) of the following values:
pan-x pan-y pinch-zoom manipulation double-tap-zoom (added for IE 11: cross-slide-x cross-slide-y)

Saying "none" will mean nothing will happen by default, but Pointer Events will be triggered for all touch interactions. Otherwise if you specify a specific value, only the specific value will be taken care of by the OS defined action (still with no Pointer events fired) while other gestures will fire the Pointer events. So if you specify only pan-x, then horizontal scrolling will work by default while dragging on the screen vertically will perform no action by default but will fire Pointer events.

For a larger example, back to the anecdote of recreating the feel of the Start Screen, we wanted to handle drag/reorder but still allow horizontal panning, as the Start Screen does. Specifically with touch on the Start Screen, if you want to move a tile, you must perform what Microsoft calls a "CrossSlide" gesture. This is essentially dragging a tile vertically until it "snaps" out of place and can then be moved freely (as a sidenote, this gesture does a lot more and can be implemented in other ways, but this is sufficient for the purpose of reordering). So we had to set -ms-touch-action as pan-x, and then we set up pointer event listeners to handle movement in the vertical direction.

The CrossSlide is an interesting beast (and IE 11 makes it a lot easier to deal with), and I plan to discuss it more, along with lessons I've learned from it in regards to WinJS development.

More to Come 

There's obviously a lot more to be said about Pointer Events and gestures. I plan to get more into detail, especially breaking down the CrossSlide with examples (which will lean heavily on another barely documented item in WinJS... Gesture Recognizer).