source: Dev/branches/rest-dojo-ui/client/dijit/_OnDijitClickMixin.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 4.6 KB
Line 
1define([
2        "dojo/on",
3        "dojo/_base/array", // array.forEach
4        "dojo/keys", // keys.ENTER keys.SPACE
5        "dojo/_base/declare", // declare
6        "dojo/_base/sniff", // has("ie")
7        "dojo/_base/unload", // unload.addOnWindowUnload
8        "dojo/_base/window" // win.doc.addEventListener win.doc.attachEvent win.doc.detachEvent
9], function(on, array, keys, declare, has, unload, win){
10
11        // module:
12        //              dijit/_OnDijitClickMixin
13        // summary:
14        //              Mixin so you can pass "ondijitclick" to this.connect() method,
15        //              as a way to handle clicks by mouse, or by keyboard (SPACE/ENTER key)
16
17
18        // Keep track of where the last keydown event was, to help avoid generating
19        // spurious ondijitclick events when:
20        // 1. focus is on a <button> or <a>
21        // 2. user presses then releases the ENTER key
22        // 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
23        // 4. onkeyup event fires, causing the ondijitclick handler to fire
24        var lastKeyDownNode = null;
25        if(has("ie")){
26                (function(){
27                        var keydownCallback = function(evt){
28                                lastKeyDownNode = evt.srcElement;
29                        };
30                        win.doc.attachEvent('onkeydown', keydownCallback);
31                        unload.addOnWindowUnload(function(){
32                                win.doc.detachEvent('onkeydown', keydownCallback);
33                        });
34                })();
35        }else{
36                win.doc.addEventListener('keydown', function(evt){
37                        lastKeyDownNode = evt.target;
38                }, true);
39        }
40
41        // Custom a11yclick (a.k.a. ondijitclick) event
42        var a11yclick = function(node, listener){
43                if(/input|button/i.test(node.nodeName)){
44                        // pass through, the browser already generates click event on SPACE/ENTER key
45                        return on(node, "click", listener);
46                }else{
47                        // Don't fire the click event unless both the keydown and keyup occur on this node.
48                        // Avoids problems where focus shifted to this node or away from the node on keydown,
49                        // either causing this node to process a stray keyup event, or causing another node
50                        // to get a stray keyup event.
51
52                        function clickKey(/*Event*/ e){
53                                return (e.keyCode == keys.ENTER || e.keyCode == keys.SPACE) &&
54                                                !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey;
55                        }
56                        var handles = [
57                                on(node, "keypress", function(e){
58                                        //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
59                                        if(clickKey(e)){
60                                                // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
61                                                lastKeyDownNode = e.target;
62
63                                                // Prevent viewport scrolling on space key in IE<9.
64                                                // (Reproducible on test_Button.html on any of the first dijit.form.Button examples)
65                                                // Do this onkeypress rather than onkeydown because onkeydown.preventDefault() will
66                                                // suppress the onkeypress event, breaking _HasDropDown
67                                                e.preventDefault();
68                                        }
69                                }),
70
71                                on(node, "keyup", function(e){
72                                        //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
73                                        if(clickKey(e) && e.target == lastKeyDownNode){ // === breaks greasemonkey
74                                                //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
75                                                lastKeyDownNode = null;
76                                                listener.call(this, e);
77                                        }
78                                }),
79
80                                on(node, "click", function(e){
81                                        // and connect for mouse clicks too (or touch-clicks on mobile)
82                                        listener.call(this, e);
83                                })
84                        ];
85
86                        return {
87                                remove: function(){
88                                        array.forEach(handles, function(h){ h.remove(); });
89                                }
90                        };
91                }
92        };
93
94        return declare("dijit._OnDijitClickMixin", null, {
95                connect: function(
96                                /*Object|null*/ obj,
97                                /*String|Function*/ event,
98                                /*String|Function*/ method){
99                        // summary:
100                        //              Connects specified obj/event to specified method of this object
101                        //              and registers for disconnect() on widget destroy.
102                        // description:
103                        //              Provide widget-specific analog to connect.connect, except with the
104                        //              implicit use of this widget as the target object.
105                        //              This version of connect also provides a special "ondijitclick"
106                        //              event which triggers on a click or space or enter keyup.
107                        //              Events connected with `this.connect` are disconnected upon
108                        //              destruction.
109                        // returns:
110                        //              A handle that can be passed to `disconnect` in order to disconnect before
111                        //              the widget is destroyed.
112                        // example:
113                        //      |       var btn = new dijit.form.Button();
114                        //      |       // when foo.bar() is called, call the listener we're going to
115                        //      |       // provide in the scope of btn
116                        //      |       btn.connect(foo, "bar", function(){
117                        //      |               console.debug(this.toString());
118                        //      |       });
119                        // tags:
120                        //              protected
121
122                        return this.inherited(arguments, [obj, event == "ondijitclick" ? a11yclick : event, method]);
123                }
124        });
125});
Note: See TracBrowser for help on using the repository browser.