[483] | 1 | define([ |
---|
| 2 | "dojo/keys", // keys.ENTER keys.SPACE |
---|
| 3 | "dojo/mouse", |
---|
| 4 | "dojo/on", |
---|
| 5 | "dojo/touch" // touch support for click is now there |
---|
| 6 | ], function(keys, mouse, on, touch){ |
---|
| 7 | |
---|
| 8 | // module: |
---|
| 9 | // dijit/a11yclick |
---|
| 10 | |
---|
| 11 | /*===== |
---|
| 12 | return { |
---|
| 13 | // summary: |
---|
| 14 | // Custom press, release, and click synthetic events |
---|
| 15 | // which trigger on a left mouse click, touch, or space/enter keyup. |
---|
| 16 | |
---|
| 17 | click: function(node, listener){ |
---|
| 18 | // summary: |
---|
| 19 | // Logical click operation for mouse, touch, or keyboard (space/enter key) |
---|
| 20 | }, |
---|
| 21 | press: function(node, listener){ |
---|
| 22 | // summary: |
---|
| 23 | // Mousedown (left button), touchstart, or keydown (space or enter) corresponding to logical click operation. |
---|
| 24 | }, |
---|
| 25 | release: function(node, listener){ |
---|
| 26 | // summary: |
---|
| 27 | // Mouseup (left button), touchend, or keyup (space or enter) corresponding to logical click operation. |
---|
| 28 | }, |
---|
| 29 | move: function(node, listener){ |
---|
| 30 | // summary: |
---|
| 31 | // Mouse cursor or a finger is dragged over the given node. |
---|
| 32 | } |
---|
| 33 | }; |
---|
| 34 | =====*/ |
---|
| 35 | |
---|
| 36 | function clickKey(/*Event*/ e){ |
---|
| 37 | // Test if this keyboard event should be tracked as the start (if keydown) or end (if keyup) of a click event. |
---|
| 38 | // Only track for nodes marked to be tracked, and not for buttons or inputs, |
---|
| 39 | // since buttons handle keyboard click natively, and text inputs should not |
---|
| 40 | // prevent typing spaces or newlines. |
---|
| 41 | if((e.keyCode === keys.ENTER || e.keyCode === keys.SPACE) && !/input|button|textarea/i.test(e.target.nodeName)){ |
---|
| 42 | |
---|
| 43 | // Test if a node or its ancestor has been marked with the dojoClick property to indicate special processing |
---|
| 44 | for(var node = e.target; node; node = node.parentNode){ |
---|
| 45 | if(node.dojoClick){ return true; } |
---|
| 46 | } |
---|
| 47 | } |
---|
| 48 | } |
---|
| 49 | |
---|
| 50 | var lastKeyDownNode; |
---|
| 51 | |
---|
| 52 | on(document, "keydown", function(e){ |
---|
| 53 | //console.log("a11yclick: onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode)); |
---|
| 54 | if(clickKey(e)){ |
---|
| 55 | // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work |
---|
| 56 | lastKeyDownNode = e.target; |
---|
| 57 | |
---|
| 58 | // Prevent viewport scrolling on space key in IE<9. |
---|
| 59 | // (Reproducible on test_Button.html on any of the first dijit/form/Button examples) |
---|
| 60 | e.preventDefault(); |
---|
| 61 | }else{ |
---|
| 62 | lastKeyDownNode = null; |
---|
| 63 | } |
---|
| 64 | }); |
---|
| 65 | |
---|
| 66 | on(document, "keyup", function(e){ |
---|
| 67 | //console.log("a11yclick: onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode)); |
---|
| 68 | if(clickKey(e) && e.target == lastKeyDownNode){ // === breaks greasemonkey |
---|
| 69 | //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert |
---|
| 70 | lastKeyDownNode = null; |
---|
| 71 | |
---|
| 72 | on.emit(e.target, "click", { |
---|
| 73 | cancelable: true, |
---|
| 74 | bubbles: true, |
---|
| 75 | ctrlKey: e.ctrlKey, |
---|
| 76 | shiftKey: e.shiftKey, |
---|
| 77 | metaKey: e.metaKey, |
---|
| 78 | altKey: e.altKey, |
---|
| 79 | _origType: e.type |
---|
| 80 | }); |
---|
| 81 | } |
---|
| 82 | }); |
---|
| 83 | |
---|
| 84 | // I want to return a hash of the synthetic events, but for backwards compatibility the main return value |
---|
| 85 | // needs to be the click event. Change for 2.0. |
---|
| 86 | |
---|
| 87 | var click = function(node, listener){ |
---|
| 88 | // Set flag on node so that keydown/keyup above emits click event |
---|
| 89 | node.dojoClick = true; |
---|
| 90 | |
---|
| 91 | return on(node, "click", listener); |
---|
| 92 | }; |
---|
| 93 | click.click = click; // forward compatibility with 2.0 |
---|
| 94 | |
---|
| 95 | click.press = function(node, listener){ |
---|
| 96 | var touchListener = on(node, touch.press, function(evt){ |
---|
| 97 | if(evt.type == "mousedown" && !mouse.isLeft(evt)){ |
---|
| 98 | // Ignore right click |
---|
| 99 | return; |
---|
| 100 | } |
---|
| 101 | listener(evt); |
---|
| 102 | }), keyListener = on(node, "keydown", function(evt){ |
---|
| 103 | if(evt.keyCode === keys.ENTER || evt.keyCode === keys.SPACE){ |
---|
| 104 | listener(evt); |
---|
| 105 | } |
---|
| 106 | }); |
---|
| 107 | return { |
---|
| 108 | remove: function(){ |
---|
| 109 | touchListener.remove(); |
---|
| 110 | keyListener.remove(); |
---|
| 111 | } |
---|
| 112 | }; |
---|
| 113 | }; |
---|
| 114 | |
---|
| 115 | click.release = function(node, listener){ |
---|
| 116 | var touchListener = on(node, touch.release, function(evt){ |
---|
| 117 | if(evt.type == "mouseup" && !mouse.isLeft(evt)){ |
---|
| 118 | // Ignore right click |
---|
| 119 | return; |
---|
| 120 | } |
---|
| 121 | listener(evt); |
---|
| 122 | }), keyListener = on(node, "keyup", function(evt){ |
---|
| 123 | if(evt.keyCode === keys.ENTER || evt.keyCode === keys.SPACE){ |
---|
| 124 | listener(evt); |
---|
| 125 | } |
---|
| 126 | }); |
---|
| 127 | return { |
---|
| 128 | remove: function(){ |
---|
| 129 | touchListener.remove(); |
---|
| 130 | keyListener.remove(); |
---|
| 131 | } |
---|
| 132 | }; |
---|
| 133 | }; |
---|
| 134 | |
---|
| 135 | click.move = touch.move; // just for convenience |
---|
| 136 | |
---|
| 137 | return click; |
---|
| 138 | }); |
---|