1 Feb 07:17
widgets emitting DOM events
Bill Keese <bill <at> dojotoolkit.org>
2012-02-01 06:17:30 GMT
2012-02-01 06:17:30 GMT
I've started working on http://bugs.dojotoolkit.org/ticket/13785 and want to open it up for feedback.
As a test, I converted StackContainer and TabContainer to use the new API for monitoring changes to panes (like a changed title), and also monitoring clicks on tabs. The former was fairly straightforward, although for the latter it made me wonder what would be appropriate events from a TabButton to indicate (a) the button was clicked to select that pane or (b) the close button was clicked to delete that pane. I made them both WidgetClick events (with different attributes), but instead they could be a WidgetSelect event and a WidgetClose event, or something else. Any opinions on this? I guess it was a rather complicated example to start with, and it's not clear that the code is any better than before.
The basic idea is that an app can setup event handlers on a high level node, and get bubbled events from descendant widgets. So given DOM like
<form id=myForm>
<input data-dojo-type=dijit/form/NumberTextBox>
...
<button data-dojo-type=dijit/form/Button>click me</button>
...
</form>
The app can do:
on(dom.byId("myForm"), "WidgetAttrModified", function(evt){
console.log("widget " + evt.widget.id + " attribute " + evt.attrName + " set to " + evt.newValue);
});
on(dom.byId("myForm"), "WidgetClick", function(evt){
console.log("widget " + evt.widget.id + " was clicked ");
});
(BTW, theoretically you could also use on.selector() to only match a subset of the widgets inside of the <form>... especially if we added more attributes to widget DOMNodes such as the widget's declared class.)
Internally, widgets signal events by calling:
this.emit("Click", [arg1, arg2, arg3], eventObj)
which will:
a) call legacy onClick() method (but I think that goes away for 2.0)
b) execute any callbacks the app registered via _WidgetBase.on(type, callback) with signature callback(arg1, arg2, arg3)
c) call on.emit(this.domNode, "WidgetClick", eventObj) to propagate the event through the DOM
As a test, I converted StackContainer and TabContainer to use the new API for monitoring changes to panes (like a changed title), and also monitoring clicks on tabs. The former was fairly straightforward, although for the latter it made me wonder what would be appropriate events from a TabButton to indicate (a) the button was clicked to select that pane or (b) the close button was clicked to delete that pane. I made them both WidgetClick events (with different attributes), but instead they could be a WidgetSelect event and a WidgetClose event, or something else. Any opinions on this? I guess it was a rather complicated example to start with, and it's not clear that the code is any better than before.
Anyway, I think the basic concept is sound, although haven't tested performance etc. But it does raise some questions:
1) _WidgetBase.on() doesn't catch bubbled events
_WidgetBase.on() doesn't catch bubbled events, which probably makes sense given that on() methods of other classes don't even have a concept of bubbling. But OTOH it may confuse users who are expecting something like below to catch attribute changes on the descendant widgets:
<form data-dojo-type=dijit/form/Form>
<script type="dojo/on" data-dojo-event="WidgetAttrModified" data-dojo-args="evt">
console.log("widget " + evt.widget.id + " attribute " + evt.attrName + " set to " + evt.newValue);
</script>
<input data-dojo-type=dijit/form/NumberTextBox>
...
<button data-dojo-type=dijit/form/Button>click me</button>
...
</form>
(The code above will never execute.)
To put it another way, requiring users to think about DOMNodes directly is perhaps a little clunky.
2) same or different event names?
Currently I have it using different event names from DOMNodes, for example "WidgetClick" instead of "click", and "WidgetAttrModified" instead of "DOMAttrModified". That's to avoid infinite loops with (for example) a widget both listening for "click" events and firing them, and also to make it clear when propagated events are from widgets or from DOMNodes. Note that widgets let most DOM events naturally bubble, with the notable exception of click events.
But it's debatable.
3) which events get bubbled?
Some events like mousemove seem dangerous to bubble because of performance reasons
Other events like onChange() are already covered via WidgetAttrModified (evt.attrName == "value" or for checkboxes "checked")
So, what's a good list of events that widgets should emit?
4) id on focusNode
For accessibility reasons form widgets often set the id attribute on a descendant of this.domNode, rather than on this.domNode itself. That would confuse users doing a
on(dom.byId("myWidget"), "...", ...);
Perhaps the event should be fired from this.focusNode if defined, or otherwise from this.domNode.
_______________________________________________ dojo-contributors mailing list dojo-contributors <at> mail.dojotoolkit.org http://mail.dojotoolkit.org/mailman/listinfo/dojo-contributors
RSS Feed