]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | // @tag core\r |
2 | /**\r | |
3 | * Represents single event type that an Observable object listens to.\r | |
4 | * All actual listeners are tracked inside here. When the event fires,\r | |
5 | * it calls all the registered listener functions.\r | |
6 | *\r | |
7 | * @private\r | |
8 | */\r | |
9 | Ext.define('Ext.util.Event', function() {\r | |
10 | var arraySlice = Array.prototype.slice,\r | |
11 | arrayInsert = Ext.Array.insert,\r | |
12 | toArray = Ext.Array.toArray,\r | |
13 | fireArgs = {};\r | |
14 | \r | |
15 | return {\r | |
16 | requires: 'Ext.util.DelayedTask',\r | |
17 | \r | |
18 | /**\r | |
19 | * @property {Boolean} isEvent\r | |
20 | * `true` in this class to identify an object as an instantiated Event, or subclass thereof.\r | |
21 | */\r | |
22 | isEvent: true,\r | |
23 | \r | |
24 | // Private. Event suspend count\r | |
25 | suspended: 0,\r | |
26 | \r | |
27 | noOptions: {},\r | |
28 | \r | |
29 | constructor: function(observable, name) {\r | |
30 | this.name = name;\r | |
31 | this.observable = observable;\r | |
32 | this.listeners = [];\r | |
33 | },\r | |
34 | \r | |
35 | addListener: function(fn, scope, options, caller, manager) {\r | |
36 | var me = this,\r | |
37 | added = false,\r | |
38 | observable = me.observable,\r | |
39 | eventName = me.name,\r | |
40 | listeners, listener, priority, isNegativePriority, highestNegativePriorityIndex,\r | |
41 | hasNegativePriorityIndex, length, index, i, listenerPriority;\r | |
42 | \r | |
43 | //<debug>\r | |
44 | if (scope && !Ext._namedScopes[scope] && (typeof fn === 'string') && (typeof scope[fn] !== 'function')) {\r | |
45 | Ext.raise("No method named '" + fn + "' found on scope object");\r | |
46 | }\r | |
47 | //</debug>\r | |
48 | \r | |
49 | if (me.findListener(fn, scope) === -1) {\r | |
50 | listener = me.createListener(fn, scope, options, caller, manager);\r | |
51 | if (me.firing) {\r | |
52 | // if we are currently firing this event, don't disturb the listener loop\r | |
53 | me.listeners = me.listeners.slice(0);\r | |
54 | }\r | |
55 | listeners = me.listeners;\r | |
56 | index = length = listeners.length;\r | |
57 | priority = options && options.priority;\r | |
58 | highestNegativePriorityIndex = me._highestNegativePriorityIndex;\r | |
59 | hasNegativePriorityIndex = highestNegativePriorityIndex !== undefined;\r | |
60 | if (priority) {\r | |
61 | // Find the index at which to insert the listener into the listeners array,\r | |
62 | // sorted by priority highest to lowest.\r | |
63 | isNegativePriority = (priority < 0);\r | |
64 | if (!isNegativePriority || hasNegativePriorityIndex) {\r | |
65 | // If the priority is a positive number, or if it is a negative number\r | |
66 | // and there are other existing negative priority listenrs, then we\r | |
67 | // need to calcuate the listeners priority-order index.\r | |
68 | // If the priority is a negative number, begin the search for priority\r | |
69 | // order index at the index of the highest existing negative priority\r | |
70 | // listener, otherwise begin at 0\r | |
71 | for(i = (isNegativePriority ? highestNegativePriorityIndex : 0); i < length; i++) {\r | |
72 | // Listeners created without options will have no "o" property\r | |
73 | listenerPriority = listeners[i].o ? listeners[i].o.priority||0 : 0;\r | |
74 | if (listenerPriority < priority) {\r | |
75 | index = i;\r | |
76 | break;\r | |
77 | }\r | |
78 | }\r | |
79 | } else {\r | |
80 | // if the priority is a negative number, and there are no other negative\r | |
81 | // priority listeners, then no calculation is needed - the negative\r | |
82 | // priority listener gets appended to the end of the listeners array.\r | |
83 | me._highestNegativePriorityIndex = index;\r | |
84 | }\r | |
85 | } else if (hasNegativePriorityIndex) {\r | |
86 | // listeners with a priority of 0 or undefined are appended to the end of\r | |
87 | // the listeners array unless there are negative priority listeners in the\r | |
88 | // listeners array, then they are inserted before the highest negative\r | |
89 | // priority listener.\r | |
90 | index = highestNegativePriorityIndex;\r | |
91 | }\r | |
92 | \r | |
93 | if (!isNegativePriority && index <= highestNegativePriorityIndex) {\r | |
94 | me._highestNegativePriorityIndex ++;\r | |
95 | }\r | |
96 | if (index === length) {\r | |
97 | listeners[length] = listener;\r | |
98 | } else {\r | |
99 | arrayInsert(listeners, index, [listener]);\r | |
100 | }\r | |
101 | \r | |
102 | if (observable.isElement) {\r | |
103 | // It is the role of Ext.util.Event (vs Ext.Element) to handle subscribe/\r | |
104 | // unsubscribe because it is the lowest level place to intercept the\r | |
105 | // listener before it is added/removed. For addListener this could easily\r | |
106 | // be done in Ext.Element's doAddListener override, but since there are\r | |
107 | // multiple paths for listener removal (un, clearListeners), it is best\r | |
108 | // to keep all subscribe/unsubscribe logic here.\r | |
109 | observable._getPublisher(eventName).subscribe(\r | |
110 | observable,\r | |
111 | eventName,\r | |
112 | options.delegated !== false,\r | |
113 | options.capture\r | |
114 | );\r | |
115 | }\r | |
116 | \r | |
117 | added = true;\r | |
118 | }\r | |
119 | \r | |
120 | return added;\r | |
121 | },\r | |
122 | \r | |
123 | createListener: function(fn, scope, o, caller, manager) {\r | |
124 | var me = this,\r | |
125 | namedScope = Ext._namedScopes[scope],\r | |
126 | listener = {\r | |
127 | fn: fn,\r | |
128 | scope: scope,\r | |
129 | ev: me,\r | |
130 | caller: caller,\r | |
131 | manager: manager,\r | |
132 | namedScope: namedScope,\r | |
133 | defaultScope: namedScope ? (scope || me.observable) : undefined,\r | |
134 | lateBound: typeof fn === 'string'\r | |
135 | },\r | |
136 | handler = fn,\r | |
137 | wrapped = false,\r | |
138 | type;\r | |
139 | \r | |
140 | // The order is important. The 'single' wrapper must be wrapped by the 'buffer' and 'delayed' wrapper\r | |
141 | // because the event removal that the single listener does destroys the listener's DelayedTask(s)\r | |
142 | if (o) {\r | |
143 | listener.o = o;\r | |
144 | if (o.single) {\r | |
145 | handler = me.createSingle(handler, listener, o, scope);\r | |
146 | wrapped = true;\r | |
147 | }\r | |
148 | if (o.target) {\r | |
149 | handler = me.createTargeted(handler, listener, o, scope, wrapped);\r | |
150 | wrapped = true;\r | |
151 | }\r | |
152 | if (o.delay) {\r | |
153 | handler = me.createDelayed(handler, listener, o, scope, wrapped);\r | |
154 | wrapped = true;\r | |
155 | }\r | |
156 | if (o.buffer) {\r | |
157 | handler = me.createBuffered(handler, listener, o, scope, wrapped);\r | |
158 | wrapped = true;\r | |
159 | }\r | |
160 | \r | |
161 | if (me.observable.isElement) {\r | |
162 | // If the event type was translated, e.g. mousedown -> touchstart, we need to save\r | |
163 | // the original type in the listener object so that the Ext.event.Event object can\r | |
164 | // reflect the correct type at firing time\r | |
165 | type = o.type;\r | |
166 | if (type) {\r | |
167 | listener.type = type;\r | |
168 | }\r | |
169 | }\r | |
170 | }\r | |
171 | \r | |
172 | listener.fireFn = handler;\r | |
173 | listener.wrapped = wrapped;\r | |
174 | return listener;\r | |
175 | },\r | |
176 | \r | |
177 | findListener: function(fn, scope) {\r | |
178 | var listeners = this.listeners,\r | |
179 | i = listeners.length,\r | |
180 | listener;\r | |
181 | \r | |
182 | while (i--) {\r | |
183 | listener = listeners[i];\r | |
184 | if (listener) {\r | |
185 | // use ==, not === for scope comparison, so that undefined and null are equal\r | |
186 | if (listener.fn === fn && listener.scope == scope) {\r | |
187 | return i;\r | |
188 | }\r | |
189 | }\r | |
190 | }\r | |
191 | \r | |
192 | return - 1;\r | |
193 | },\r | |
194 | \r | |
195 | removeListener: function(fn, scope, index) {\r | |
196 | var me = this,\r | |
197 | removed = false,\r | |
198 | observable = me.observable,\r | |
199 | eventName = me.name,\r | |
200 | listener, highestNegativePriorityIndex, options,\r | |
201 | k, manager, managedListeners, managedListener, i;\r | |
202 | \r | |
203 | index = index || me.findListener(fn, scope);\r | |
204 | \r | |
205 | if (index != -1) {\r | |
206 | listener = me.listeners[index];\r | |
207 | options = listener.o;\r | |
208 | highestNegativePriorityIndex = me._highestNegativePriorityIndex;\r | |
209 | \r | |
210 | if (me.firing) {\r | |
211 | me.listeners = me.listeners.slice(0);\r | |
212 | }\r | |
213 | \r | |
214 | // cancel and remove a buffered handler that hasn't fired yet\r | |
215 | if (listener.task) {\r | |
216 | listener.task.cancel();\r | |
217 | delete listener.task;\r | |
218 | }\r | |
219 | \r | |
220 | // cancel and remove all delayed handlers that haven't fired yet\r | |
221 | k = listener.tasks && listener.tasks.length;\r | |
222 | if (k) {\r | |
223 | while (k--) {\r | |
224 | listener.tasks[k].cancel();\r | |
225 | }\r | |
226 | delete listener.tasks;\r | |
227 | }\r | |
228 | \r | |
229 | // Remove this listener from the listeners array\r | |
230 | // We can use splice directly. The IE8 bug which Ext.Array works around only affects *insertion*\r | |
231 | // http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/6e946d03-e09f-4b22-a4dd-cd5e276bf05a/\r | |
232 | me.listeners.splice(index, 1);\r | |
233 | \r | |
234 | manager = listener.manager;\r | |
235 | if (manager) {\r | |
236 | // If this is a managed listener we need to remove it from the manager's\r | |
237 | // managedListeners array. This ensures that if we listen using mon\r | |
238 | // and then remove without using mun, the managedListeners array is updated\r | |
239 | // accordingly, for example\r | |
240 | //\r | |
241 | // manager.on(target, 'foo', fn);\r | |
242 | //\r | |
243 | // target.un('foo', fn);\r | |
244 | managedListeners = manager.managedListeners;\r | |
245 | if (managedListeners) {\r | |
246 | for (i = managedListeners.length; i--;) {\r | |
247 | managedListener = managedListeners[i];\r | |
248 | if (managedListener.item === me.observable && managedListener.ename === eventName &&\r | |
249 | managedListener.fn === fn && managedListener.scope === scope) {\r | |
250 | managedListeners.splice(i, 1);\r | |
251 | }\r | |
252 | }\r | |
253 | }\r | |
254 | }\r | |
255 | \r | |
256 | // if the listeners array contains negative priority listeners, adjust the\r | |
257 | // internal index if needed.\r | |
258 | if (highestNegativePriorityIndex) {\r | |
259 | if (index < highestNegativePriorityIndex) {\r | |
260 | me._highestNegativePriorityIndex --;\r | |
261 | } else if (index === highestNegativePriorityIndex && index === me.listeners.length) {\r | |
262 | delete me._highestNegativePriorityIndex;\r | |
263 | }\r | |
264 | }\r | |
265 | \r | |
266 | if (observable.isElement) {\r | |
267 | observable._getPublisher(eventName).unsubscribe(\r | |
268 | observable,\r | |
269 | eventName,\r | |
270 | options.delegated !== false,\r | |
271 | options.capture\r | |
272 | );\r | |
273 | }\r | |
274 | \r | |
275 | removed = true;\r | |
276 | }\r | |
277 | \r | |
278 | return removed;\r | |
279 | },\r | |
280 | \r | |
281 | // Iterate to stop any buffered/delayed events\r | |
282 | clearListeners: function() {\r | |
283 | var listeners = this.listeners,\r | |
284 | i = listeners.length,\r | |
285 | listener;\r | |
286 | \r | |
287 | while (i--) {\r | |
288 | listener = listeners[i];\r | |
289 | this.removeListener(listener.fn, listener.scope);\r | |
290 | }\r | |
291 | },\r | |
292 | \r | |
293 | suspend: function() {\r | |
294 | ++this.suspended;\r | |
295 | },\r | |
296 | \r | |
297 | resume: function() {\r | |
298 | if (this.suspended) {\r | |
299 | --this.suspended;\r | |
300 | }\r | |
301 | },\r | |
302 | \r | |
303 | isSuspended: function() {\r | |
304 | return this.suspended > 0;\r | |
305 | },\r | |
306 | \r | |
307 | fireDelegated: function(firingObservable, args) {\r | |
308 | this.firingObservable = firingObservable;\r | |
309 | return this.fire.apply(this, args);\r | |
310 | },\r | |
311 | \r | |
312 | fire: function() {\r | |
313 | var me = this,\r | |
314 | listeners = me.listeners,\r | |
315 | count = listeners.length,\r | |
316 | observable = me.observable,\r | |
317 | isElement = observable.isElement,\r | |
318 | isComponent = observable.isComponent,\r | |
319 | firingObservable = me.firingObservable,\r | |
320 | options, delegate, fireInfo, i, args, listener, len, delegateEl, currentTarget,\r | |
321 | type, chained, firingArgs, e, fireFn, fireScope;\r | |
322 | \r | |
323 | if (!me.suspended && count > 0) {\r | |
324 | me.firing = true;\r | |
325 | args = arguments.length ? arraySlice.call(arguments, 0) : [];\r | |
326 | len = args.length;\r | |
327 | if (isElement) {\r | |
328 | e = args[0];\r | |
329 | }\r | |
330 | for (i = 0; i < count; i++) {\r | |
331 | listener = listeners[i];\r | |
332 | options = listener.o;\r | |
333 | \r | |
334 | if (isElement) {\r | |
335 | if (currentTarget) {\r | |
336 | // restore the previous currentTarget if we changed it last time\r | |
337 | // around the loop while processing the delegate option.\r | |
338 | e.setCurrentTarget(currentTarget);\r | |
339 | }\r | |
340 | \r | |
341 | // For events that have been translated to provide device compatibility,\r | |
342 | // e.g. mousedown -> touchstart, we want the event object to reflect the\r | |
343 | // type that was originally listened for, not the type of the actual event\r | |
344 | // that fired. The listener's "type" property reflects the original type.\r | |
345 | type = listener.type;\r | |
346 | \r | |
347 | if (type) {\r | |
348 | // chain a new object to the event object before changing the type.\r | |
349 | // This is more efficient than creating a new event object, and we\r | |
350 | // don't want to change the type of the original event because it may\r | |
351 | // be used asynchronously by other handlers\r | |
352 | chained = e;\r | |
353 | e = args[0] = chained.chain({ type: type });\r | |
354 | }\r | |
355 | \r | |
356 | // In Ext4 Ext.EventObject was a singleton event object that was reused as events\r | |
357 | // were fired. Set Ext.EventObject to the last fired event for compatibility.\r | |
358 | Ext.EventObject = e;\r | |
359 | }\r | |
360 | \r | |
361 | firingArgs = args;\r | |
362 | \r | |
363 | if (options) {\r | |
364 | delegate = options.delegate;\r | |
365 | if (delegate) {\r | |
366 | if (isElement) {\r | |
367 | // prepending the currentTarget.id to the delegate selector\r | |
368 | // allows us to match selectors such as "> div"\r | |
369 | delegateEl = e.getTarget('#' + e.currentTarget.id + ' ' + delegate);\r | |
370 | if (delegateEl) {\r | |
371 | args[1] = delegateEl;\r | |
372 | // save the current target before changing it to the delegateEl\r | |
373 | // so that we can restore it next time around\r | |
374 | currentTarget = e.currentTarget;\r | |
375 | e.setCurrentTarget(delegateEl);\r | |
376 | } else {\r | |
377 | continue;\r | |
378 | }\r | |
379 | } else if (isComponent &&\r | |
380 | !firingObservable.is('#' + observable.id + ' ' + options.delegate)) {\r | |
381 | continue;\r | |
382 | }\r | |
383 | }\r | |
384 | \r | |
385 | if (isElement) {\r | |
386 | if (options.preventDefault) {\r | |
387 | e.preventDefault();\r | |
388 | }\r | |
389 | \r | |
390 | if (options.stopPropagation) {\r | |
391 | e.stopPropagation();\r | |
392 | }\r | |
393 | \r | |
394 | if (options.stopEvent) {\r | |
395 | e.stopEvent();\r | |
396 | }\r | |
397 | }\r | |
398 | \r | |
399 | args[len] = options;\r | |
400 | \r | |
401 | if (options.args) {\r | |
402 | firingArgs = options.args.concat(args);\r | |
403 | }\r | |
404 | }\r | |
405 | \r | |
406 | fireInfo = me.getFireInfo(listener);\r | |
407 | fireFn = fireInfo.fn;\r | |
408 | fireScope = fireInfo.scope;\r | |
409 | \r | |
410 | // We don't want to keep closure and scope on the Event prototype!\r | |
411 | fireInfo.fn = fireInfo.scope = null;\r | |
412 | \r | |
413 | if (fireFn.apply(fireScope, firingArgs) === false) {\r | |
414 | Ext.EventObject = null;\r | |
415 | \r | |
416 | return (me.firing = false);\r | |
417 | }\r | |
418 | \r | |
419 | if (chained) {\r | |
420 | // if we chained the event object for type translation we need to\r | |
421 | // un-chain it before proceeding to process the next listener, which\r | |
422 | // may not be a translated event.\r | |
423 | e = args[0] = chained;\r | |
424 | chained = null;\r | |
425 | }\r | |
426 | \r | |
427 | // We don't guarantee Ext.EventObject existence outside of the immediate\r | |
428 | // event propagation scope\r | |
429 | Ext.EventObject = null;\r | |
430 | }\r | |
431 | }\r | |
432 | \r | |
433 | me.firing = false;\r | |
434 | \r | |
435 | return true;\r | |
436 | },\r | |
437 | \r | |
438 | getFireInfo: function(listener, fromWrapped) {\r | |
439 | var observable = this.observable,\r | |
440 | fireFn = listener.fireFn,\r | |
441 | scope = listener.scope,\r | |
442 | namedScope = listener.namedScope,\r | |
443 | fn;\r | |
444 | \r | |
445 | // If we are called with a wrapped listener, only attempt to do scope\r | |
446 | // resolution if we are explicitly called by the last wrapped function\r | |
447 | if (!fromWrapped && listener.wrapped) {\r | |
448 | fireArgs.fn = fireFn;\r | |
449 | return fireArgs;\r | |
450 | }\r | |
451 | \r | |
452 | fn = fromWrapped ? listener.fn : fireFn;\r | |
453 | //<debug>\r | |
454 | var name = fn;\r | |
455 | \r | |
456 | //</debug>\r | |
457 | if (listener.lateBound) {\r | |
458 | // handler is a function name - need to resolve it to a function reference\r | |
459 | if (!scope || namedScope) {\r | |
460 | // Only invoke resolveListenerScope if the user did not specify a scope,\r | |
461 | // or if the user specified a named scope. Named function handlers that\r | |
462 | // use an arbitrary object as the scope just skip this part, and just\r | |
463 | // use the given scope object to resolve the method.\r | |
464 | scope = (listener.caller || observable).resolveListenerScope(listener.defaultScope);\r | |
465 | }\r | |
466 | //<debug>\r | |
467 | if (!scope) {\r | |
468 | Ext.raise('Unable to dynamically resolve scope for "' + listener.ev.name + '" listener on ' + this.observable.id);\r | |
469 | }\r | |
470 | \r | |
471 | if (!Ext.isFunction(scope[fn])) {\r | |
472 | Ext.raise('No method named "' + fn + '" on ' +\r | |
473 | (scope.$className || 'scope object.'));\r | |
474 | }\r | |
475 | //</debug>\r | |
476 | \r | |
477 | fn = scope[fn];\r | |
478 | } else if (namedScope && namedScope.isController) {\r | |
479 | // If handler is a function reference and scope:'controller' was requested\r | |
480 | // we'll do our best to look up a controller.\r | |
481 | scope = (listener.caller || observable).resolveListenerScope(listener.defaultScope);\r | |
482 | //<debug>\r | |
483 | if (!scope) {\r | |
484 | Ext.raise('Unable to dynamically resolve scope for "' + listener.ev.name + '" listener on ' + this.observable.id);\r | |
485 | }\r | |
486 | //</debug>\r | |
487 | } else if (!scope || namedScope) {\r | |
488 | // If handler is a function reference we use the observable instance as\r | |
489 | // the default scope\r | |
490 | scope = observable;\r | |
491 | }\r | |
492 | \r | |
493 | // We can only ever be firing one event at a time, so just keep\r | |
494 | // overwriting tghe object we've got in our closure, otherwise we'll be\r | |
495 | // creating a whole bunch of garbage objects\r | |
496 | fireArgs.fn = fn;\r | |
497 | fireArgs.scope = scope;\r | |
498 | //<debug>\r | |
499 | if (!fn) {\r | |
500 | Ext.raise('Unable to dynamically resolve method "' + name + '" on ' + this.observable.$className);\r | |
501 | }\r | |
502 | //</debug>\r | |
503 | return fireArgs;\r | |
504 | },\r | |
505 | \r | |
506 | createTargeted: function (handler, listener, o, scope, wrapped) {\r | |
507 | return function(){\r | |
508 | if (o.target === arguments[0]) {\r | |
509 | var fireInfo;\r | |
510 | \r | |
511 | if (!wrapped) {\r | |
512 | fireInfo = listener.ev.getFireInfo(listener, true);\r | |
513 | handler = fireInfo.fn;\r | |
514 | scope = fireInfo.scope;\r | |
515 | \r | |
516 | // We don't want to keep closure and scope references on the Event prototype!\r | |
517 | fireInfo.fn = fireInfo.scope = null;\r | |
518 | }\r | |
519 | \r | |
520 | return handler.apply(scope, arguments);\r | |
521 | }\r | |
522 | };\r | |
523 | },\r | |
524 | \r | |
525 | createBuffered: function (handler, listener, o, scope, wrapped) {\r | |
526 | listener.task = new Ext.util.DelayedTask();\r | |
527 | return function() {\r | |
528 | var fireInfo;\r | |
529 | \r | |
530 | if (!wrapped) {\r | |
531 | fireInfo = listener.ev.getFireInfo(listener, true);\r | |
532 | handler = fireInfo.fn;\r | |
533 | scope = fireInfo.scope;\r | |
534 | \r | |
535 | // We don't want to keep closure and scope references on the Event prototype!\r | |
536 | fireInfo.fn = fireInfo.scope = null;\r | |
537 | }\r | |
538 | \r | |
539 | listener.task.delay(o.buffer, handler, scope, toArray(arguments));\r | |
540 | };\r | |
541 | },\r | |
542 | \r | |
543 | createDelayed: function (handler, listener, o, scope, wrapped) {\r | |
544 | return function() {\r | |
545 | var task = new Ext.util.DelayedTask(),\r | |
546 | fireInfo;\r | |
547 | \r | |
548 | if (!wrapped) {\r | |
549 | fireInfo = listener.ev.getFireInfo(listener, true);\r | |
550 | handler = fireInfo.fn;\r | |
551 | scope = fireInfo.scope;\r | |
552 | \r | |
553 | // We don't want to keep closure and scope references on the Event prototype!\r | |
554 | fireInfo.fn = fireInfo.scope = null;\r | |
555 | }\r | |
556 | \r | |
557 | if (!listener.tasks) {\r | |
558 | listener.tasks = [];\r | |
559 | }\r | |
560 | listener.tasks.push(task);\r | |
561 | task.delay(o.delay || 10, handler, scope, toArray(arguments));\r | |
562 | };\r | |
563 | },\r | |
564 | \r | |
565 | createSingle: function (handler, listener, o, scope, wrapped) {\r | |
566 | return function() {\r | |
567 | var event = listener.ev,\r | |
568 | fireInfo;\r | |
569 | \r | |
570 | \r | |
571 | if (event.removeListener(listener.fn, scope) && event.observable) {\r | |
572 | // Removing from a regular Observable-owned, named event (not an anonymous\r | |
573 | // event such as Ext's readyEvent): Decrement the listeners count\r | |
574 | event.observable.hasListeners[event.name]--;\r | |
575 | }\r | |
576 | \r | |
577 | if (!wrapped) {\r | |
578 | fireInfo = event.getFireInfo(listener, true);\r | |
579 | handler = fireInfo.fn;\r | |
580 | scope = fireInfo.scope;\r | |
581 | \r | |
582 | // We don't want to keep closure and scope references on the Event prototype!\r | |
583 | fireInfo.fn = fireInfo.scope = null;\r | |
584 | }\r | |
585 | \r | |
586 | return handler.apply(scope, arguments);\r | |
587 | };\r | |
588 | }\r | |
589 | };\r | |
590 | });\r |