Wednesday, August 14, 2013

IE Doesn't Key-Up Enter Keys


There are two more things that I would like from my ctrl_alt_foo keyboard library for Dart. First, I need the enter key to work properly in Internet Explorer. Second I would like for it to support basic keyboard shortcuts on OSX (e.g. ⌘+N instead of Ctrl+N). I think that the latter should be more straight forward, though I am not eager to boot in OSX to try it out. I remain unsure why the Enter key is being registered properly everywhere except Internet Explorer, so I start there.

I am using ctrl_alt_foo package throughout the ICE Code Editor. For input fields like the New Project Dialog, a typical pattern sees me using ctrl_alt_foo's KeyboardEventStreamX class to listen for Enter key events like the following:
    KeyboardEventStreamX.onKeyUp(dialog.query('input'))
      .listen((e) {
        if (e.isEnter) _create();
      });
This code snippet works in all browsers except Internet Explorer. Either the keyboard event stream is not properly established or the isEnter predicate method is not working. I suspect the latter since similar code that closes the dialog on Escape key events does work.

To understand what is happening, I add some good ole print STDERR debug statements:
    KeyboardEventStreamX.onKeyUp(dialog.query('input'))
      .listen((e) {
        print('[NewProjectDialog/onKeyUp] ${e.keyCode}');
        if (e.isEnter) _create();
        else print('[NewProjectDialog/onKeyUp] not Enter');
      });

    KeyboardEventStreamX.onKeyDown(dialog.query('input'))
      .listen((e) {
        print('[NewProjectDialog/onKeyDown] ${e.keyCode}');
        if (e.isEnter) print('[NewProjectDialog/onKeyDown] yes Enter');
        else print('[NewProjectDialog/onKeyDown] not Enter');
      });
For good measure, I have added similar event handling for on key down. I do not suspect a problem between key-up/key-down but since I have to compile to JavaScript to test this out, I err on the side of too much information.

Compiling takes around ten seconds with:
➜  public git:(ctrl-alt-foo) dart2js -ofull.dart.js full.dart
I ought to consider adding Guard or watch to autocompile, but it is still rare that I need to compile and even more rare that I need to auto-compile. I may consider pulling this back into ctrl_alt_foo, however.

Anyhow, the code is compiled and, when I hit Enter, I find:
[NewProjectDialog/onKeyDown] 13
[NewProjectDialog/onKeyDown] yes Enter 
Freaking Internet Explorer. Of course it was a key-up/key-down thing.

But is this Dart or is this Internet Explorer (10)? To answer that question, I create an IE-test page:
<body onload="console.log('load')">
<div>
<label>Name:<input id="foo" type="text" size="30"></label>
<button>Save</button>
</div>
</body>
<script>
var input = document.getElementById('foo');
input.addEventListener('keyup', function(){
  console.log('up');
});
input.addEventListener('keydown', function(){
  console.log('down');
});
</script>
I include an onload attribute on the BODY because I half suspect that the act of hitting Enter is submitting the (non-existent) form. This turns out not to be the case as the “load” message is only logged once.

After the pages loads, I type the letter “a” into the text element, which results in both a down and up console message. I check the active element and it remains the input field, now with a value of “a”. Then I hit Enter and only see a down event. Bother. Even more interesting is that the active element is the adjacent BUTTON element:



Sigh. The more things change…

I could whine all night, but I have a question at hand. What should I do with the following code to ensure that it works cross-browser?
    KeyboardEventStreamX.onKeyUp(dialog.query('input'))
      .listen((e) {
        if (e.isEnter) _create();
      });
On a more philosophical note, what should Dart do? Does it have a responsibility to normalize crazy browser implementations so that an Enter key will generate a key-up event? Is something like that even possible?

The last question, in my mind, is a pretty big “if.” Dart could add a onKeyPress listener and generate a subsequent Enter key-up event whenever it sees an Enter key. But that would substitute one poor browser behavior for another. Consider the case when an INPUT field is wrapped inside a FORM. Hitting Enter should submit that form, in which case a key-up event should not be generated. And how to handle onSubmit handlers that may or may not prevent form submission?

If there is no way to normalize that behavior, then what? Push this back on developers? Developers still need to know vagaries of various browser implementations? That's not the promise of Dart. Even if it normalizes 90% of browser strangeness, we would be left with the weirdest 10% edge cases. Does Dart then only support the lowest common denominator?

For my purposes, I am going to do just that. Until I can figure out a way to see key-up Enter events in Internet explorer, I will not support them in ctrl_alt_foo. For now, this means that I remove the onKeyUp stream from KeyboardEventStreamX and change all the calls in the ICE codebase. I may eventually drop onKeyUp in favor of just onKey if there proves to be no way of supporting this.

With that, I have keyboard shortcuts working in Chrome, Firefox (on Linux) and on Internet Explorer. All of my keyboard tests still pass in both ctrl_alt_foo and ICE (where the tests are as functional as possible in Dart). It is somewhat disappointing to drop onKeyUp from ctrl_alt_foo, of which all I can say is…

Thanks Internet Explorer, you're the reason we can't have nice things.

That's not at all constructive. In truth IE is making progress, so what I mean to say is how do I go about submitting a bug for Internet Explorer?


Day #843

No comments:

Post a Comment