Changeset 8424
- Timestamp:
- 05/04/07 12:25:13 (19 months ago)
- Location:
- dojo/trunk/_base
- Files:
-
- 3 modified
Legend:
- Unmodified
- Added
- Removed
-
dojo/trunk/_base/connect.js
r8402 r8424 10 10 // create a dispatcher function 11 11 getDispatcher: function(){ 12 // return a dispatcher function 12 // following comments pulled out-of-line to prevent cloning them 13 // in the returned function. 14 // - indices (i) that are really in the array of listeners (ls) will 15 // not be in Array.prototype. This is the 'sparse array' trick 16 // that keeps us safe from libs that take liberties with built-in 17 // objects 18 // - listener is invoked with current scope (this) 13 19 return function(){ 14 // iterate over our listeners15 20 var ls = arguments.callee.listeners; 16 21 for(var i in ls){ 17 // indices that are really in the array will not be in Array.prototype18 // this 'sparse array' trick keeps us safe from libs that take19 // liberties with built-in objects20 22 if(!(i in Array.prototype)){ 21 // invoke the listener with our current scope22 23 ls[i].apply(this, arguments); 23 24 } … … 65 66 }; 66 67 67 // arbitrary method delegation (knows nothing about DOM) 68 // Multiple delegation for arbitrary methods. 69 70 // This unit knows nothing about DOM, 71 // but we include DOM aware 72 // documentation and dontFix 73 // argument here to help the autodocs. 74 // Actual DOM aware code is in event.js. 68 75 69 76 dojo.connect = function(/*Object|null*/ obj, 70 77 /*String*/ event, 71 78 /*Object|null*/ context, 72 /*String|Function*/ method){ 79 /*String|Function*/ method, 80 /*Boolean*/ dontFix){ 73 81 // summary: 74 82 // Create a link that calls one function when another executes. … … 89 97 // The source object for the event function. 90 98 // Defaults to dojo.global if null. 99 // If obj is a DOM node, the connection is delegated 100 // to the DOM event manager (unless dontFix is true). 91 101 // event: 92 102 // String name of the event function in obj. … … 106 116 // method receives the same arguments as the event. 107 117 // See context argument comments for information on method's scope. 118 // dontFix: 119 // If obj is a DOM node, set dontFix to true to prevent delegation 120 // of this connection to the DOM event manager. 108 121 // usage: 109 122 // // when obj.onchange(), do ui.update() … … 133 146 // dojo.connect("globalEvent", globalHandler); // same 134 147 135 // normalize arguments into args148 // normalize arguments 136 149 var a=arguments, args=[], i=0; 137 if(dojo.isString(a[0])){ 138 args.push(null, a[i++]); 139 }else{ 140 args.push(a[i++], a[i++]); 141 } 142 if(dojo.isString(a[i+1])||(dojo.isFunction(a[i+1]))){ 143 args.push(a[i++], a[i++]); 144 }else{ 145 args.push(null, a[i++]); 146 } 147 for (; i<arguments.length; i++){ 148 args.push(arguments[i]); 149 } 150 // if a[0] is a String, obj was ommited 151 args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]); 152 // if the arg-after-next is a String or Function, context was NOT omitted 153 var a1 = a[i+1]; 154 args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]); 155 // absorb any additional arguments 156 for (var l=a.length; i<l; i++){ args.push(a[i]); } 157 // do the actual work 150 158 return dojo._connect.apply(this, args); /*Handle*/ 151 159 } … … 162 170 // Removes the connection between event and the method referenced by handle. 163 171 // handle: 164 // the return value of the dojo.connect call that created the connection.172 // the return value of the dojo.connect call that created the connection. 165 173 dojo._disconnect.apply(this, handle); 174 if (handle && handle[0]!=undefined){ 175 dojo._disconnect.apply(this, handle); 176 // let's not keep this reference 177 delete handle[0]; 178 } 166 179 } 167 180 -
dojo/trunk/_base/event.js
r8402 r8424 8 8 var de = { 9 9 addListener: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){ 10 if(!node){ return;}10 if(!node){return;} 11 11 event = de._normalizeEventName(event) 12 12 fp = de._fixCallback(event, fp); … … 27 27 _normalizeEventName: function(/*String*/name){ 28 28 // Generally, name should be lower case, unless it is special 29 // somehow (e.g. a Mozilla event)30 // Remove 'on' 29 // somehow (e.g. a Mozilla DOM event). 30 // Remove 'on'. 31 31 return (name.slice(0,2)=="on" ? name.slice(2) : name); 32 32 }, 33 33 _fixCallback: function(/*String*/name, fp){ 34 //return function(e){ return fp(de._fixEvent(e, this)); }; 35 return (name!="keypress" ? fp : function(e){ return fp(de._fixEvent(e, this)); }); 34 // By default, we only invoke _fixEvent for 'keypress' 35 // If code is added to _fixEvent for other events, we have 36 // to revisit this optimization. 37 // This also applies to _fixEvent overrides for Safari and Opera 38 // below. 39 return (name!="keypress" ? fp : function(e){ return fp.call(this, de._fixEvent(e, this)); }); 36 40 }, 37 41 _fixEvent: function(evt, sender){ 38 // fixCallback only attaches us to keypress, but we switch on 39 // evt.type because we might be called from dojo.fixEvent 42 // _fixCallback only attaches us to keypress. 43 // Switch on evt.type anyway because we might 44 // be called directly from dojo.fixEvent. 40 45 switch(evt.type){ 41 46 case "keypress": 42 de._ fixKey(evt);47 de._setKeyChar(evt); 43 48 break; 44 49 } 45 50 return evt; 46 51 }, 47 _fixKey: function(evt, charCode){ 48 var c = (arguments.length > 1 ? charCode : evt.charCode); 49 evt.keyChar = (c ? String.fromCharCode(c) : ''); 52 _setKeyChar: function(evt){ 53 evt.keyChar = (evt.charCode ? String.fromCharCode(evt.charCode) : ''); 50 54 } 51 55 }; … … 53 57 // DOM events 54 58 59 // FIXME: no reason to make this public, use connect 55 60 dojo.addListener = function(node, event, context, method){ 56 61 return de.addListener(node, event, dojo.hitch(context, method)); // Handle 57 62 } 58 63 64 // FIXME: no reason to make this public, use disconnect 59 65 dojo.removeListener = function(node, event, handle){ 60 66 de.removeListener(node, event, handle); … … 68 74 // sender: node to treat as "currentTarget" 69 75 return de._fixEvent(evt, sender); 70 //return (de._fixEvent ? de._fixEvent(evt, sender) : evt);71 76 } 72 77 … … 88 93 89 94 dojo._connect = function(obj, event, context, method, dontFix){ 90 dontFix = !obj || !(obj.nodeType||obj.attachEvent||obj.addEventListener) || dontFix; 95 // use listener code (event fixing) for nodes that look like objects, unless told not to 96 dontFix = Boolean(!obj || !(obj.nodeType||obj.attachEvent||obj.addEventListener) || dontFix); 97 // grab up the result of baseline disconnect, or construct one using addListener 91 98 var h = (dontFix ? dc.apply(this, arguments) : [obj, event, dojo.addListener.apply(this, arguments)]); 99 // append flag to the result identifying the kind of listener 92 100 h.push(dontFix); 93 101 return h; … … 95 103 96 104 dojo._disconnect = function(obj, event, handle, dontFix){ 105 // dispatch this disconnect either to the baseline code or to removeListener 97 106 (dontFix ? dd : dojo.removeListener).apply(this, arguments); 98 107 } … … 166 175 // IE event normalization 167 176 if(dojo.isIE){ 177 _trySetKeyCode = function(e, code){ 178 try{ 179 // squelch errors when keyCode is read-only 180 // (e.g. if keyCode is ctrl or shift) 181 return e.keyCode = code; 182 }catch(e){ 183 return 0; 184 } 185 } 186 168 187 var ap = Array.prototype; 169 188 // by default, use the standard listener … … 205 224 if(!node){return;} // undefined 206 225 event = de._normalizeEventName(event); 207 var handle = iel.add(node, event, de._fixCallback(fp));208 226 if(event=="onkeypress"){ 209 // FIXME: we are using the knowledge that handle 210 // is an Integer, which is supposed to be private. 211 // Perhaps the listener could natively return a 212 // Number object instead of a concrete value. 213 handle = new Number(handle); 214 handle.keydown = de.addListener(node, "onkeydown", de._nop); 215 } 216 return handle; 227 // we need to listen to onkeydown to synthesize 228 // keypress events that otherwise won't fire 229 // on IE 230 var kd = node.onkeydown; 231 if(!kd||!kd.listeners||!kd.listeners._stealthKeydown){ 232 // we simply ignore this connection when disconnecting 233 // because it's harmless 234 de.addListener(node, "onkeydown", de._stealthKeyDown); 235 // we only want one stealth listener per node 236 kd.listeners._stealthKeydown = true; 237 } 238 } 239 return iel.add(node, event, de._fixCallback(fp, node)); 217 240 }, 218 241 removeListener: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){ 219 242 iel.remove(node, de._normalizeEventName(event), handle); 220 if(handle.keydown){iel.remove(node, "onkeydown", handle.keydown);}221 243 }, 222 244 _normalizeEventName: function(/*String*/eventName){ … … 226 248 return (eventName.slice(0,2)!="on" ? "on"+eventName : eventName); 227 249 }, 228 _nop: function(){ },229 _fixCallback: function(fp ){250 _nop: function(){}, 251 _fixCallback: function(fp, sender){ 230 252 return function(e){ 231 e = de._fixEvent(e, this) 232 var r = fp(e); 233 de._postFixEvent(e); 234 return r; 253 return fp.call(this, de._fixEvent(e, sender)); 235 254 }; 236 255 }, … … 277 296 c=99; // Mozilla maps CTRL-BREAK to CTRL-c 278 297 } 279 try{ 280 // squelch errors when keyCode is read-only 281 // (e.g. if keyCode is ctrl or shift) 282 evt.keyCode = (c ? 0 : evt.keyCode); 283 }catch(e){ 284 c=0; 285 } 298 // if we have a charCode, try to 0 keycode 299 // if that fails, our charCode is bogus and is set to 0 300 if(c){c = _trySetKeyCode(evt, 0);} 286 301 evt.charCode = c; 287 de._ fixKey(evt);302 de._setKeyChar(evt); 288 303 break; 289 304 } … … 308 323 222:39 309 324 }, 310 _postFixEvent: function(evt){ 311 switch(evt.type){ 312 // IE doesn't fire keypress for most non-printable characters. 313 // other browsers do, we simulate it here. 314 case "keydown": 315 var c = evt.keyCode; 316 // These are Windows Virtual Key Codes 317 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp 318 var unprintable = (c!=13)&&(c!=32)&&(c!=27)&&(c<48||c>90)&&(c<96||c>111)&&(c<186||c>192)&&(c<219||c>222); 319 if(unprintable||evt.ctrlKey){ 320 c = (unprintable ? 0 : c); 321 if(evt.ctrlKey){ 322 if(evt.keyCode==3){ 323 break; // IE will post CTRL-BREAK as keypress natively 324 }else if(c>95 && c<106){ 325 c -= 48; // map CTRL-[numpad 0-9] to ASCII 326 }else if((!evt.shiftKey)&&(c>=65&&c<=90)){ 327 c += 32; // map CTRL-[A-Z] to lowercase 328 }else{ 329 c = de._punctMap[c] || c; // map other problematic CTRL combinations to ASCII 330 } 331 } 332 var faux = document.createEventObject(evt); 333 faux.charCode = c; 334 de._fixKey(faux); 335 faux.faux = true; // just for debugging 336 evt.target.fireEvent("onkeypress", faux); 337 evt.cancelBubble = faux.cancelBubble; 338 evt.returnValue = faux.returnValue; 339 try{ 340 // squelch errors when keyCode is read-only 341 // (e.g. if keyCode is ctrl or shift) 342 evt.keyCode = faux.keyCode; 343 }catch(e){}; 325 _stealthKeyDown: function(evt){ 326 // IE doesn't fire keypress for most non-printable characters. 327 // other browsers do, we simulate it here. 328 var kp = evt.currentTarget.onkeypress; 329 // only works if kp exists and is a dispatcher 330 if(!kp||!kp.listeners)return; 331 // munge key/charCode 332 var c = evt.keyCode; 333 // These are Windows Virtual Key Codes 334 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp 335 var unprintable = (c!=13)&&(c!=32)&&(c!=27)&&(c<48||c>90)&&(c<96||c>111)&&(c<186||c>192)&&(c<219||c>222); 336 if(unprintable||evt.ctrlKey){ 337 c = (unprintable ? 0 : c); 338 if(evt.ctrlKey){ 339 if(evt.keyCode==3){ 340 return; // IE will post CTRL-BREAK as keypress natively 341 }else if(c>95 && c<106){ 342 c -= 48; // map CTRL-[numpad 0-9] to ASCII 343 }else if((!evt.shiftKey)&&(c>=65&&c<=90)){ 344 c += 32; // map CTRL-[A-Z] to lowercase 345 }else{ 346 c = de._punctMap[c] || c; // map other problematic CTRL combinations to ASCII 344 347 } 345 break; 348 } 349 // simulate a keypress event 350 var faux = de._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c}); 351 kp.call(evt.currentTarget, faux); 352 evt.cancelBubble = faux.cancelBubble; 353 evt.returnValue = faux.returnValue; 354 _trySetKeyCode(evt, faux.keyCode); 346 355 } 347 356 }, … … 351 360 }, 352 361 _preventDefault: function(){ 353 try{evt.keyCode = 0;}catch(e){}; // squelch errors when keyCode is read-only (e.g. if keyCode is ctrl or shift)362 _trySetKeyCode(this, 0); 354 363 this.returnValue = false; 355 364 } 356 365 }); 357 366 358 // override stopEvent 367 // override stopEvent for IE 359 368 dojo.stopEvent = function(evt){ 360 369 evt = evt || window.event; … … 364 373 } 365 374 366 de._synthesizeEvent = function(evt, keyCode, charCode, shiftKey) { 367 var faux = { 368 type: evt.type, 369 shiftKey: shiftKey, 370 ctrlKey: evt.ctrlKey, 371 altKey: evt.altKey, 372 keyCode: (charCode ? 0 : keyCode), 373 charCode: charCode 374 }; 375 de._fixKey(faux, charCode); 375 de._synthesizeEvent = function(evt, props) { 376 var faux = dojo.mixin({}, evt, props); 377 if(faux.charCode){faux.keyCode = 0;} 378 de._setKeyChar(faux); 376 379 // FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault); 377 380 // but it throws an error when preventDefault is invoked on Safari … … 399 402 c += 32; 400 403 } 401 return de._synthesizeEvent(evt, evt.keyCode, c, evt.shiftKey);404 return de._synthesizeEvent(evt, { charCode: c }); 402 405 } 403 406 return evt; … … 423 426 c = (c>=32 && c<63232 ? c : 0); // avoid generating keyChar for non-printables 424 427 } 425 return de._synthesizeEvent(evt, keyCode, c, s);428 return de._synthesizeEvent(evt, {charCode: c, shiftKey: s}); 426 429 } 427 430 return evt; … … 462 465 if(dojo.isIE<7){ 463 466 // keep this out of the closure 464 // closing over 'iel' or 'ieh' borks 465 // l eak prevention467 // closing over 'iel' or 'ieh' borks leak prevention 468 // ls[i] is an index into the master handler array 466 469 dojo._getIeDispatcher = function(){ 467 470 return function(){ 468 471 var ap=Array.prototype, ls=arguments.callee.listeners, h=dojo._ie_listener.handlers; 469 472 for(var i in ls){ 470 // real indices won't be in Array.prototype471 473 if(!(i in ap)){ 472 // listener value is a hash into the master handler array473 474 h[ls[i]].apply(this, arguments); 474 475 } -
dojo/trunk/_base/lang.js
r8299 r8424 115 115 // summary: 116 116 // Returns a function that will only ever execute in the a given scope. 117 // This allows for easy use of object member functions117 // This allows for easy use of object member functions 118 118 // in callbacks and other places in which the "this" keyword may 119 119 // otherwise not reference the expected scope. … … 123 123 // for the hitched function. 124 124 // scope: 125 // The scope to run the method in 125 // The scope to use when method executes. If method is a string, 126 // scope is also the object containing method. 126 127 // method: 127 128 // A function to be hitched to scope, or the name of the method in