define([ "dojo/keys", // keys.ENTER keys.SPACE "dojo/mouse", "dojo/on", "dojo/touch" // touch support for click is now there ], function(keys, mouse, on, touch){ // module: // dijit/a11yclick /*===== return { // summary: // Custom press, release, and click synthetic events // which trigger on a left mouse click, touch, or space/enter keyup. click: function(node, listener){ // summary: // Logical click operation for mouse, touch, or keyboard (space/enter key) }, press: function(node, listener){ // summary: // Mousedown (left button), touchstart, or keydown (space or enter) corresponding to logical click operation. }, release: function(node, listener){ // summary: // Mouseup (left button), touchend, or keyup (space or enter) corresponding to logical click operation. }, move: function(node, listener){ // summary: // Mouse cursor or a finger is dragged over the given node. } }; =====*/ function clickKey(/*Event*/ e){ // Test if this keyboard event should be tracked as the start (if keydown) or end (if keyup) of a click event. // Only track for nodes marked to be tracked, and not for buttons or inputs, // since buttons handle keyboard click natively, and text inputs should not // prevent typing spaces or newlines. if((e.keyCode === keys.ENTER || e.keyCode === keys.SPACE) && !/input|button|textarea/i.test(e.target.nodeName)){ // Test if a node or its ancestor has been marked with the dojoClick property to indicate special processing for(var node = e.target; node; node = node.parentNode){ if(node.dojoClick){ return true; } } } } var lastKeyDownNode; on(document, "keydown", function(e){ //console.log("a11yclick: onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode)); if(clickKey(e)){ // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work lastKeyDownNode = e.target; // Prevent viewport scrolling on space key in IE<9. // (Reproducible on test_Button.html on any of the first dijit/form/Button examples) e.preventDefault(); }else{ lastKeyDownNode = null; } }); on(document, "keyup", function(e){ //console.log("a11yclick: onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode)); if(clickKey(e) && e.target == lastKeyDownNode){ // === breaks greasemonkey //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert lastKeyDownNode = null; on.emit(e.target, "click", { cancelable: true, bubbles: true, ctrlKey: e.ctrlKey, shiftKey: e.shiftKey, metaKey: e.metaKey, altKey: e.altKey, _origType: e.type }); } }); // I want to return a hash of the synthetic events, but for backwards compatibility the main return value // needs to be the click event. Change for 2.0. var click = function(node, listener){ // Set flag on node so that keydown/keyup above emits click event node.dojoClick = true; return on(node, "click", listener); }; click.click = click; // forward compatibility with 2.0 click.press = function(node, listener){ var touchListener = on(node, touch.press, function(evt){ if(evt.type == "mousedown" && !mouse.isLeft(evt)){ // Ignore right click return; } listener(evt); }), keyListener = on(node, "keydown", function(evt){ if(evt.keyCode === keys.ENTER || evt.keyCode === keys.SPACE){ listener(evt); } }); return { remove: function(){ touchListener.remove(); keyListener.remove(); } }; }; click.release = function(node, listener){ var touchListener = on(node, touch.release, function(evt){ if(evt.type == "mouseup" && !mouse.isLeft(evt)){ // Ignore right click return; } listener(evt); }), keyListener = on(node, "keyup", function(evt){ if(evt.keyCode === keys.ENTER || evt.keyCode === keys.SPACE){ listener(evt); } }); return { remove: function(){ touchListener.remove(); keyListener.remove(); } }; }; click.move = touch.move; // just for convenience return click; });