1 | define([ |
---|
2 | "dojo/_base/lang", |
---|
3 | "dojo/query", |
---|
4 | "dojo/_base/NodeList", // for this.connect() |
---|
5 | "dojo/NodeList-traverse" |
---|
6 | ], function(lang, query) { |
---|
7 | |
---|
8 | // module: |
---|
9 | // dojox/NodeList/delegate |
---|
10 | |
---|
11 | var NodeList = query.NodeList; |
---|
12 | |
---|
13 | lang.extend(NodeList, { |
---|
14 | delegate: function(/*String*/ selector, /*String*/ eventName, /*Function*/ fn){ |
---|
15 | // summary: |
---|
16 | // Monitor nodes in this NodeList for [bubbled] events on nodes that match selector. |
---|
17 | // Calls fn(evt) for those events, where (inside of fn()), this == the node |
---|
18 | // that matches the selector. |
---|
19 | // description: |
---|
20 | // Sets up event handlers that can catch events on any subnodes matching a given selector, |
---|
21 | // including nodes created after delegate() has been called. |
---|
22 | // |
---|
23 | // This allows an app to setup a single event handler on a high level node, rather than many |
---|
24 | // event handlers on subnodes. For example, one onclick handler for a Tree widget, rather than separate |
---|
25 | // handlers for each node in the tree. |
---|
26 | // Since setting up many event handlers is expensive, this can increase performance. |
---|
27 | // |
---|
28 | // Note that delegate() will not work for events that don't bubble, like focus. |
---|
29 | // onmouseenter/onmouseleave also don't currently work. |
---|
30 | // selector: |
---|
31 | // CSS selector valid to `dojo.query`, like ".foo" or "div > span". The |
---|
32 | // selector is relative to the nodes in this NodeList, not the document root. |
---|
33 | // For example myNodeList.delegate("> a", "onclick", ...) will catch events on |
---|
34 | // anchor nodes which are (immediate) children of the nodes in myNodeList. |
---|
35 | // eventName: |
---|
36 | // Standard event name used as an argument to `dojo.connect`, like "onclick". |
---|
37 | // fn: |
---|
38 | // Callback function passed the event object, and where this == the node that matches the selector. |
---|
39 | // That means that for example, after setting up a handler via |
---|
40 | // | dojo.query("body").delegate("fieldset", "onclick", ...) |
---|
41 | // clicking on a fieldset or *any nodes inside of a fieldset* will be reported |
---|
42 | // as a click on the fieldset itself. |
---|
43 | // example: |
---|
44 | // | dojo.query("navbar").delegate("a", "onclick", function(evt){ |
---|
45 | // | console.log("user clicked anchor ", this.node); |
---|
46 | // | }); |
---|
47 | |
---|
48 | // Possible future tasks: |
---|
49 | // - change signature of callback to be fn(node, evt), and then have scope argument |
---|
50 | // to delegate(selector, eventName, scope, fn)? |
---|
51 | // - support non-bubbling events like focus |
---|
52 | // - support onmouseenter/onmouseleave |
---|
53 | // - maybe should return an array of connect handles instead, to allow undelegate()? |
---|
54 | // - single node version |
---|
55 | |
---|
56 | return this.connect(eventName, function(evt){ |
---|
57 | var closest = query(evt.target).closest(selector, this); |
---|
58 | if(closest.length){ |
---|
59 | fn.call(closest[0], evt); |
---|
60 | } |
---|
61 | }); //dojo/NodeList |
---|
62 | } |
---|
63 | }); |
---|
64 | |
---|
65 | return NodeList; |
---|
66 | }); |
---|