Monday, September 9, 2013

Dynamically Generated JavaScript from Dart


I'll admit that I am completely obsessed at this point.

I must figure out a way to test keyboard events in Dart. I must.

I was thwarted in my attempts to use JavaScript, via js-interop, to generate keyboard events with character data. It turns out that this really does not work in JavaScript—at least not with Chrome/WebKit. Most JavaScript libraries that do this wind up populating additional Event properties like which or use other event types to fake keyboard events. Since Dart is typed, these kinds of tricks won't work for me.

So it is time to try even dumber tricks.

Tonight's try will be to add listeners in JavaScript, where keyboard event malarky is acceptable. If successful, I will convert those listeners to streams in Dart.

The first question is, how do I create a function in JavaScript that can be used in Dart? I could add it via a <script> tag, but then anyone using my library would have to do the same. I would also have to deal with <script> load order issues. No thanks.

What about JavaScript's eval()? I would normally avoid that, but it might just do the trick. By way of proof of concept, I eval() a JavaScript function into life from Dart, and then call it from Dart as well:
    js.context.eval("function hi(name) {alert('hi ' + name)}");
    js.context.hi('bob');
And that just works!



From there, I can create a JavaScript function that will invoke a callback in Dart:
  static void createJsListener() {
    js.context.eval('''
function _dart_key_event_x(target_classname, cb) {
  //var target = document.getElementsByClassName(target_classname)[0];
  target = document;

  target.addEventListener("keydown", function(event) {
    console.log("js event " + event);
    cb(event);
  });
}''');
  }
And I can can get that JavaScript listener to invoke my Dart callback function:
    createJsListener();
    js.context.dartCallback = new js.Callback.many((event) {
      print('event! ${event}');
      _controller.add(new KeyEventX(event));
    });

    js.context._dart_key_event_x(temp_classname, js.context.dartCallback);
I am still not quite done. The event that is returned is a proxy to the JavaScript event object. I will need a little more malarky to convert that into a KeyEvent sub-class in Dart. But it does look like it will be possible. If I print the keyCode from that proxied object:
class KeyEventX implements KeyEvent {
  KeyboardEvent _parent;

  KeyEventX(KeyboardEvent parent) {
    _parent = parent;
    print('[KeyEventX] ${parent.keyCode}');
  }
  // ...
}
Then I see an actual keycode:
[KeyEventX] 65
I will pick back up tomorrow to see if I can finish this off. But, so far, the ability to generate JavaScript from Dart seems like it may be just what I need.


Day #869

No comments:

Post a Comment