event.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojo._base.event"] = true;
  8. dojo.provide("dojo._base.event");
  9. dojo.require("dojo._base.connect");
  10. // this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
  11. (function(){
  12. // DOM event listener machinery
  13. var del = (dojo._event_listener = {
  14. add: function(/*DOMNode*/ node, /*String*/ name, /*Function*/ fp){
  15. if(!node){return;}
  16. name = del._normalizeEventName(name);
  17. fp = del._fixCallback(name, fp);
  18. if(
  19. !dojo.isIE &&
  20. (name == "mouseenter" || name == "mouseleave")
  21. ){
  22. var ofp = fp;
  23. name = (name == "mouseenter") ? "mouseover" : "mouseout";
  24. fp = function(e){
  25. if(!dojo.isDescendant(e.relatedTarget, node)){
  26. // e.type = oname; // FIXME: doesn't take? SJM: event.type is generally immutable.
  27. return ofp.call(this, e);
  28. }
  29. }
  30. }
  31. node.addEventListener(name, fp, false);
  32. return fp; /*Handle*/
  33. },
  34. remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){
  35. // summary:
  36. // clobbers the listener from the node
  37. // node:
  38. // DOM node to attach the event to
  39. // event:
  40. // the name of the handler to remove the function from
  41. // handle:
  42. // the handle returned from add
  43. if(node){
  44. event = del._normalizeEventName(event);
  45. if(!dojo.isIE && (event == "mouseenter" || event == "mouseleave")){
  46. event = (event == "mouseenter") ? "mouseover" : "mouseout";
  47. }
  48. node.removeEventListener(event, handle, false);
  49. }
  50. },
  51. _normalizeEventName: function(/*String*/ name){
  52. // Generally, name should be lower case, unless it is special
  53. // somehow (e.g. a Mozilla DOM event).
  54. // Remove 'on'.
  55. return name.slice(0,2) =="on" ? name.slice(2) : name;
  56. },
  57. _fixCallback: function(/*String*/ name, fp){
  58. // By default, we only invoke _fixEvent for 'keypress'
  59. // If code is added to _fixEvent for other events, we have
  60. // to revisit this optimization.
  61. // This also applies to _fixEvent overrides for Safari and Opera
  62. // below.
  63. return name != "keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); };
  64. },
  65. _fixEvent: function(evt, sender){
  66. // _fixCallback only attaches us to keypress.
  67. // Switch on evt.type anyway because we might
  68. // be called directly from dojo.fixEvent.
  69. switch(evt.type){
  70. case "keypress":
  71. del._setKeyChar(evt);
  72. break;
  73. }
  74. return evt;
  75. },
  76. _setKeyChar: function(evt){
  77. evt.keyChar = evt.charCode >= 32 ? String.fromCharCode(evt.charCode) : '';
  78. evt.charOrCode = evt.keyChar || evt.keyCode;
  79. },
  80. // For IE and Safari: some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE
  81. // we map those virtual key codes to ascii here
  82. // not valid for all (non-US) keyboards, so maybe we shouldn't bother
  83. _punctMap: {
  84. 106:42,
  85. 111:47,
  86. 186:59,
  87. 187:43,
  88. 188:44,
  89. 189:45,
  90. 190:46,
  91. 191:47,
  92. 192:96,
  93. 219:91,
  94. 220:92,
  95. 221:93,
  96. 222:39
  97. }
  98. });
  99. // DOM events
  100. dojo.fixEvent = function(/*Event*/ evt, /*DOMNode*/ sender){
  101. // summary:
  102. // normalizes properties on the event object including event
  103. // bubbling methods, keystroke normalization, and x/y positions
  104. // evt: Event
  105. // native event object
  106. // sender: DOMNode
  107. // node to treat as "currentTarget"
  108. return del._fixEvent(evt, sender);
  109. };
  110. dojo.stopEvent = function(/*Event*/ evt){
  111. // summary:
  112. // prevents propagation and clobbers the default action of the
  113. // passed event
  114. // evt: Event
  115. // The event object. If omitted, window.event is used on IE.
  116. evt.preventDefault();
  117. evt.stopPropagation();
  118. // NOTE: below, this method is overridden for IE
  119. };
  120. // the default listener to use on dontFix nodes, overriden for IE
  121. var node_listener = dojo._listener;
  122. // Unify connect and event listeners
  123. dojo._connect = function(obj, event, context, method, dontFix){
  124. // FIXME: need a more strict test
  125. var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener);
  126. // choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node
  127. // we need the third option to provide leak prevention on broken browsers (IE)
  128. var lid = isNode ? (dontFix ? 2 : 1) : 0, l = [dojo._listener, del, node_listener][lid];
  129. // create a listener
  130. var h = l.add(obj, event, dojo.hitch(context, method));
  131. // formerly, the disconnect package contained "l" directly, but if client code
  132. // leaks the disconnect package (by connecting it to a node), referencing "l"
  133. // compounds the problem.
  134. // instead we return a listener id, which requires custom _disconnect below.
  135. // return disconnect package
  136. return [ obj, event, h, lid ];
  137. };
  138. dojo._disconnect = function(obj, event, handle, listener){
  139. ([dojo._listener, del, node_listener][listener]).remove(obj, event, handle);
  140. };
  141. // Constants
  142. // Public: client code should test
  143. // keyCode against these named constants, as the
  144. // actual codes can vary by browser.
  145. dojo.keys = {
  146. // summary:
  147. // Definitions for common key values
  148. BACKSPACE: 8,
  149. TAB: 9,
  150. CLEAR: 12,
  151. ENTER: 13,
  152. SHIFT: 16,
  153. CTRL: 17,
  154. ALT: 18,
  155. META: dojo.isSafari ? 91 : 224, // the apple key on macs
  156. PAUSE: 19,
  157. CAPS_LOCK: 20,
  158. ESCAPE: 27,
  159. SPACE: 32,
  160. PAGE_UP: 33,
  161. PAGE_DOWN: 34,
  162. END: 35,
  163. HOME: 36,
  164. LEFT_ARROW: 37,
  165. UP_ARROW: 38,
  166. RIGHT_ARROW: 39,
  167. DOWN_ARROW: 40,
  168. INSERT: 45,
  169. DELETE: 46,
  170. HELP: 47,
  171. LEFT_WINDOW: 91,
  172. RIGHT_WINDOW: 92,
  173. SELECT: 93,
  174. NUMPAD_0: 96,
  175. NUMPAD_1: 97,
  176. NUMPAD_2: 98,
  177. NUMPAD_3: 99,
  178. NUMPAD_4: 100,
  179. NUMPAD_5: 101,
  180. NUMPAD_6: 102,
  181. NUMPAD_7: 103,
  182. NUMPAD_8: 104,
  183. NUMPAD_9: 105,
  184. NUMPAD_MULTIPLY: 106,
  185. NUMPAD_PLUS: 107,
  186. NUMPAD_ENTER: 108,
  187. NUMPAD_MINUS: 109,
  188. NUMPAD_PERIOD: 110,
  189. NUMPAD_DIVIDE: 111,
  190. F1: 112,
  191. F2: 113,
  192. F3: 114,
  193. F4: 115,
  194. F5: 116,
  195. F6: 117,
  196. F7: 118,
  197. F8: 119,
  198. F9: 120,
  199. F10: 121,
  200. F11: 122,
  201. F12: 123,
  202. F13: 124,
  203. F14: 125,
  204. F15: 126,
  205. NUM_LOCK: 144,
  206. SCROLL_LOCK: 145,
  207. // virtual key mapping
  208. copyKey: dojo.isMac && !dojo.isAIR ? (dojo.isSafari ? 91 : 224 ) : 17
  209. };
  210. var evtCopyKey = dojo.isMac ? "metaKey" : "ctrlKey";
  211. dojo.isCopyKey = function(e){
  212. // summary:
  213. // Checks an event for the copy key (meta on Mac, and ctrl anywhere else)
  214. // e: Event
  215. // Event object to examine
  216. return e[evtCopyKey]; // Boolean
  217. };
  218. // Public: decoding mouse buttons from events
  219. /*=====
  220. dojo.mouseButtons = {
  221. // LEFT: Number
  222. // Numeric value of the left mouse button for the platform.
  223. LEFT: 0,
  224. // MIDDLE: Number
  225. // Numeric value of the middle mouse button for the platform.
  226. MIDDLE: 1,
  227. // RIGHT: Number
  228. // Numeric value of the right mouse button for the platform.
  229. RIGHT: 2,
  230. isButton: function(e, button){
  231. // summary:
  232. // Checks an event object for a pressed button
  233. // e: Event
  234. // Event object to examine
  235. // button: Number
  236. // The button value (example: dojo.mouseButton.LEFT)
  237. return e.button == button; // Boolean
  238. },
  239. isLeft: function(e){
  240. // summary:
  241. // Checks an event object for the pressed left button
  242. // e: Event
  243. // Event object to examine
  244. return e.button == 0; // Boolean
  245. },
  246. isMiddle: function(e){
  247. // summary:
  248. // Checks an event object for the pressed middle button
  249. // e: Event
  250. // Event object to examine
  251. return e.button == 1; // Boolean
  252. },
  253. isRight: function(e){
  254. // summary:
  255. // Checks an event object for the pressed right button
  256. // e: Event
  257. // Event object to examine
  258. return e.button == 2; // Boolean
  259. }
  260. };
  261. =====*/
  262. if(dojo.isIE < 9 || (dojo.isIE && dojo.isQuirks)){
  263. dojo.mouseButtons = {
  264. LEFT: 1,
  265. MIDDLE: 4,
  266. RIGHT: 2,
  267. // helper functions
  268. isButton: function(e, button){ return e.button & button; },
  269. isLeft: function(e){ return e.button & 1; },
  270. isMiddle: function(e){ return e.button & 4; },
  271. isRight: function(e){ return e.button & 2; }
  272. };
  273. }else{
  274. dojo.mouseButtons = {
  275. LEFT: 0,
  276. MIDDLE: 1,
  277. RIGHT: 2,
  278. // helper functions
  279. isButton: function(e, button){ return e.button == button; },
  280. isLeft: function(e){ return e.button == 0; },
  281. isMiddle: function(e){ return e.button == 1; },
  282. isRight: function(e){ return e.button == 2; }
  283. };
  284. }
  285. // IE event normalization
  286. if(dojo.isIE){
  287. var _trySetKeyCode = function(e, code){
  288. try{
  289. // squelch errors when keyCode is read-only
  290. // (e.g. if keyCode is ctrl or shift)
  291. return (e.keyCode = code);
  292. }catch(e){
  293. return 0;
  294. }
  295. };
  296. // by default, use the standard listener
  297. var iel = dojo._listener;
  298. var listenersName = (dojo._ieListenersName = "_" + dojo._scopeName + "_listeners");
  299. // dispatcher tracking property
  300. if(!dojo.config._allow_leaks){
  301. // custom listener that handles leak protection for DOM events
  302. node_listener = iel = dojo._ie_listener = {
  303. // support handler indirection: event handler functions are
  304. // referenced here. Event dispatchers hold only indices.
  305. handlers: [],
  306. // add a listener to an object
  307. add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
  308. source = source || dojo.global;
  309. var f = source[method];
  310. if(!f||!f[listenersName]){
  311. var d = dojo._getIeDispatcher();
  312. // original target function is special
  313. d.target = f && (ieh.push(f) - 1);
  314. // dispatcher holds a list of indices into handlers table
  315. d[listenersName] = [];
  316. // redirect source to dispatcher
  317. f = source[method] = d;
  318. }
  319. return f[listenersName].push(ieh.push(listener) - 1) ; /*Handle*/
  320. },
  321. // remove a listener from an object
  322. remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
  323. var f = (source||dojo.global)[method], l = f && f[listenersName];
  324. if(f && l && handle--){
  325. delete ieh[l[handle]];
  326. delete l[handle];
  327. }
  328. }
  329. };
  330. // alias used above
  331. var ieh = iel.handlers;
  332. }
  333. dojo.mixin(del, {
  334. add: function(/*DOMNode*/ node, /*String*/ event, /*Function*/ fp){
  335. if(!node){return;} // undefined
  336. event = del._normalizeEventName(event);
  337. if(event=="onkeypress"){
  338. // we need to listen to onkeydown to synthesize
  339. // keypress events that otherwise won't fire
  340. // on IE
  341. var kd = node.onkeydown;
  342. if(!kd || !kd[listenersName] || !kd._stealthKeydownHandle){
  343. var h = del.add(node, "onkeydown", del._stealthKeyDown);
  344. kd = node.onkeydown;
  345. kd._stealthKeydownHandle = h;
  346. kd._stealthKeydownRefs = 1;
  347. }else{
  348. kd._stealthKeydownRefs++;
  349. }
  350. }
  351. return iel.add(node, event, del._fixCallback(fp));
  352. },
  353. remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){
  354. event = del._normalizeEventName(event);
  355. iel.remove(node, event, handle);
  356. if(event=="onkeypress"){
  357. var kd = node.onkeydown;
  358. if(--kd._stealthKeydownRefs <= 0){
  359. iel.remove(node, "onkeydown", kd._stealthKeydownHandle);
  360. delete kd._stealthKeydownHandle;
  361. }
  362. }
  363. },
  364. _normalizeEventName: function(/*String*/ eventName){
  365. // Generally, eventName should be lower case, unless it is
  366. // special somehow (e.g. a Mozilla event)
  367. // ensure 'on'
  368. return eventName.slice(0,2) != "on" ? "on" + eventName : eventName;
  369. },
  370. _nop: function(){},
  371. _fixEvent: function(/*Event*/ evt, /*DOMNode*/ sender){
  372. // summary:
  373. // normalizes properties on the event object including event
  374. // bubbling methods, keystroke normalization, and x/y positions
  375. // evt:
  376. // native event object
  377. // sender:
  378. // node to treat as "currentTarget"
  379. if(!evt){
  380. var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window;
  381. evt = w.event;
  382. }
  383. if(!evt){return(evt);}
  384. evt.target = evt.srcElement;
  385. evt.currentTarget = (sender || evt.srcElement);
  386. evt.layerX = evt.offsetX;
  387. evt.layerY = evt.offsetY;
  388. // FIXME: scroll position query is duped from dojo.html to
  389. // avoid dependency on that entire module. Now that HTML is in
  390. // Base, we should convert back to something similar there.
  391. var se = evt.srcElement, doc = (se && se.ownerDocument) || document;
  392. // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used
  393. // here rather than document.body
  394. var docBody = ((dojo.isIE < 6) || (doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement;
  395. var offset = dojo._getIeDocumentElementOffset();
  396. evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;
  397. evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y;
  398. if(evt.type == "mouseover"){
  399. evt.relatedTarget = evt.fromElement;
  400. }
  401. if(evt.type == "mouseout"){
  402. evt.relatedTarget = evt.toElement;
  403. }
  404. if (dojo.isIE < 9 || dojo.isQuirks) {
  405. evt.stopPropagation = del._stopPropagation;
  406. evt.preventDefault = del._preventDefault;
  407. }
  408. return del._fixKeys(evt);
  409. },
  410. _fixKeys: function(evt){
  411. switch(evt.type){
  412. case "keypress":
  413. var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
  414. if (c==10){
  415. // CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
  416. c=0;
  417. evt.keyCode = 13;
  418. }else if(c==13||c==27){
  419. c=0; // Mozilla considers ENTER and ESC non-printable
  420. }else if(c==3){
  421. c=99; // Mozilla maps CTRL-BREAK to CTRL-c
  422. }
  423. // Mozilla sets keyCode to 0 when there is a charCode
  424. // but that stops the event on IE.
  425. evt.charCode = c;
  426. del._setKeyChar(evt);
  427. break;
  428. }
  429. return evt;
  430. },
  431. _stealthKeyDown: function(evt){
  432. // IE doesn't fire keypress for most non-printable characters.
  433. // other browsers do, we simulate it here.
  434. var kp = evt.currentTarget.onkeypress;
  435. // only works if kp exists and is a dispatcher
  436. if(!kp || !kp[listenersName]){ return; }
  437. // munge key/charCode
  438. var k=evt.keyCode;
  439. // These are Windows Virtual Key Codes
  440. // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
  441. var unprintable = (k!=13 || (dojo.isIE >= 9 && !dojo.isQuirks)) && k!=32 && k!=27 && (k<48||k>90) && (k<96||k>111) && (k<186||k>192) && (k<219||k>222);
  442. // synthesize keypress for most unprintables and CTRL-keys
  443. if(unprintable||evt.ctrlKey){
  444. var c = unprintable ? 0 : k;
  445. if(evt.ctrlKey){
  446. if(k==3 || k==13){
  447. return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
  448. }else if(c>95 && c<106){
  449. c -= 48; // map CTRL-[numpad 0-9] to ASCII
  450. }else if((!evt.shiftKey)&&(c>=65&&c<=90)){
  451. c += 32; // map CTRL-[A-Z] to lowercase
  452. }else{
  453. c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
  454. }
  455. }
  456. // simulate a keypress event
  457. var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
  458. kp.call(evt.currentTarget, faux);
  459. if(dojo.isIE < 9 || (dojo.isIE && dojo.isQuirks)){
  460. evt.cancelBubble = faux.cancelBubble;
  461. }
  462. evt.returnValue = faux.returnValue;
  463. _trySetKeyCode(evt, faux.keyCode);
  464. }
  465. },
  466. // Called in Event scope
  467. _stopPropagation: function(){
  468. this.cancelBubble = true;
  469. },
  470. _preventDefault: function(){
  471. // Setting keyCode to 0 is the only way to prevent certain keypresses (namely
  472. // ctrl-combinations that correspond to menu accelerator keys).
  473. // Otoh, it prevents upstream listeners from getting this information
  474. // Try to split the difference here by clobbering keyCode only for ctrl
  475. // combinations. If you still need to access the key upstream, bubbledKeyCode is
  476. // provided as a workaround.
  477. this.bubbledKeyCode = this.keyCode;
  478. if(this.ctrlKey){_trySetKeyCode(this, 0);}
  479. this.returnValue = false;
  480. }
  481. });
  482. // override stopEvent for IE
  483. dojo.stopEvent = (dojo.isIE < 9 || dojo.isQuirks) ? function(evt){
  484. evt = evt || window.event;
  485. del._stopPropagation.call(evt);
  486. del._preventDefault.call(evt);
  487. } : dojo.stopEvent;
  488. }
  489. del._synthesizeEvent = function(evt, props){
  490. var faux = dojo.mixin({}, evt, props);
  491. del._setKeyChar(faux);
  492. // FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault);
  493. // but it throws an error when preventDefault is invoked on Safari
  494. // does Event.preventDefault not support "apply" on Safari?
  495. faux.preventDefault = function(){ evt.preventDefault(); };
  496. faux.stopPropagation = function(){ evt.stopPropagation(); };
  497. return faux;
  498. };
  499. // Opera event normalization
  500. if(dojo.isOpera){
  501. dojo.mixin(del, {
  502. _fixEvent: function(evt, sender){
  503. switch(evt.type){
  504. case "keypress":
  505. var c = evt.which;
  506. if(c==3){
  507. c=99; // Mozilla maps CTRL-BREAK to CTRL-c
  508. }
  509. // can't trap some keys at all, like INSERT and DELETE
  510. // there is no differentiating info between DELETE and ".", or INSERT and "-"
  511. c = c<41 && !evt.shiftKey ? 0 : c;
  512. if(evt.ctrlKey && !evt.shiftKey && c>=65 && c<=90){
  513. // lowercase CTRL-[A-Z] keys
  514. c += 32;
  515. }
  516. return del._synthesizeEvent(evt, { charCode: c });
  517. }
  518. return evt;
  519. }
  520. });
  521. }
  522. // Webkit event normalization
  523. if(dojo.isWebKit){
  524. del._add = del.add;
  525. del._remove = del.remove;
  526. dojo.mixin(del, {
  527. add: function(/*DOMNode*/ node, /*String*/ event, /*Function*/ fp){
  528. if(!node){return;} // undefined
  529. var handle = del._add(node, event, fp);
  530. if(del._normalizeEventName(event) == "keypress"){
  531. // we need to listen to onkeydown to synthesize
  532. // keypress events that otherwise won't fire
  533. // in Safari 3.1+: https://lists.webkit.org/pipermail/webkit-dev/2007-December/002992.html
  534. handle._stealthKeyDownHandle = del._add(node, "keydown", function(evt){
  535. //A variation on the IE _stealthKeydown function
  536. //Synthesize an onkeypress event, but only for unprintable characters.
  537. var k=evt.keyCode;
  538. // These are Windows Virtual Key Codes
  539. // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
  540. var unprintable = k!=13 && k!=32 && (k<48 || k>90) && (k<96 || k>111) && (k<186 || k>192) && (k<219 || k>222);
  541. // synthesize keypress for most unprintables and CTRL-keys
  542. if(unprintable || evt.ctrlKey){
  543. var c = unprintable ? 0 : k;
  544. if(evt.ctrlKey){
  545. if(k==3 || k==13){
  546. return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
  547. }else if(c>95 && c<106){
  548. c -= 48; // map CTRL-[numpad 0-9] to ASCII
  549. }else if(!evt.shiftKey && c>=65 && c<=90){
  550. c += 32; // map CTRL-[A-Z] to lowercase
  551. }else{
  552. c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
  553. }
  554. }
  555. // simulate a keypress event
  556. var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
  557. fp.call(evt.currentTarget, faux);
  558. }
  559. });
  560. }
  561. return handle; /*Handle*/
  562. },
  563. remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){
  564. if(node){
  565. if(handle._stealthKeyDownHandle){
  566. del._remove(node, "keydown", handle._stealthKeyDownHandle);
  567. }
  568. del._remove(node, event, handle);
  569. }
  570. },
  571. _fixEvent: function(evt, sender){
  572. switch(evt.type){
  573. case "keypress":
  574. if(evt.faux){ return evt; }
  575. var c = evt.charCode;
  576. c = c>=32 ? c : 0;
  577. return del._synthesizeEvent(evt, {charCode: c, faux: true});
  578. }
  579. return evt;
  580. }
  581. });
  582. }
  583. })();
  584. if(dojo.isIE){
  585. // keep this out of the closure
  586. // closing over 'iel' or 'ieh' b0rks leak prevention
  587. // ls[i] is an index into the master handler array
  588. dojo._ieDispatcher = function(args, sender){
  589. var ap = Array.prototype,
  590. h = dojo._ie_listener.handlers,
  591. c = args.callee,
  592. ls = c[dojo._ieListenersName],
  593. t = h[c.target];
  594. // return value comes from original target function
  595. var r = t && t.apply(sender, args);
  596. // make local copy of listener array so it's immutable during processing
  597. var lls = [].concat(ls);
  598. // invoke listeners after target function
  599. for(var i in lls){
  600. var f = h[lls[i]];
  601. if(!(i in ap) && f){
  602. f.apply(sender, args);
  603. }
  604. }
  605. return r;
  606. };
  607. dojo._getIeDispatcher = function(){
  608. // ensure the returned function closes over nothing ("new Function" apparently doesn't close)
  609. return new Function(dojo._scopeName + "._ieDispatcher(arguments, this)"); // function
  610. };
  611. // keep this out of the closure to reduce RAM allocation
  612. dojo._event_listener._fixCallback = function(fp){
  613. var f = dojo._event_listener._fixEvent;
  614. return function(e){ return fp.call(this, f(e, this)); };
  615. };
  616. }
  617. }