A HTML5 Browser maze, oninput support
While I was working on version 3 of Kommonwealth I got back to a part of our interface which makes use of live input events (ie: Events that fire as you type into the input) to offer a preview before the onchange event is used to actually change the data by sending an ajax post to the server.
For those who haven't heard of the oninput event, it's part of the html5 spec. You know those older ui parts such as autocomplete features and whatnot. The normal way of making these work is to manually subscribe to keydown and keyup events, and sometimes even use a timer for long inputs. Why? Because onchange only fires after you blur the input (that is what it is speced for and meant to do) and there was no event that would fire while typing was being done, so the only easy way to do it was to subscribe to keyboard events. Of course this method only applied to text inputs. The oninput event is basically an event in html5 which takes care of it. It works similarly to onchange, but instead of firing on blur it fires while you're typing into the input. This has an extra benefit in compliant browsers that like onchange it is only supposed to fire when the data has actually changed (ie: typing asdf then pasting asdf to replace it shouldn't fire).
Well of course this would be like all other html5 features incomplete browser support, the html5 spec doesn't list browser support in any browser. But that's where user code comes into play. We create code to support it manually in browsers that don't support it, and allow browsers that do support it to take over and handle it natively.
So like with other html5 features I started writing some jQuery code to support the oninput event in browsers that didn't support it so that browsers that took up support would support it natively, and browsers without support would fallback to the user code support. After awhile of working on it I noticed something very strange. After some fiddling I decided to try disabling my code... oninput didn't stop working, what? So I did some actual tests and realised that while the html5 spec didn't list browser support for oninput, Firefox actually already supported oninput natively.
One problem now, event detection. jQuery refers to a very good blog post (this one) explaining how to detect events. Problem... it doesn't work for oninput in Firefox. After some fiddling arround and a tip from Diego Perini in the comments on that blog post I finally have a full fledged support test for oninput support.
- Test A: Check for "oninput" on an input
- Test B: Use setAttribute on an input to set an oninput and check to see if node.oninput is a function
- Test C: Use the w3 event api to create an input and fake a keypress to see if oninput fires
I created a test page to test for browser support and with some help from joeyaa, Deltaneos, and PanSola in #wikia got some browser support tests for a number of browsers.
- Firefox 2 through 3.5 has support for oninput, Only test method C works to detect support.
- Chrome supports oninput. Test method A works to detect support.
- Opera 10 supports oninput and additionally onforminput, however it violates spec by firing an additional oninput when the onchange event is fired when the value is the same as the last user input (ie: if you type asdf you get events for "a", "as", "asd", "adsf", and an unwanted extra event for "asdf" when you blur the input). Test method A works to detect support.
- IE7 and IE8 don't support oninput. It's unknown if IE9 does. (Update 2011-05-11: Going by comments on Zoltan Hawryluk's post linked to in the comments IE9 does support oninput)
- Safari on the iPhone supports oninput, however it doesn't bubble like it is supposed to. Test method A works, so a proper test will need to also test on a div instead of just an input to see if oninput bubbles.
- Update 2011-05-11: The built-in Android browser and Dolphin HD browser both supports oninput, it does bubble, however it seams to fire oninput events twice for each change. Test method A works. The Dolphin HD browser works the same.
- Update 2011-05-11: The Firefox for Android browser seams to support oninput, a little oddly though; It bubbles fine. The word completion feature in the keyboard seams to hold back oninput events, while that feature is running oninput events are not fired until the word is fully entered. Like the other two Android browsers Firefox also seams to fire oninput events twice. Test method B works on Firefox for Android.
So far every browser I tested doesn't use an input delay, every one of them fires on each key input.
So this is an interesting table. oninput works in Gecko, WebKit, and Presto (Opera). And Opera additionally supports onforminput. And for any other browser we can emulate support using a library and other existing events. The only bug we have to deal with is iPhone's non bubbling which theoretically could be fixed by listening for input events the same way we fake focusin by listening for capturing "input" events rather than bubbling "input" events and then firing an input that bubbles ourselves. Opera 10 is a little annoying with it's non-spec extra oninput event, however that's not really a big issue since oninput is really more of a preview thing, it's not that bad if a preview fires a little too often. And if it's really a problem there is probably some way to use a capturing event to cancel any event that is fired when the input value is the same as the last time the event was fired.
^_^ The only problem here, is that IE doesn't work in Kommonwealth's editor anyway because of issues with IE. So implementing oninput support with user code has just dropped off my priority list since every browser we are supporting appears to have full oninput support already natively built in.