Blame | Last modification | View Log | RSS feed
if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.dojo._hasResource["dojo._base.event"] = true;dojo.provide("dojo._base.event");dojo.require("dojo._base.connect");// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA(function(){// DOM event listener machineryvar del = dojo._event_listener = {add: function(/*DOMNode*/node, /*String*/name, /*Function*/fp){if(!node){return;}name = del._normalizeEventName(name);fp = del._fixCallback(name, fp);var oname = name;if((!dojo.isIE)&&((name == "mouseenter")||(name == "mouseleave"))){var oname = name;var ofp = fp;name = (name == "mouseenter") ? "mouseover" : "mouseout";fp = function(e){// thanks ben!var id = dojo.isDescendant(e.relatedTarget, node);if(id == false){// e.type = oname; // FIXME: doesn't take?return ofp.call(this, e);}}}node.addEventListener(name, fp, false);return fp; /*Handle*/},remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){// summary:// clobbers the listener from the node// node:// DOM node to attach the event to// event:// the name of the handler to remove the function from// handle:// the handle returned from add(node)&&(node.removeEventListener(del._normalizeEventName(event), handle, false));},_normalizeEventName: function(/*String*/name){// Generally, name should be lower case, unless it is special// somehow (e.g. a Mozilla DOM event).// Remove 'on'.return (name.slice(0,2)=="on" ? name.slice(2) : name);},_fixCallback: function(/*String*/name, fp){// By default, we only invoke _fixEvent for 'keypress'// If code is added to _fixEvent for other events, we have// to revisit this optimization.// This also applies to _fixEvent overrides for Safari and Opera// below.return (name!="keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); });},_fixEvent: function(evt, sender){// _fixCallback only attaches us to keypress.// Switch on evt.type anyway because we might// be called directly from dojo.fixEvent.switch(evt.type){case "keypress":del._setKeyChar(evt);break;}return evt;},_setKeyChar: function(evt){evt.keyChar = (evt.charCode ? String.fromCharCode(evt.charCode) : '');}};// DOM eventsdojo.fixEvent = function(/*Event*/evt, /*DOMNode*/sender){// summary:// normalizes properties on the event object including event// bubbling methods, keystroke normalization, and x/y positions// evt: Event// native event object// sender: DOMNode// node to treat as "currentTarget"return del._fixEvent(evt, sender);}dojo.stopEvent = function(/*Event*/evt){// summary:// prevents propagation and clobbers the default action of the// passed event// evt: Event// The event object. If omitted, window.event is used on IE.evt.preventDefault();evt.stopPropagation();// NOTE: below, this method is overridden for IE}// the default listener to use on dontFix nodes, overriden for IEvar node_listener = dojo._listener;// Unify connect and event listenersdojo._connect = function(obj, event, context, method, dontFix){// FIXME: need a more strict testvar isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener);// choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node// we need the third option to provide leak prevention on broken browsers (IE)var lid = !isNode ? 0 : (!dontFix ? 1 : 2), l = [dojo._listener, del, node_listener][lid];// create a listenervar h = l.add(obj, event, dojo.hitch(context, method));// formerly, the disconnect package contained "l" directly, but if client code// leaks the disconnect package (by connecting it to a node), referencing "l"// compounds the problem.// instead we return a listener id, which requires custom _disconnect below.// return disconnect packagereturn [ obj, event, h, lid ];}dojo._disconnect = function(obj, event, handle, listener){([dojo._listener, del, node_listener][listener]).remove(obj, event, handle);}// Constants// Public: client code should test// keyCode against these named constants, as the// actual codes can vary by browser.dojo.keys = {BACKSPACE: 8,TAB: 9,CLEAR: 12,ENTER: 13,SHIFT: 16,CTRL: 17,ALT: 18,PAUSE: 19,CAPS_LOCK: 20,ESCAPE: 27,SPACE: 32,PAGE_UP: 33,PAGE_DOWN: 34,END: 35,HOME: 36,LEFT_ARROW: 37,UP_ARROW: 38,RIGHT_ARROW: 39,DOWN_ARROW: 40,INSERT: 45,DELETE: 46,HELP: 47,LEFT_WINDOW: 91,RIGHT_WINDOW: 92,SELECT: 93,NUMPAD_0: 96,NUMPAD_1: 97,NUMPAD_2: 98,NUMPAD_3: 99,NUMPAD_4: 100,NUMPAD_5: 101,NUMPAD_6: 102,NUMPAD_7: 103,NUMPAD_8: 104,NUMPAD_9: 105,NUMPAD_MULTIPLY: 106,NUMPAD_PLUS: 107,NUMPAD_ENTER: 108,NUMPAD_MINUS: 109,NUMPAD_PERIOD: 110,NUMPAD_DIVIDE: 111,F1: 112,F2: 113,F3: 114,F4: 115,F5: 116,F6: 117,F7: 118,F8: 119,F9: 120,F10: 121,F11: 122,F12: 123,F13: 124,F14: 125,F15: 126,NUM_LOCK: 144,SCROLL_LOCK: 145};// IE event normalizationif(dojo.isIE){var _trySetKeyCode = function(e, code){try{// squelch errors when keyCode is read-only// (e.g. if keyCode is ctrl or shift)return (e.keyCode = code);}catch(e){return 0;}}// by default, use the standard listenervar iel = dojo._listener;// dispatcher tracking propertyif(!djConfig._allow_leaks){// custom listener that handles leak protection for DOM eventsnode_listener = iel = dojo._ie_listener = {// support handler indirection: event handler functions are// referenced here. Event dispatchers hold only indices.handlers: [],// add a listener to an objectadd: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){source = source || dojo.global;var f = source[method];if(!f||!f._listeners){var d = dojo._getIeDispatcher();// original target function is speciald.target = f && (ieh.push(f) - 1);// dispatcher holds a list of indices into handlers tabled._listeners = [];// redirect source to dispatcherf = source[method] = d;}return f._listeners.push(ieh.push(listener) - 1) ; /*Handle*/},// remove a listener from an objectremove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){var f = (source||dojo.global)[method], l = f&&f._listeners;if(f && l && handle--){delete ieh[l[handle]];delete l[handle];}}};// alias used abovevar ieh = iel.handlers;}dojo.mixin(del, {add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){if(!node){return;} // undefinedevent = del._normalizeEventName(event);if(event=="onkeypress"){// we need to listen to onkeydown to synthesize// keypress events that otherwise won't fire// on IEvar kd = node.onkeydown;if(!kd||!kd._listeners||!kd._stealthKeydown){// we simply ignore this connection when disconnecting// because it's side-effects are harmlessdel.add(node, "onkeydown", del._stealthKeyDown);// we only want one stealth listener per nodenode.onkeydown._stealthKeydown = true;}}return iel.add(node, event, del._fixCallback(fp));},remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){iel.remove(node, del._normalizeEventName(event), handle);},_normalizeEventName: function(/*String*/eventName){// Generally, eventName should be lower case, unless it is// special somehow (e.g. a Mozilla event)// ensure 'on'return (eventName.slice(0,2)!="on" ? "on"+eventName : eventName);},_nop: function(){},_fixEvent: function(/*Event*/evt, /*DOMNode*/sender){// summary:// normalizes properties on the event object including event// bubbling methods, keystroke normalization, and x/y positions// evt: native event object// sender: node to treat as "currentTarget"if(!evt){var w = (sender)&&((sender.ownerDocument || sender.document || sender).parentWindow)||window;evt = w.event;}if(!evt){return(evt);}evt.target = evt.srcElement;evt.currentTarget = (sender || evt.srcElement);evt.layerX = evt.offsetX;evt.layerY = evt.offsetY;// FIXME: scroll position query is duped from dojo.html to// avoid dependency on that entire module. Now that HTML is in// Base, we should convert back to something similar there.var se = evt.srcElement, doc = (se && se.ownerDocument) || document;// DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used// here rather than document.bodyvar docBody = ((dojo.isIE<6)||(doc["compatMode"]=="BackCompat")) ? doc.body : doc.documentElement;var offset = dojo._getIeDocumentElementOffset();evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y;if(evt.type == "mouseover"){evt.relatedTarget = evt.fromElement;}if(evt.type == "mouseout"){evt.relatedTarget = evt.toElement;}evt.stopPropagation = del._stopPropagation;evt.preventDefault = del._preventDefault;return del._fixKeys(evt);},_fixKeys: function(evt){switch(evt.type){case "keypress":var c = ("charCode" in evt ? evt.charCode : evt.keyCode);if (c==10){// CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozillac=0;evt.keyCode = 13;}else if(c==13||c==27){c=0; // Mozilla considers ENTER and ESC non-printable}else if(c==3){c=99; // Mozilla maps CTRL-BREAK to CTRL-c}// Mozilla sets keyCode to 0 when there is a charCode// but that stops the event on IE.evt.charCode = c;del._setKeyChar(evt);break;}return evt;},// some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE// we map those virtual key codes to ascii here// not valid for all (non-US) keyboards, so maybe we shouldn't bother_punctMap: {106:42,111:47,186:59,187:43,188:44,189:45,190:46,191:47,192:96,219:91,220:92,221:93,222:39},_stealthKeyDown: function(evt){// IE doesn't fire keypress for most non-printable characters.// other browsers do, we simulate it here.var kp=evt.currentTarget.onkeypress;// only works if kp exists and is a dispatcherif(!kp||!kp._listeners)return;// munge key/charCodevar k=evt.keyCode;// These are Windows Virtual Key Codes// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.aspvar unprintable = (k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);// synthesize keypress for most unprintables and CTRL-keysif(unprintable||evt.ctrlKey){var c = (unprintable ? 0 : k);if(evt.ctrlKey){if(k==3 || k==13){return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively}else if(c>95 && c<106){c -= 48; // map CTRL-[numpad 0-9] to ASCII}else if((!evt.shiftKey)&&(c>=65&&c<=90)){c += 32; // map CTRL-[A-Z] to lowercase}else{c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII}}// simulate a keypress eventvar faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});kp.call(evt.currentTarget, faux);evt.cancelBubble = faux.cancelBubble;evt.returnValue = faux.returnValue;_trySetKeyCode(evt, faux.keyCode);}},// Called in Event scope_stopPropagation: function(){this.cancelBubble = true;},_preventDefault: function(){// Setting keyCode to 0 is the only way to prevent certain keypresses (namely// ctrl-combinations that correspond to menu accelerator keys).// Otoh, it prevents upstream listeners from getting this information// Try to split the difference here by clobbering keyCode only for ctrl// combinations. If you still need to access the key upstream, bubbledKeyCode is// provided as a workaround.this.bubbledKeyCode = this.keyCode;if(this.ctrlKey){_trySetKeyCode(this, 0);}this.returnValue = false;}});// override stopEvent for IEdojo.stopEvent = function(evt){evt = evt || window.event;del._stopPropagation.call(evt);del._preventDefault.call(evt);}}del._synthesizeEvent = function(evt, props){var faux = dojo.mixin({}, evt, props);del._setKeyChar(faux);// FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault);// but it throws an error when preventDefault is invoked on Safari// does Event.preventDefault not support "apply" on Safari?faux.preventDefault = function(){ evt.preventDefault(); };faux.stopPropagation = function(){ evt.stopPropagation(); };return faux;}// Opera event normalizationif(dojo.isOpera){dojo.mixin(del, {_fixEvent: function(evt, sender){switch(evt.type){case "keypress":var c = evt.which;if(c==3){c=99; // Mozilla maps CTRL-BREAK to CTRL-c}// can't trap some keys at all, like INSERT and DELETE// there is no differentiating info between DELETE and ".", or INSERT and "-"c = ((c<41)&&(!evt.shiftKey) ? 0 : c);if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){// lowercase CTRL-[A-Z] keysc += 32;}return del._synthesizeEvent(evt, { charCode: c });}return evt;}});}// Safari event normalizationif(dojo.isSafari){dojo.mixin(del, {_fixEvent: function(evt, sender){switch(evt.type){case "keypress":var c = evt.charCode, s = evt.shiftKey, k = evt.keyCode;// FIXME: This is a hack, suggest we rethink keyboard strategy.// Arrow and page keys have 0 "keyCode" in keypress events.on Safari for Windowsk = k || identifierMap[evt.keyIdentifier] || 0;if(evt.keyIdentifier=="Enter"){c = 0; // differentiate Enter from CTRL-m (both code 13)}else if((evt.ctrlKey)&&(c>0)&&(c<27)){c += 96; // map CTRL-[A-Z] codes to ASCII} else if (c==dojo.keys.SHIFT_TAB) {c = dojo.keys.TAB; // morph SHIFT_TAB into TAB + shiftKey: trues = true;} else {c = (c>=32 && c<63232 ? c : 0); // avoid generating keyChar for non-printables}return del._synthesizeEvent(evt, {charCode: c, shiftKey: s, keyCode: k});}return evt;}});dojo.mixin(dojo.keys, {SHIFT_TAB: 25,UP_ARROW: 63232,DOWN_ARROW: 63233,LEFT_ARROW: 63234,RIGHT_ARROW: 63235,F1: 63236,F2: 63237,F3: 63238,F4: 63239,F5: 63240,F6: 63241,F7: 63242,F8: 63243,F9: 63244,F10: 63245,F11: 63246,F12: 63247,PAUSE: 63250,DELETE: 63272,HOME: 63273,END: 63275,PAGE_UP: 63276,PAGE_DOWN: 63277,INSERT: 63302,PRINT_SCREEN: 63248,SCROLL_LOCK: 63249,NUM_LOCK: 63289});var dk = dojo.keys, identifierMap = { "Up": dk.UP_ARROW, "Down": dk.DOWN_ARROW, "Left": dk.LEFT_ARROW, "Right": dk.RIGHT_ARROW, "PageUp": dk.PAGE_UP, "PageDown": dk.PAGE_DOWN };}})();if(dojo.isIE){// keep this out of the closure// closing over 'iel' or 'ieh' b0rks leak prevention// ls[i] is an index into the master handler arraydojo._getIeDispatcher = function(){return function(){var ap=Array.prototype, h=dojo._ie_listener.handlers, c=arguments.callee, ls=c._listeners, t=h[c.target];// return value comes from original target functionvar r = t && t.apply(this, arguments);// invoke listeners after target functionfor(var i in ls){if(!(i in ap)){h[ls[i]].apply(this, arguments);}}return r;}}// keep this out of the closure to reduce RAM allocationdojo._event_listener._fixCallback = function(fp){var f = dojo._event_listener._fixEvent;return function(e){ return fp.call(this, f(e, this)); };}}}