summaryrefslogtreecommitdiff
path: root/lib/dijit/a11yclick.js.uncompressed.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/a11yclick.js.uncompressed.js')
-rw-r--r--lib/dijit/a11yclick.js.uncompressed.js131
1 files changed, 131 insertions, 0 deletions
diff --git a/lib/dijit/a11yclick.js.uncompressed.js b/lib/dijit/a11yclick.js.uncompressed.js
new file mode 100644
index 000000000..ed92308dd
--- /dev/null
+++ b/lib/dijit/a11yclick.js.uncompressed.js
@@ -0,0 +1,131 @@
+define("dijit/a11yclick", [
+ "dojo/on",
+ "dojo/_base/array", // array.forEach
+ "dojo/keys", // keys.ENTER keys.SPACE
+ "dojo/_base/declare", // declare
+ "dojo/has", // has("dom-addeventlistener")
+ "dojo/_base/unload", // unload.addOnWindowUnload
+ "dojo/_base/window" // win.doc.addEventListener win.doc.attachEvent win.doc.detachEvent
+], function(on, array, keys, declare, has, unload, win){
+
+ // module:
+ // dijit/a11yclick
+
+ // Keep track of where the last keydown event was, to help avoid generating
+ // spurious ondijitclick events when:
+ // 1. focus is on a <button> or <a>
+ // 2. user presses then releases the ENTER key
+ // 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
+ // 4. onkeyup event fires, causing the ondijitclick handler to fire
+ var lastKeyDownNode = null;
+ if(has("dom-addeventlistener")){
+ win.doc.addEventListener('keydown', function(evt){
+ lastKeyDownNode = evt.target;
+ }, true);
+ }else{
+ // Fallback path for IE6-8
+ (function(){
+ var keydownCallback = function(evt){
+ lastKeyDownNode = evt.srcElement;
+ };
+ win.doc.attachEvent('onkeydown', keydownCallback);
+ unload.addOnWindowUnload(function(){
+ win.doc.detachEvent('onkeydown', keydownCallback);
+ });
+ })();
+ }
+
+ function clickKey(/*Event*/ e){
+ return (e.keyCode === keys.ENTER || e.keyCode === keys.SPACE) &&
+ !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey;
+ }
+
+ return function(node, listener){
+ // summary:
+ // Custom a11yclick (a.k.a. ondijitclick) event
+ // which triggers on a mouse click, touch, or space/enter keyup.
+
+ if(/input|button/i.test(node.nodeName)){
+ // pass through, the browser already generates click event on SPACE/ENTER key
+ return on(node, "click", listener);
+ }else{
+ // Don't fire the click event unless both the keydown and keyup occur on this node.
+ // Avoids problems where focus shifted to this node or away from the node on keydown,
+ // either causing this node to process a stray keyup event, or causing another node
+ // to get a stray keyup event.
+
+ var handles = [
+ on(node, "keydown", function(e){
+ //console.log(this.id + ": 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();
+ }
+ }),
+
+ on(node, "keyup", function(e){
+ //console.log(this.id + ": 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
+ });
+ }
+ }),
+
+ on(node, "click", function(e){
+ // catch mouse clicks, plus the on.emit() calls from above and below
+ listener.call(this, e);
+ })
+ ];
+
+ if(has("touch")){
+ // touchstart-->touchend will automatically generate a click event, but there are problems
+ // on iOS after focus has been programatically shifted (#14604, #14918), so setup a failsafe
+ // if click doesn't fire naturally.
+
+ var clickTimer;
+ handles.push(
+ on(node, "touchend", function(e){
+ var target = e.target;
+ clickTimer = setTimeout(function(){
+ clickTimer = null;
+ on.emit(target, "click", {
+ cancelable: true,
+ bubbles: true
+ });
+ }, 600);
+ }),
+ on(node, "click", function(e){
+ // If browser generates a click naturally, clear the timer to fire a synthetic click event
+ if(clickTimer){
+ clearTimeout(clickTimer);
+ }
+ })
+ // TODO: if the touchstart and touchend were <100ms apart, and then there's another touchstart
+ // event <300ms after the touchend event, then clear the synthetic click timer, because user
+ // is doing a zoom. Alternately monitor screen.deviceXDPI (or something similar) to see if
+ // zoom level has changed.
+ );
+ }
+
+ return {
+ remove: function(){
+ array.forEach(handles, function(h){ h.remove(); });
+ if(clickTimer){
+ clearTimeout(clickTimer);
+ clickTimer = null;
+ }
+ }
+ };
+ }
+ };
+
+ return ret;
+});