adhearsion 0.7.6 → 0.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. data/.version +1 -1
  2. data/CHANGELOG +43 -25
  3. data/Rakefile +0 -5
  4. data/TODO +51 -2
  5. data/ahn +2 -1
  6. data/apps/default/Rakefile +16 -7
  7. data/apps/default/config/adhearsion.yml +22 -1
  8. data/apps/default/config/helpers/manager_proxy.yml +1 -0
  9. data/apps/default/config/helpers/micromenus/images/arrow-off.gif +0 -0
  10. data/apps/default/config/helpers/micromenus/images/arrow-on.gif +0 -0
  11. data/apps/default/config/helpers/micromenus/images/error.gif +0 -0
  12. data/apps/default/config/helpers/micromenus/images/folder-off.gif +0 -0
  13. data/apps/default/config/helpers/micromenus/images/folder-on.gif +0 -0
  14. data/apps/default/config/helpers/micromenus/images/folder.png +0 -0
  15. data/apps/default/config/helpers/micromenus/images/ggbridge.jpg +0 -0
  16. data/apps/default/config/helpers/micromenus/images/green.png +0 -0
  17. data/apps/default/config/helpers/micromenus/images/microbrowser.bg.gif +0 -0
  18. data/apps/default/config/helpers/micromenus/images/red.png +0 -0
  19. data/apps/default/config/helpers/micromenus/images/url-off.gif +0 -0
  20. data/apps/default/config/helpers/micromenus/images/url-on.gif +0 -0
  21. data/apps/default/config/helpers/micromenus/images/yellow.png +0 -0
  22. data/apps/default/config/helpers/micromenus/javascripts/animation.js +1341 -0
  23. data/apps/default/config/helpers/micromenus/javascripts/carousel.js +1238 -0
  24. data/apps/default/config/helpers/micromenus/javascripts/columnav.js +306 -0
  25. data/apps/default/config/helpers/micromenus/javascripts/connection.js +965 -0
  26. data/apps/default/config/helpers/micromenus/javascripts/container.js +4727 -0
  27. data/apps/default/config/helpers/micromenus/javascripts/container_core.js +2915 -0
  28. data/apps/default/config/helpers/micromenus/javascripts/dom.js +892 -0
  29. data/apps/default/config/helpers/micromenus/javascripts/dragdrop.js +2921 -907
  30. data/apps/default/config/helpers/micromenus/javascripts/event.js +1771 -0
  31. data/apps/default/config/helpers/micromenus/javascripts/yahoo.js +433 -0
  32. data/apps/default/config/helpers/micromenus/stylesheets/carousel.css +78 -0
  33. data/apps/default/config/helpers/micromenus/stylesheets/columnav.css +135 -0
  34. data/apps/default/config/helpers/micromenus/stylesheets/microbrowsers.css +42 -0
  35. data/apps/default/config/helpers/multi_messenger.yml +5 -1
  36. data/apps/default/config/migration.rb +10 -0
  37. data/apps/default/extensions.rb +1 -1
  38. data/apps/default/helpers/factorial.alien.c +3 -3
  39. data/apps/default/helpers/lookup.rb +2 -1
  40. data/apps/default/helpers/manager_proxy.rb +67 -15
  41. data/apps/default/helpers/micromenus.rb +173 -31
  42. data/apps/default/helpers/multi_messenger.rb +20 -3
  43. data/lib/adhearsion.rb +218 -88
  44. data/lib/constants.rb +1 -0
  45. data/lib/core_extensions.rb +15 -9
  46. data/lib/phone_number.rb +85 -0
  47. data/lib/rami.rb +3 -2
  48. data/lib/servlet_container.rb +47 -24
  49. data/lib/sexy_migrations.rb +70 -0
  50. data/test/asterisk_module_test.rb +9 -9
  51. data/test/specs/numerical_string_spec.rb +53 -0
  52. metadata +31 -11
  53. data/apps/default/config/helpers/micromenus/javascripts/builder.js +0 -131
  54. data/apps/default/config/helpers/micromenus/javascripts/controls.js +0 -834
  55. data/apps/default/config/helpers/micromenus/javascripts/effects.js +0 -956
  56. data/apps/default/config/helpers/micromenus/javascripts/prototype.js +0 -2319
  57. data/apps/default/config/helpers/micromenus/javascripts/scriptaculous.js +0 -51
  58. data/apps/default/config/helpers/micromenus/javascripts/slider.js +0 -278
  59. data/apps/default/config/helpers/micromenus/javascripts/unittest.js +0 -557
  60. data/apps/default/config/helpers/micromenus/stylesheets/firefox.css +0 -10
  61. data/apps/default/config/helpers/micromenus/stylesheets/firefox.xul.css +0 -44
@@ -0,0 +1,1771 @@
1
+ /*
2
+ Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3
+ Code licensed under the BSD License:
4
+ http://developer.yahoo.net/yui/license.txt
5
+ version: 0.12.2
6
+ */
7
+ /**
8
+ * The CustomEvent class lets you define events for your application
9
+ * that can be subscribed to by one or more independent component.
10
+ *
11
+ * @param {String} type The type of event, which is passed to the callback
12
+ * when the event fires
13
+ * @param {Object} oScope The context the event will fire from. "this" will
14
+ * refer to this object in the callback. Default value:
15
+ * the window object. The listener can override this.
16
+ * @param {boolean} silent pass true to prevent the event from writing to
17
+ * the debugsystem
18
+ * @param {int} signature the signature that the custom event subscriber
19
+ * will receive. YAHOO.util.CustomEvent.LIST or
20
+ * YAHOO.util.CustomEvent.FLAT. The default is
21
+ * YAHOO.util.CustomEvent.LIST.
22
+ * @namespace YAHOO.util
23
+ * @class CustomEvent
24
+ * @constructor
25
+ */
26
+ YAHOO.util.CustomEvent = function(type, oScope, silent, signature) {
27
+
28
+ /**
29
+ * The type of event, returned to subscribers when the event fires
30
+ * @property type
31
+ * @type string
32
+ */
33
+ this.type = type;
34
+
35
+ /**
36
+ * The scope the the event will fire from by default. Defaults to the window
37
+ * obj
38
+ * @property scope
39
+ * @type object
40
+ */
41
+ this.scope = oScope || window;
42
+
43
+ /**
44
+ * By default all custom events are logged in the debug build, set silent
45
+ * to true to disable debug outpu for this event.
46
+ * @property silent
47
+ * @type boolean
48
+ */
49
+ this.silent = silent;
50
+
51
+ /**
52
+ * Custom events support two styles of arguments provided to the event
53
+ * subscribers.
54
+ * <ul>
55
+ * <li>YAHOO.util.CustomEvent.LIST:
56
+ * <ul>
57
+ * <li>param1: event name</li>
58
+ * <li>param2: array of arguments sent to fire</li>
59
+ * <li>param3: <optional> a custom object supplied by the subscriber</li>
60
+ * </ul>
61
+ * </li>
62
+ * <li>YAHOO.util.CustomEvent.FLAT
63
+ * <ul>
64
+ * <li>param1: the first argument passed to fire. If you need to
65
+ * pass multiple parameters, use and array or object literal</li>
66
+ * <li>param2: <optional> a custom object supplied by the subscriber</li>
67
+ * </ul>
68
+ * </li>
69
+ * </ul>
70
+ * @property signature
71
+ * @type int
72
+ */
73
+ this.signature = signature || YAHOO.util.CustomEvent.LIST;
74
+
75
+ /**
76
+ * The subscribers to this event
77
+ * @property subscribers
78
+ * @type Subscriber[]
79
+ */
80
+ this.subscribers = [];
81
+
82
+ if (!this.silent) {
83
+ }
84
+
85
+ var onsubscribeType = "_YUICEOnSubscribe";
86
+
87
+ // Only add subscribe events for events that are not generated by
88
+ // CustomEvent
89
+ if (type !== onsubscribeType) {
90
+
91
+ /**
92
+ * Custom events provide a custom event that fires whenever there is
93
+ * a new subscriber to the event. This provides an opportunity to
94
+ * handle the case where there is a non-repeating event that has
95
+ * already fired has a new subscriber.
96
+ *
97
+ * @event subscribeEvent
98
+ * @type YAHOO.util.CustomEvent
99
+ * @param {Function} fn The function to execute
100
+ * @param {Object} obj An object to be passed along when the event
101
+ * fires
102
+ * @param {boolean|Object} override If true, the obj passed in becomes
103
+ * the execution scope of the listener.
104
+ * if an object, that object becomes the
105
+ * the execution scope.
106
+ */
107
+ this.subscribeEvent =
108
+ new YAHOO.util.CustomEvent(onsubscribeType, this, true);
109
+
110
+ }
111
+ };
112
+
113
+ /**
114
+ * Subscriber listener sigature constant. The LIST type returns three
115
+ * parameters: the event type, the array of args passed to fire, and
116
+ * the optional custom object
117
+ * @property YAHOO.util.CustomEvent.LIST
118
+ * @static
119
+ * @type int
120
+ */
121
+ YAHOO.util.CustomEvent.LIST = 0;
122
+
123
+ /**
124
+ * Subscriber listener sigature constant. The FLAT type returns two
125
+ * parameters: the first argument passed to fire and the optional
126
+ * custom object
127
+ * @property YAHOO.util.CustomEvent.FLAT
128
+ * @static
129
+ * @type int
130
+ */
131
+ YAHOO.util.CustomEvent.FLAT = 1;
132
+
133
+ YAHOO.util.CustomEvent.prototype = {
134
+
135
+ /**
136
+ * Subscribes the caller to this event
137
+ * @method subscribe
138
+ * @param {Function} fn The function to execute
139
+ * @param {Object} obj An object to be passed along when the event
140
+ * fires
141
+ * @param {boolean|Object} override If true, the obj passed in becomes
142
+ * the execution scope of the listener.
143
+ * if an object, that object becomes the
144
+ * the execution scope.
145
+ */
146
+ subscribe: function(fn, obj, override) {
147
+ if (this.subscribeEvent) {
148
+ this.subscribeEvent.fire(fn, obj, override);
149
+ }
150
+
151
+ this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, override) );
152
+ },
153
+
154
+ /**
155
+ * Unsubscribes the caller from this event
156
+ * @method unsubscribe
157
+ * @param {Function} fn The function to execute
158
+ * @param {Object} obj The custom object passed to subscribe (optional)
159
+ * @return {boolean} True if the subscriber was found and detached.
160
+ */
161
+ unsubscribe: function(fn, obj) {
162
+ var found = false;
163
+ for (var i=0, len=this.subscribers.length; i<len; ++i) {
164
+ var s = this.subscribers[i];
165
+ if (s && s.contains(fn, obj)) {
166
+ this._delete(i);
167
+ found = true;
168
+ }
169
+ }
170
+
171
+ return found;
172
+ },
173
+
174
+ /**
175
+ * Notifies the subscribers. The callback functions will be executed
176
+ * from the scope specified when the event was created, and with the
177
+ * following parameters:
178
+ * <ul>
179
+ * <li>The type of event</li>
180
+ * <li>All of the arguments fire() was executed with as an array</li>
181
+ * <li>The custom object (if any) that was passed into the subscribe()
182
+ * method</li>
183
+ * </ul>
184
+ * @method fire
185
+ * @param {Object*} arguments an arbitrary set of parameters to pass to
186
+ * the handler.
187
+ * @return {boolean} false if one of the subscribers returned false,
188
+ * true otherwise
189
+ */
190
+ fire: function() {
191
+ var len=this.subscribers.length;
192
+ if (!len && this.silent) {
193
+ return true;
194
+ }
195
+
196
+ var args=[], ret=true, i;
197
+
198
+ for (i=0; i<arguments.length; ++i) {
199
+ args.push(arguments[i]);
200
+ }
201
+
202
+ var argslength = args.length;
203
+
204
+ if (!this.silent) {
205
+ }
206
+
207
+ for (i=0; i<len; ++i) {
208
+ var s = this.subscribers[i];
209
+ if (s) {
210
+ if (!this.silent) {
211
+ }
212
+
213
+ var scope = s.getScope(this.scope);
214
+
215
+ if (this.signature == YAHOO.util.CustomEvent.FLAT) {
216
+ var param = null;
217
+ if (args.length > 0) {
218
+ param = args[0];
219
+ }
220
+ ret = s.fn.call(scope, param, s.obj);
221
+ } else {
222
+ ret = s.fn.call(scope, this.type, args, s.obj);
223
+ }
224
+ if (false === ret) {
225
+ if (!this.silent) {
226
+ }
227
+
228
+ //break;
229
+ return false;
230
+ }
231
+ }
232
+ }
233
+
234
+ return true;
235
+ },
236
+
237
+ /**
238
+ * Removes all listeners
239
+ * @method unsubscribeAll
240
+ */
241
+ unsubscribeAll: function() {
242
+ for (var i=0, len=this.subscribers.length; i<len; ++i) {
243
+ this._delete(len - 1 - i);
244
+ }
245
+ },
246
+
247
+ /**
248
+ * @method _delete
249
+ * @private
250
+ */
251
+ _delete: function(index) {
252
+ var s = this.subscribers[index];
253
+ if (s) {
254
+ delete s.fn;
255
+ delete s.obj;
256
+ }
257
+
258
+ // delete this.subscribers[index];
259
+ this.subscribers.splice(index, 1);
260
+ },
261
+
262
+ /**
263
+ * @method toString
264
+ */
265
+ toString: function() {
266
+ return "CustomEvent: " + "'" + this.type + "', " +
267
+ "scope: " + this.scope;
268
+
269
+ }
270
+ };
271
+
272
+ /////////////////////////////////////////////////////////////////////
273
+
274
+ /**
275
+ * Stores the subscriber information to be used when the event fires.
276
+ * @param {Function} fn The function to execute
277
+ * @param {Object} obj An object to be passed along when the event fires
278
+ * @param {boolean} override If true, the obj passed in becomes the execution
279
+ * scope of the listener
280
+ * @class Subscriber
281
+ * @constructor
282
+ */
283
+ YAHOO.util.Subscriber = function(fn, obj, override) {
284
+
285
+ /**
286
+ * The callback that will be execute when the event fires
287
+ * @property fn
288
+ * @type function
289
+ */
290
+ this.fn = fn;
291
+
292
+ /**
293
+ * An optional custom object that will passed to the callback when
294
+ * the event fires
295
+ * @property obj
296
+ * @type object
297
+ */
298
+ this.obj = obj || null;
299
+
300
+ /**
301
+ * The default execution scope for the event listener is defined when the
302
+ * event is created (usually the object which contains the event).
303
+ * By setting override to true, the execution scope becomes the custom
304
+ * object passed in by the subscriber. If override is an object, that
305
+ * object becomes the scope.
306
+ * @property override
307
+ * @type boolean|object
308
+ */
309
+ this.override = override;
310
+
311
+ };
312
+
313
+ /**
314
+ * Returns the execution scope for this listener. If override was set to true
315
+ * the custom obj will be the scope. If override is an object, that is the
316
+ * scope, otherwise the default scope will be used.
317
+ * @method getScope
318
+ * @param {Object} defaultScope the scope to use if this listener does not
319
+ * override it.
320
+ */
321
+ YAHOO.util.Subscriber.prototype.getScope = function(defaultScope) {
322
+ if (this.override) {
323
+ if (this.override === true) {
324
+ return this.obj;
325
+ } else {
326
+ return this.override;
327
+ }
328
+ }
329
+ return defaultScope;
330
+ };
331
+
332
+ /**
333
+ * Returns true if the fn and obj match this objects properties.
334
+ * Used by the unsubscribe method to match the right subscriber.
335
+ *
336
+ * @method contains
337
+ * @param {Function} fn the function to execute
338
+ * @param {Object} obj an object to be passed along when the event fires
339
+ * @return {boolean} true if the supplied arguments match this
340
+ * subscriber's signature.
341
+ */
342
+ YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
343
+ if (obj) {
344
+ return (this.fn == fn && this.obj == obj);
345
+ } else {
346
+ return (this.fn == fn);
347
+ }
348
+ };
349
+
350
+ /**
351
+ * @method toString
352
+ */
353
+ YAHOO.util.Subscriber.prototype.toString = function() {
354
+ return "Subscriber { obj: " + (this.obj || "") +
355
+ ", override: " + (this.override || "no") + " }";
356
+ };
357
+
358
+ /**
359
+ * The Event Utility provides utilities for managing DOM Events and tools
360
+ * for building event systems
361
+ *
362
+ * @module event
363
+ * @title Event Utility
364
+ * @namespace YAHOO.util
365
+ * @requires yahoo
366
+ */
367
+
368
+ // The first instance of Event will win if it is loaded more than once.
369
+ if (!YAHOO.util.Event) {
370
+
371
+ /**
372
+ * The event utility provides functions to add and remove event listeners,
373
+ * event cleansing. It also tries to automatically remove listeners it
374
+ * registers during the unload event.
375
+ *
376
+ * @class Event
377
+ * @static
378
+ */
379
+ YAHOO.util.Event = function() {
380
+
381
+ /**
382
+ * True after the onload event has fired
383
+ * @property loadComplete
384
+ * @type boolean
385
+ * @static
386
+ * @private
387
+ */
388
+ var loadComplete = false;
389
+
390
+ /**
391
+ * Cache of wrapped listeners
392
+ * @property listeners
393
+ * @type array
394
+ * @static
395
+ * @private
396
+ */
397
+ var listeners = [];
398
+
399
+ /**
400
+ * User-defined unload function that will be fired before all events
401
+ * are detached
402
+ * @property unloadListeners
403
+ * @type array
404
+ * @static
405
+ * @private
406
+ */
407
+ var unloadListeners = [];
408
+
409
+ /**
410
+ * Cache of DOM0 event handlers to work around issues with DOM2 events
411
+ * in Safari
412
+ * @property legacyEvents
413
+ * @static
414
+ * @private
415
+ */
416
+ var legacyEvents = [];
417
+
418
+ /**
419
+ * Listener stack for DOM0 events
420
+ * @property legacyHandlers
421
+ * @static
422
+ * @private
423
+ */
424
+ var legacyHandlers = [];
425
+
426
+ /**
427
+ * The number of times to poll after window.onload. This number is
428
+ * increased if additional late-bound handlers are requested after
429
+ * the page load.
430
+ * @property retryCount
431
+ * @static
432
+ * @private
433
+ */
434
+ var retryCount = 0;
435
+
436
+ /**
437
+ * onAvailable listeners
438
+ * @property onAvailStack
439
+ * @static
440
+ * @private
441
+ */
442
+ var onAvailStack = [];
443
+
444
+ /**
445
+ * Lookup table for legacy events
446
+ * @property legacyMap
447
+ * @static
448
+ * @private
449
+ */
450
+ var legacyMap = [];
451
+
452
+ /**
453
+ * Counter for auto id generation
454
+ * @property counter
455
+ * @static
456
+ * @private
457
+ */
458
+ var counter = 0;
459
+
460
+ return { // PREPROCESS
461
+
462
+ /**
463
+ * The number of times we should look for elements that are not
464
+ * in the DOM at the time the event is requested after the document
465
+ * has been loaded. The default is 200@amp;50 ms, so it will poll
466
+ * for 10 seconds or until all outstanding handlers are bound
467
+ * (whichever comes first).
468
+ * @property POLL_RETRYS
469
+ * @type int
470
+ * @static
471
+ * @final
472
+ */
473
+ POLL_RETRYS: 200,
474
+
475
+ /**
476
+ * The poll interval in milliseconds
477
+ * @property POLL_INTERVAL
478
+ * @type int
479
+ * @static
480
+ * @final
481
+ */
482
+ POLL_INTERVAL: 20,
483
+
484
+ /**
485
+ * Element to bind, int constant
486
+ * @property EL
487
+ * @type int
488
+ * @static
489
+ * @final
490
+ */
491
+ EL: 0,
492
+
493
+ /**
494
+ * Type of event, int constant
495
+ * @property TYPE
496
+ * @type int
497
+ * @static
498
+ * @final
499
+ */
500
+ TYPE: 1,
501
+
502
+ /**
503
+ * Function to execute, int constant
504
+ * @property FN
505
+ * @type int
506
+ * @static
507
+ * @final
508
+ */
509
+ FN: 2,
510
+
511
+ /**
512
+ * Function wrapped for scope correction and cleanup, int constant
513
+ * @property WFN
514
+ * @type int
515
+ * @static
516
+ * @final
517
+ */
518
+ WFN: 3,
519
+
520
+ /**
521
+ * Object passed in by the user that will be returned as a
522
+ * parameter to the callback, int constant
523
+ * @property OBJ
524
+ * @type int
525
+ * @static
526
+ * @final
527
+ */
528
+ OBJ: 3,
529
+
530
+ /**
531
+ * Adjusted scope, either the element we are registering the event
532
+ * on or the custom object passed in by the listener, int constant
533
+ * @property ADJ_SCOPE
534
+ * @type int
535
+ * @static
536
+ * @final
537
+ */
538
+ ADJ_SCOPE: 4,
539
+
540
+ /**
541
+ * Safari detection is necessary to work around the preventDefault
542
+ * bug that makes it so you can't cancel a href click from the
543
+ * handler. There is not a capabilities check we can use here.
544
+ * @property isSafari
545
+ * @private
546
+ * @static
547
+ */
548
+ isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
549
+
550
+ /**
551
+ * IE detection needed to properly calculate pageX and pageY.
552
+ * capabilities checking didn't seem to work because another
553
+ * browser that does not provide the properties have the values
554
+ * calculated in a different manner than IE.
555
+ * @property isIE
556
+ * @private
557
+ * @static
558
+ */
559
+ isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
560
+ navigator.userAgent.match(/msie/gi)),
561
+
562
+ /**
563
+ * poll handle
564
+ * @property _interval
565
+ * @private
566
+ */
567
+ _interval: null,
568
+
569
+ /**
570
+ * @method startInterval
571
+ * @static
572
+ * @private
573
+ */
574
+ startInterval: function() {
575
+ if (!this._interval) {
576
+ var self = this;
577
+ var callback = function() { self._tryPreloadAttach(); };
578
+ this._interval = setInterval(callback, this.POLL_INTERVAL);
579
+ // this.timeout = setTimeout(callback, i);
580
+ }
581
+ },
582
+
583
+ /**
584
+ * Executes the supplied callback when the item with the supplied
585
+ * id is found. This is meant to be used to execute behavior as
586
+ * soon as possible as the page loads. If you use this after the
587
+ * initial page load it will poll for a fixed time for the element.
588
+ * The number of times it will poll and the frequency are
589
+ * configurable. By default it will poll for 10 seconds.
590
+ *
591
+ * @method onAvailable
592
+ *
593
+ * @param {string} p_id the id of the element to look for.
594
+ * @param {function} p_fn what to execute when the element is found.
595
+ * @param {object} p_obj an optional object to be passed back as
596
+ * a parameter to p_fn.
597
+ * @param {boolean} p_override If set to true, p_fn will execute
598
+ * in the scope of p_obj
599
+ *
600
+ * @static
601
+ */
602
+ onAvailable: function(p_id, p_fn, p_obj, p_override) {
603
+ onAvailStack.push( { id: p_id,
604
+ fn: p_fn,
605
+ obj: p_obj,
606
+ override: p_override,
607
+ checkReady: false } );
608
+
609
+ retryCount = this.POLL_RETRYS;
610
+ this.startInterval();
611
+ },
612
+
613
+ /**
614
+ * Works the same way as onAvailable, but additionally checks the
615
+ * state of sibling elements to determine if the content of the
616
+ * available element is safe to modify.
617
+ *
618
+ * @method onContentReady
619
+ *
620
+ * @param {string} p_id the id of the element to look for.
621
+ * @param {function} p_fn what to execute when the element is ready.
622
+ * @param {object} p_obj an optional object to be passed back as
623
+ * a parameter to p_fn.
624
+ * @param {boolean} p_override If set to true, p_fn will execute
625
+ * in the scope of p_obj
626
+ *
627
+ * @static
628
+ */
629
+ onContentReady: function(p_id, p_fn, p_obj, p_override) {
630
+ onAvailStack.push( { id: p_id,
631
+ fn: p_fn,
632
+ obj: p_obj,
633
+ override: p_override,
634
+ checkReady: true } );
635
+
636
+ retryCount = this.POLL_RETRYS;
637
+ this.startInterval();
638
+ },
639
+
640
+ /**
641
+ * Appends an event handler
642
+ *
643
+ * @method addListener
644
+ *
645
+ * @param {Object} el The html element to assign the
646
+ * event to
647
+ * @param {String} sType The type of event to append
648
+ * @param {Function} fn The method the event invokes
649
+ * @param {Object} obj An arbitrary object that will be
650
+ * passed as a parameter to the handler
651
+ * @param {boolean} override If true, the obj passed in becomes
652
+ * the execution scope of the listener
653
+ * @return {boolean} True if the action was successful or defered,
654
+ * false if one or more of the elements
655
+ * could not have the listener attached,
656
+ * or if the operation throws an exception.
657
+ * @static
658
+ */
659
+ addListener: function(el, sType, fn, obj, override) {
660
+
661
+ if (!fn || !fn.call) {
662
+ return false;
663
+ }
664
+
665
+ // The el argument can be an array of elements or element ids.
666
+ if ( this._isValidCollection(el)) {
667
+ var ok = true;
668
+ for (var i=0,len=el.length; i<len; ++i) {
669
+ ok = this.on(el[i],
670
+ sType,
671
+ fn,
672
+ obj,
673
+ override) && ok;
674
+ }
675
+ return ok;
676
+
677
+ } else if (typeof el == "string") {
678
+ var oEl = this.getEl(el);
679
+ // If the el argument is a string, we assume it is
680
+ // actually the id of the element. If the page is loaded
681
+ // we convert el to the actual element, otherwise we
682
+ // defer attaching the event until onload event fires
683
+
684
+ // check to see if we need to delay hooking up the event
685
+ // until after the page loads.
686
+ if (oEl) {
687
+ el = oEl;
688
+ } else {
689
+ // defer adding the event until the element is available
690
+ this.onAvailable(el, function() {
691
+ YAHOO.util.Event.on(el, sType, fn, obj, override);
692
+ });
693
+
694
+ return true;
695
+ }
696
+ }
697
+
698
+ // Element should be an html element or an array if we get
699
+ // here.
700
+ if (!el) {
701
+ return false;
702
+ }
703
+
704
+ // we need to make sure we fire registered unload events
705
+ // prior to automatically unhooking them. So we hang on to
706
+ // these instead of attaching them to the window and fire the
707
+ // handles explicitly during our one unload event.
708
+ if ("unload" == sType && obj !== this) {
709
+ unloadListeners[unloadListeners.length] =
710
+ [el, sType, fn, obj, override];
711
+ return true;
712
+ }
713
+
714
+
715
+ // if the user chooses to override the scope, we use the custom
716
+ // object passed in, otherwise the executing scope will be the
717
+ // HTML element that the event is registered on
718
+ var scope = el;
719
+ if (override) {
720
+ if (override === true) {
721
+ scope = obj;
722
+ } else {
723
+ scope = override;
724
+ }
725
+ }
726
+
727
+ // wrap the function so we can return the obj object when
728
+ // the event fires;
729
+ var wrappedFn = function(e) {
730
+ return fn.call(scope, YAHOO.util.Event.getEvent(e),
731
+ obj);
732
+ };
733
+
734
+ var li = [el, sType, fn, wrappedFn, scope];
735
+ var index = listeners.length;
736
+ // cache the listener so we can try to automatically unload
737
+ listeners[index] = li;
738
+
739
+ if (this.useLegacyEvent(el, sType)) {
740
+ var legacyIndex = this.getLegacyIndex(el, sType);
741
+
742
+ // Add a new dom0 wrapper if one is not detected for this
743
+ // element
744
+ if ( legacyIndex == -1 ||
745
+ el != legacyEvents[legacyIndex][0] ) {
746
+
747
+ legacyIndex = legacyEvents.length;
748
+ legacyMap[el.id + sType] = legacyIndex;
749
+
750
+ // cache the signature for the DOM0 event, and
751
+ // include the existing handler for the event, if any
752
+ legacyEvents[legacyIndex] =
753
+ [el, sType, el["on" + sType]];
754
+ legacyHandlers[legacyIndex] = [];
755
+
756
+ el["on" + sType] =
757
+ function(e) {
758
+ YAHOO.util.Event.fireLegacyEvent(
759
+ YAHOO.util.Event.getEvent(e), legacyIndex);
760
+ };
761
+ }
762
+
763
+ // add a reference to the wrapped listener to our custom
764
+ // stack of events
765
+ //legacyHandlers[legacyIndex].push(index);
766
+ legacyHandlers[legacyIndex].push(li);
767
+
768
+ } else {
769
+ try {
770
+ this._simpleAdd(el, sType, wrappedFn, false);
771
+ } catch(e) {
772
+ // handle an error trying to attach an event. If it fails
773
+ // we need to clean up the cache
774
+ this.removeListener(el, sType, fn);
775
+ return false;
776
+ }
777
+ }
778
+
779
+ return true;
780
+
781
+ },
782
+
783
+ /**
784
+ * When using legacy events, the handler is routed to this object
785
+ * so we can fire our custom listener stack.
786
+ * @method fireLegacyEvent
787
+ * @static
788
+ * @private
789
+ */
790
+ fireLegacyEvent: function(e, legacyIndex) {
791
+ var ok = true;
792
+
793
+ var le = legacyHandlers[legacyIndex];
794
+ for (var i=0,len=le.length; i<len; ++i) {
795
+ var li = le[i];
796
+ if ( li && li[this.WFN] ) {
797
+ var scope = li[this.ADJ_SCOPE];
798
+ var ret = li[this.WFN].call(scope, e);
799
+ ok = (ok && ret);
800
+ }
801
+ }
802
+
803
+ return ok;
804
+ },
805
+
806
+ /**
807
+ * Returns the legacy event index that matches the supplied
808
+ * signature
809
+ * @method getLegacyIndex
810
+ * @static
811
+ * @private
812
+ */
813
+ getLegacyIndex: function(el, sType) {
814
+ var key = this.generateId(el) + sType;
815
+ if (typeof legacyMap[key] == "undefined") {
816
+ return -1;
817
+ } else {
818
+ return legacyMap[key];
819
+ }
820
+ },
821
+
822
+ /**
823
+ * Logic that determines when we should automatically use legacy
824
+ * events instead of DOM2 events.
825
+ * @method useLegacyEvent
826
+ * @static
827
+ * @private
828
+ */
829
+ useLegacyEvent: function(el, sType) {
830
+ if (!el.addEventListener && !el.attachEvent) {
831
+ return true;
832
+ } else if (this.isSafari) {
833
+ if ("click" == sType || "dblclick" == sType) {
834
+ return true;
835
+ }
836
+ }
837
+ return false;
838
+ },
839
+
840
+ /**
841
+ * Removes an event handler
842
+ *
843
+ * @method removeListener
844
+ *
845
+ * @param {Object} el the html element or the id of the element to
846
+ * assign the event to.
847
+ * @param {String} sType the type of event to remove.
848
+ * @param {Function} fn the method the event invokes. If fn is
849
+ * undefined, then all event handlers for the type of event are
850
+ * removed.
851
+ * @return {boolean} true if the unbind was successful, false
852
+ * otherwise.
853
+ * @static
854
+ */
855
+ removeListener: function(el, sType, fn) {
856
+ var i, len;
857
+
858
+ // The el argument can be a string
859
+ if (typeof el == "string") {
860
+ el = this.getEl(el);
861
+ // The el argument can be an array of elements or element ids.
862
+ } else if ( this._isValidCollection(el)) {
863
+ var ok = true;
864
+ for (i=0,len=el.length; i<len; ++i) {
865
+ ok = ( this.removeListener(el[i], sType, fn) && ok );
866
+ }
867
+ return ok;
868
+ }
869
+
870
+ if (!fn || !fn.call) {
871
+ //return false;
872
+ return this.purgeElement(el, false, sType);
873
+ }
874
+
875
+ if ("unload" == sType) {
876
+
877
+ for (i=0, len=unloadListeners.length; i<len; i++) {
878
+ var li = unloadListeners[i];
879
+ if (li &&
880
+ li[0] == el &&
881
+ li[1] == sType &&
882
+ li[2] == fn) {
883
+ unloadListeners.splice(i, 1);
884
+ return true;
885
+ }
886
+ }
887
+
888
+ return false;
889
+ }
890
+
891
+ var cacheItem = null;
892
+
893
+ // The index is a hidden parameter; needed to remove it from
894
+ // the method signature because it was tempting users to
895
+ // try and take advantage of it, which is not possible.
896
+ var index = arguments[3];
897
+
898
+ if ("undefined" == typeof index) {
899
+ index = this._getCacheIndex(el, sType, fn);
900
+ }
901
+
902
+ if (index >= 0) {
903
+ cacheItem = listeners[index];
904
+ }
905
+
906
+ if (!el || !cacheItem) {
907
+ return false;
908
+ }
909
+
910
+
911
+ if (this.useLegacyEvent(el, sType)) {
912
+ var legacyIndex = this.getLegacyIndex(el, sType);
913
+ var llist = legacyHandlers[legacyIndex];
914
+ if (llist) {
915
+ for (i=0, len=llist.length; i<len; ++i) {
916
+ li = llist[i];
917
+ if (li &&
918
+ li[this.EL] == el &&
919
+ li[this.TYPE] == sType &&
920
+ li[this.FN] == fn) {
921
+ llist.splice(i, 1);
922
+ break;
923
+ }
924
+ }
925
+ }
926
+
927
+ } else {
928
+ try {
929
+ this._simpleRemove(el, sType, cacheItem[this.WFN], false);
930
+ } catch(e) {
931
+ return false;
932
+ }
933
+ }
934
+
935
+ // removed the wrapped handler
936
+ delete listeners[index][this.WFN];
937
+ delete listeners[index][this.FN];
938
+ listeners.splice(index, 1);
939
+
940
+ return true;
941
+
942
+ },
943
+
944
+ /**
945
+ * Returns the event's target element
946
+ * @method getTarget
947
+ * @param {Event} ev the event
948
+ * @param {boolean} resolveTextNode when set to true the target's
949
+ * parent will be returned if the target is a
950
+ * text node. @deprecated, the text node is
951
+ * now resolved automatically
952
+ * @return {HTMLElement} the event's target
953
+ * @static
954
+ */
955
+ getTarget: function(ev, resolveTextNode) {
956
+ var t = ev.target || ev.srcElement;
957
+ return this.resolveTextNode(t);
958
+ },
959
+
960
+ /**
961
+ * In some cases, some browsers will return a text node inside
962
+ * the actual element that was targeted. This normalizes the
963
+ * return value for getTarget and getRelatedTarget.
964
+ * @method resolveTextNode
965
+ * @param {HTMLElement} node node to resolve
966
+ * @return {HTMLElement} the normized node
967
+ * @static
968
+ */
969
+ resolveTextNode: function(node) {
970
+ // if (node && node.nodeName &&
971
+ // "#TEXT" == node.nodeName.toUpperCase()) {
972
+ if (node && 3 == node.nodeType) {
973
+ return node.parentNode;
974
+ } else {
975
+ return node;
976
+ }
977
+ },
978
+
979
+ /**
980
+ * Returns the event's pageX
981
+ * @method getPageX
982
+ * @param {Event} ev the event
983
+ * @return {int} the event's pageX
984
+ * @static
985
+ */
986
+ getPageX: function(ev) {
987
+ var x = ev.pageX;
988
+ if (!x && 0 !== x) {
989
+ x = ev.clientX || 0;
990
+
991
+ if ( this.isIE ) {
992
+ x += this._getScrollLeft();
993
+ }
994
+ }
995
+
996
+ return x;
997
+ },
998
+
999
+ /**
1000
+ * Returns the event's pageY
1001
+ * @method getPageY
1002
+ * @param {Event} ev the event
1003
+ * @return {int} the event's pageY
1004
+ * @static
1005
+ */
1006
+ getPageY: function(ev) {
1007
+ var y = ev.pageY;
1008
+ if (!y && 0 !== y) {
1009
+ y = ev.clientY || 0;
1010
+
1011
+ if ( this.isIE ) {
1012
+ y += this._getScrollTop();
1013
+ }
1014
+ }
1015
+
1016
+ return y;
1017
+ },
1018
+
1019
+ /**
1020
+ * Returns the pageX and pageY properties as an indexed array.
1021
+ * @method getXY
1022
+ * @param {Event} ev the event
1023
+ * @return {[x, y]} the pageX and pageY properties of the event
1024
+ * @static
1025
+ */
1026
+ getXY: function(ev) {
1027
+ return [this.getPageX(ev), this.getPageY(ev)];
1028
+ },
1029
+
1030
+ /**
1031
+ * Returns the event's related target
1032
+ * @method getRelatedTarget
1033
+ * @param {Event} ev the event
1034
+ * @return {HTMLElement} the event's relatedTarget
1035
+ * @static
1036
+ */
1037
+ getRelatedTarget: function(ev) {
1038
+ var t = ev.relatedTarget;
1039
+ if (!t) {
1040
+ if (ev.type == "mouseout") {
1041
+ t = ev.toElement;
1042
+ } else if (ev.type == "mouseover") {
1043
+ t = ev.fromElement;
1044
+ }
1045
+ }
1046
+
1047
+ return this.resolveTextNode(t);
1048
+ },
1049
+
1050
+ /**
1051
+ * Returns the time of the event. If the time is not included, the
1052
+ * event is modified using the current time.
1053
+ * @method getTime
1054
+ * @param {Event} ev the event
1055
+ * @return {Date} the time of the event
1056
+ * @static
1057
+ */
1058
+ getTime: function(ev) {
1059
+ if (!ev.time) {
1060
+ var t = new Date().getTime();
1061
+ try {
1062
+ ev.time = t;
1063
+ } catch(e) {
1064
+ return t;
1065
+ }
1066
+ }
1067
+
1068
+ return ev.time;
1069
+ },
1070
+
1071
+ /**
1072
+ * Convenience method for stopPropagation + preventDefault
1073
+ * @method stopEvent
1074
+ * @param {Event} ev the event
1075
+ * @static
1076
+ */
1077
+ stopEvent: function(ev) {
1078
+ this.stopPropagation(ev);
1079
+ this.preventDefault(ev);
1080
+ },
1081
+
1082
+ /**
1083
+ * Stops event propagation
1084
+ * @method stopPropagation
1085
+ * @param {Event} ev the event
1086
+ * @static
1087
+ */
1088
+ stopPropagation: function(ev) {
1089
+ if (ev.stopPropagation) {
1090
+ ev.stopPropagation();
1091
+ } else {
1092
+ ev.cancelBubble = true;
1093
+ }
1094
+ },
1095
+
1096
+ /**
1097
+ * Prevents the default behavior of the event
1098
+ * @method preventDefault
1099
+ * @param {Event} ev the event
1100
+ * @static
1101
+ */
1102
+ preventDefault: function(ev) {
1103
+ if (ev.preventDefault) {
1104
+ ev.preventDefault();
1105
+ } else {
1106
+ ev.returnValue = false;
1107
+ }
1108
+ },
1109
+
1110
+ /**
1111
+ * Finds the event in the window object, the caller's arguments, or
1112
+ * in the arguments of another method in the callstack. This is
1113
+ * executed automatically for events registered through the event
1114
+ * manager, so the implementer should not normally need to execute
1115
+ * this function at all.
1116
+ * @method getEvent
1117
+ * @param {Event} e the event parameter from the handler
1118
+ * @return {Event} the event
1119
+ * @static
1120
+ */
1121
+ getEvent: function(e) {
1122
+ var ev = e || window.event;
1123
+
1124
+ if (!ev) {
1125
+ var c = this.getEvent.caller;
1126
+ while (c) {
1127
+ ev = c.arguments[0];
1128
+ if (ev && Event == ev.constructor) {
1129
+ break;
1130
+ }
1131
+ c = c.caller;
1132
+ }
1133
+ }
1134
+
1135
+ return ev;
1136
+ },
1137
+
1138
+ /**
1139
+ * Returns the charcode for an event
1140
+ * @method getCharCode
1141
+ * @param {Event} ev the event
1142
+ * @return {int} the event's charCode
1143
+ * @static
1144
+ */
1145
+ getCharCode: function(ev) {
1146
+ return ev.charCode || ev.keyCode || 0;
1147
+ },
1148
+
1149
+ /**
1150
+ * Locating the saved event handler data by function ref
1151
+ *
1152
+ * @method _getCacheIndex
1153
+ * @static
1154
+ * @private
1155
+ */
1156
+ _getCacheIndex: function(el, sType, fn) {
1157
+ for (var i=0,len=listeners.length; i<len; ++i) {
1158
+ var li = listeners[i];
1159
+ if ( li &&
1160
+ li[this.FN] == fn &&
1161
+ li[this.EL] == el &&
1162
+ li[this.TYPE] == sType ) {
1163
+ return i;
1164
+ }
1165
+ }
1166
+
1167
+ return -1;
1168
+ },
1169
+
1170
+ /**
1171
+ * Generates an unique ID for the element if it does not already
1172
+ * have one.
1173
+ * @method generateId
1174
+ * @param el the element to create the id for
1175
+ * @return {string} the resulting id of the element
1176
+ * @static
1177
+ */
1178
+ generateId: function(el) {
1179
+ var id = el.id;
1180
+
1181
+ if (!id) {
1182
+ id = "yuievtautoid-" + counter;
1183
+ ++counter;
1184
+ el.id = id;
1185
+ }
1186
+
1187
+ return id;
1188
+ },
1189
+
1190
+ /**
1191
+ * We want to be able to use getElementsByTagName as a collection
1192
+ * to attach a group of events to. Unfortunately, different
1193
+ * browsers return different types of collections. This function
1194
+ * tests to determine if the object is array-like. It will also
1195
+ * fail if the object is an array, but is empty.
1196
+ * @method _isValidCollection
1197
+ * @param o the object to test
1198
+ * @return {boolean} true if the object is array-like and populated
1199
+ * @static
1200
+ * @private
1201
+ */
1202
+ _isValidCollection: function(o) {
1203
+ // this.logger.debug(o.constructor.toString())
1204
+ // this.logger.debug(typeof o)
1205
+
1206
+ return ( o && // o is something
1207
+ o.length && // o is indexed
1208
+ typeof o != "string" && // o is not a string
1209
+ !o.tagName && // o is not an HTML element
1210
+ !o.alert && // o is not a window
1211
+ typeof o[0] != "undefined" );
1212
+
1213
+ },
1214
+
1215
+ /**
1216
+ * @private
1217
+ * @property elCache
1218
+ * DOM element cache
1219
+ * @static
1220
+ */
1221
+ elCache: {},
1222
+
1223
+ /**
1224
+ * We cache elements bound by id because when the unload event
1225
+ * fires, we can no longer use document.getElementById
1226
+ * @method getEl
1227
+ * @static
1228
+ * @private
1229
+ */
1230
+ getEl: function(id) {
1231
+ return document.getElementById(id);
1232
+ },
1233
+
1234
+ /**
1235
+ * Clears the element cache
1236
+ * @deprecated Elements are not cached any longer
1237
+ * @method clearCache
1238
+ * @static
1239
+ * @private
1240
+ */
1241
+ clearCache: function() { },
1242
+
1243
+ /**
1244
+ * hook up any deferred listeners
1245
+ * @method _load
1246
+ * @static
1247
+ * @private
1248
+ */
1249
+ _load: function(e) {
1250
+ loadComplete = true;
1251
+ var EU = YAHOO.util.Event;
1252
+ // Remove the listener to assist with the IE memory issue, but not
1253
+ // for other browsers because FF 1.0x does not like it.
1254
+ if (this.isIE) {
1255
+ EU._simpleRemove(window, "load", EU._load);
1256
+ }
1257
+ },
1258
+
1259
+ /**
1260
+ * Polling function that runs before the onload event fires,
1261
+ * attempting to attach to DOM Nodes as soon as they are
1262
+ * available
1263
+ * @method _tryPreloadAttach
1264
+ * @static
1265
+ * @private
1266
+ */
1267
+ _tryPreloadAttach: function() {
1268
+
1269
+ if (this.locked) {
1270
+ return false;
1271
+ }
1272
+
1273
+ this.locked = true;
1274
+
1275
+
1276
+ // keep trying until after the page is loaded. We need to
1277
+ // check the page load state prior to trying to bind the
1278
+ // elements so that we can be certain all elements have been
1279
+ // tested appropriately
1280
+ var tryAgain = !loadComplete;
1281
+ if (!tryAgain) {
1282
+ tryAgain = (retryCount > 0);
1283
+ }
1284
+
1285
+ // onAvailable
1286
+ var notAvail = [];
1287
+ for (var i=0,len=onAvailStack.length; i<len ; ++i) {
1288
+ var item = onAvailStack[i];
1289
+ if (item) {
1290
+ var el = this.getEl(item.id);
1291
+
1292
+ if (el) {
1293
+ // The element is available, but not necessarily ready
1294
+ // @todo verify IE7 compatibility
1295
+ // @todo should we test parentNode.nextSibling?
1296
+ // @todo re-evaluate global content ready
1297
+ if ( !item.checkReady ||
1298
+ loadComplete ||
1299
+ el.nextSibling ||
1300
+ (document && document.body) ) {
1301
+
1302
+ var scope = el;
1303
+ if (item.override) {
1304
+ if (item.override === true) {
1305
+ scope = item.obj;
1306
+ } else {
1307
+ scope = item.override;
1308
+ }
1309
+ }
1310
+ item.fn.call(scope, item.obj);
1311
+ //delete onAvailStack[i];
1312
+ // null out instead of delete for Opera
1313
+ onAvailStack[i] = null;
1314
+ }
1315
+ } else {
1316
+ notAvail.push(item);
1317
+ }
1318
+ }
1319
+ }
1320
+
1321
+ retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
1322
+
1323
+ if (tryAgain) {
1324
+ // we may need to strip the nulled out items here
1325
+ this.startInterval();
1326
+ } else {
1327
+ clearInterval(this._interval);
1328
+ this._interval = null;
1329
+ }
1330
+
1331
+ this.locked = false;
1332
+
1333
+ return true;
1334
+
1335
+ },
1336
+
1337
+ /**
1338
+ * Removes all listeners attached to the given element via addListener.
1339
+ * Optionally, the node's children can also be purged.
1340
+ * Optionally, you can specify a specific type of event to remove.
1341
+ * @method purgeElement
1342
+ * @param {HTMLElement} el the element to purge
1343
+ * @param {boolean} recurse recursively purge this element's children
1344
+ * as well. Use with caution.
1345
+ * @param {string} sType optional type of listener to purge. If
1346
+ * left out, all listeners will be removed
1347
+ * @static
1348
+ */
1349
+ purgeElement: function(el, recurse, sType) {
1350
+ var elListeners = this.getListeners(el, sType);
1351
+ if (elListeners) {
1352
+ for (var i=0,len=elListeners.length; i<len ; ++i) {
1353
+ var l = elListeners[i];
1354
+ // can't use the index on the changing collection
1355
+ //this.removeListener(el, l.type, l.fn, l.index);
1356
+ this.removeListener(el, l.type, l.fn);
1357
+ }
1358
+ }
1359
+
1360
+ if (recurse && el && el.childNodes) {
1361
+ for (i=0,len=el.childNodes.length; i<len ; ++i) {
1362
+ this.purgeElement(el.childNodes[i], recurse, sType);
1363
+ }
1364
+ }
1365
+ },
1366
+
1367
+ /**
1368
+ * Returns all listeners attached to the given element via addListener.
1369
+ * Optionally, you can specify a specific type of event to return.
1370
+ * @method getListeners
1371
+ * @param el {HTMLElement} the element to inspect
1372
+ * @param sType {string} optional type of listener to return. If
1373
+ * left out, all listeners will be returned
1374
+ * @return {Object} the listener. Contains the following fields:
1375
+ * &nbsp;&nbsp;type: (string) the type of event
1376
+ * &nbsp;&nbsp;fn: (function) the callback supplied to addListener
1377
+ * &nbsp;&nbsp;obj: (object) the custom object supplied to addListener
1378
+ * &nbsp;&nbsp;adjust: (boolean) whether or not to adjust the default scope
1379
+ * &nbsp;&nbsp;index: (int) its position in the Event util listener cache
1380
+ * @static
1381
+ */
1382
+ getListeners: function(el, sType) {
1383
+ var elListeners = [];
1384
+ if (listeners && listeners.length > 0) {
1385
+ for (var i=0,len=listeners.length; i<len ; ++i) {
1386
+ var l = listeners[i];
1387
+ if ( l && l[this.EL] === el &&
1388
+ (!sType || sType === l[this.TYPE]) ) {
1389
+ elListeners.push({
1390
+ type: l[this.TYPE],
1391
+ fn: l[this.FN],
1392
+ obj: l[this.OBJ],
1393
+ adjust: l[this.ADJ_SCOPE],
1394
+ index: i
1395
+ });
1396
+ }
1397
+ }
1398
+ }
1399
+
1400
+ return (elListeners.length) ? elListeners : null;
1401
+ },
1402
+
1403
+ /**
1404
+ * Removes all listeners registered by pe.event. Called
1405
+ * automatically during the unload event.
1406
+ * @method _unload
1407
+ * @static
1408
+ * @private
1409
+ */
1410
+ _unload: function(e) {
1411
+
1412
+ var EU = YAHOO.util.Event, i, j, l, len, index;
1413
+
1414
+ for (i=0,len=unloadListeners.length; i<len; ++i) {
1415
+ l = unloadListeners[i];
1416
+ if (l) {
1417
+ var scope = window;
1418
+ if (l[EU.ADJ_SCOPE]) {
1419
+ if (l[EU.ADJ_SCOPE] === true) {
1420
+ scope = l[EU.OBJ];
1421
+ } else {
1422
+ scope = l[EU.ADJ_SCOPE];
1423
+ }
1424
+ }
1425
+ l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ] );
1426
+ unloadListeners[i] = null;
1427
+ l=null;
1428
+ scope=null;
1429
+ }
1430
+ }
1431
+
1432
+ unloadListeners = null;
1433
+
1434
+ if (listeners && listeners.length > 0) {
1435
+ j = listeners.length;
1436
+ while (j) {
1437
+ index = j-1;
1438
+ l = listeners[index];
1439
+ if (l) {
1440
+ EU.removeListener(l[EU.EL], l[EU.TYPE],
1441
+ l[EU.FN], index);
1442
+ }
1443
+ j = j - 1;
1444
+ }
1445
+ l=null;
1446
+
1447
+ EU.clearCache();
1448
+ }
1449
+
1450
+ for (i=0,len=legacyEvents.length; i<len; ++i) {
1451
+ // dereference the element
1452
+ //delete legacyEvents[i][0];
1453
+ legacyEvents[i][0] = null;
1454
+
1455
+ // delete the array item
1456
+ //delete legacyEvents[i];
1457
+ legacyEvents[i] = null;
1458
+ }
1459
+
1460
+ legacyEvents = null;
1461
+
1462
+ EU._simpleRemove(window, "unload", EU._unload);
1463
+
1464
+ },
1465
+
1466
+ /**
1467
+ * Returns scrollLeft
1468
+ * @method _getScrollLeft
1469
+ * @static
1470
+ * @private
1471
+ */
1472
+ _getScrollLeft: function() {
1473
+ return this._getScroll()[1];
1474
+ },
1475
+
1476
+ /**
1477
+ * Returns scrollTop
1478
+ * @method _getScrollTop
1479
+ * @static
1480
+ * @private
1481
+ */
1482
+ _getScrollTop: function() {
1483
+ return this._getScroll()[0];
1484
+ },
1485
+
1486
+ /**
1487
+ * Returns the scrollTop and scrollLeft. Used to calculate the
1488
+ * pageX and pageY in Internet Explorer
1489
+ * @method _getScroll
1490
+ * @static
1491
+ * @private
1492
+ */
1493
+ _getScroll: function() {
1494
+ var dd = document.documentElement, db = document.body;
1495
+ if (dd && (dd.scrollTop || dd.scrollLeft)) {
1496
+ return [dd.scrollTop, dd.scrollLeft];
1497
+ } else if (db) {
1498
+ return [db.scrollTop, db.scrollLeft];
1499
+ } else {
1500
+ return [0, 0];
1501
+ }
1502
+ },
1503
+
1504
+ /**
1505
+ * Adds a DOM event directly without the caching, cleanup, scope adj, etc
1506
+ *
1507
+ * @method _simpleAdd
1508
+ * @param {HTMLElement} el the element to bind the handler to
1509
+ * @param {string} sType the type of event handler
1510
+ * @param {function} fn the callback to invoke
1511
+ * @param {boolen} capture capture or bubble phase
1512
+ * @static
1513
+ * @private
1514
+ */
1515
+ _simpleAdd: function () {
1516
+ if (window.addEventListener) {
1517
+ return function(el, sType, fn, capture) {
1518
+ el.addEventListener(sType, fn, (capture));
1519
+ };
1520
+ } else if (window.attachEvent) {
1521
+ return function(el, sType, fn, capture) {
1522
+ el.attachEvent("on" + sType, fn);
1523
+ };
1524
+ } else {
1525
+ return function(){};
1526
+ }
1527
+ }(),
1528
+
1529
+ /**
1530
+ * Basic remove listener
1531
+ *
1532
+ * @method _simpleRemove
1533
+ * @param {HTMLElement} el the element to bind the handler to
1534
+ * @param {string} sType the type of event handler
1535
+ * @param {function} fn the callback to invoke
1536
+ * @param {boolen} capture capture or bubble phase
1537
+ * @static
1538
+ * @private
1539
+ */
1540
+ _simpleRemove: function() {
1541
+ if (window.removeEventListener) {
1542
+ return function (el, sType, fn, capture) {
1543
+ el.removeEventListener(sType, fn, (capture));
1544
+ };
1545
+ } else if (window.detachEvent) {
1546
+ return function (el, sType, fn) {
1547
+ el.detachEvent("on" + sType, fn);
1548
+ };
1549
+ } else {
1550
+ return function(){};
1551
+ }
1552
+ }()
1553
+ };
1554
+
1555
+ }();
1556
+
1557
+ (function() {
1558
+ var EU = YAHOO.util.Event;
1559
+
1560
+ /**
1561
+ * YAHOO.util.Event.on is an alias for addListener
1562
+ * @method on
1563
+ * @see addListener
1564
+ * @static
1565
+ */
1566
+ EU.on = EU.addListener;
1567
+
1568
+ // YAHOO.mix(EU, YAHOO.util.EventProvider.prototype);
1569
+ // EU.createEvent("DOMContentReady");
1570
+ // EU.subscribe("DOMContentReady", EU._load);
1571
+
1572
+ if (document && document.body) {
1573
+ EU._load();
1574
+ } else {
1575
+ // EU._simpleAdd(document, "DOMContentLoaded", EU._load);
1576
+ EU._simpleAdd(window, "load", EU._load);
1577
+ }
1578
+ EU._simpleAdd(window, "unload", EU._unload);
1579
+ EU._tryPreloadAttach();
1580
+ })();
1581
+ }
1582
+
1583
+ /**
1584
+ * EventProvider is designed to be used with YAHOO.augment to wrap
1585
+ * CustomEvents in an interface that allows events to be subscribed to
1586
+ * and fired by name. This makes it possible for implementing code to
1587
+ * subscribe to an event that either has not been created yet, or will
1588
+ * not be created at all.
1589
+ *
1590
+ * @Class EventProvider
1591
+ */
1592
+ YAHOO.util.EventProvider = function() { };
1593
+
1594
+ YAHOO.util.EventProvider.prototype = {
1595
+
1596
+ /**
1597
+ * Private storage of custom events
1598
+ * @property __yui_events
1599
+ * @type Object[]
1600
+ * @private
1601
+ */
1602
+ __yui_events: null,
1603
+
1604
+ /**
1605
+ * Private storage of custom event subscribers
1606
+ * @property __yui_subscribers
1607
+ * @type Object[]
1608
+ * @private
1609
+ */
1610
+ __yui_subscribers: null,
1611
+
1612
+ /**
1613
+ * Subscribe to a CustomEvent by event type
1614
+ *
1615
+ * @method subscribe
1616
+ * @param p_type {string} the type, or name of the event
1617
+ * @param p_fn {function} the function to exectute when the event fires
1618
+ * @param p_obj
1619
+ * @param p_obj {Object} An object to be passed along when the event
1620
+ * fires
1621
+ * @param p_override {boolean} If true, the obj passed in becomes the
1622
+ * execution scope of the listener
1623
+ */
1624
+ subscribe: function(p_type, p_fn, p_obj, p_override) {
1625
+
1626
+ this.__yui_events = this.__yui_events || {};
1627
+ var ce = this.__yui_events[p_type];
1628
+
1629
+ if (ce) {
1630
+ ce.subscribe(p_fn, p_obj, p_override);
1631
+ } else {
1632
+ this.__yui_subscribers = this.__yui_subscribers || {};
1633
+ var subs = this.__yui_subscribers;
1634
+ if (!subs[p_type]) {
1635
+ subs[p_type] = [];
1636
+ }
1637
+ subs[p_type].push(
1638
+ { fn: p_fn, obj: p_obj, override: p_override } );
1639
+ }
1640
+ },
1641
+
1642
+ /**
1643
+ * Unsubscribes the from the specified event
1644
+ * @method unsubscribe
1645
+ * @param p_type {string} The type, or name of the event
1646
+ * @param p_fn {Function} The function to execute
1647
+ * @param p_obj {Object} The custom object passed to subscribe (optional)
1648
+ * @return {boolean} true if the subscriber was found and detached.
1649
+ */
1650
+ unsubscribe: function(p_type, p_fn, p_obj) {
1651
+ this.__yui_events = this.__yui_events || {};
1652
+ var ce = this.__yui_events[p_type];
1653
+ if (ce) {
1654
+ return ce.unsubscribe(p_fn, p_obj);
1655
+ } else {
1656
+ return false;
1657
+ }
1658
+ },
1659
+
1660
+ /**
1661
+ * Creates a new custom event of the specified type. If a custom event
1662
+ * by that name already exists, it will not be re-created. In either
1663
+ * case the custom event is returned.
1664
+ *
1665
+ * @method createEvent
1666
+ *
1667
+ * @param p_type {string} the type, or name of the event
1668
+ * @param p_config {object} optional config params. Valid properties are:
1669
+ *
1670
+ * <ul>
1671
+ * <li>
1672
+ * scope: defines the default execution scope. If not defined
1673
+ * the default scope will be this instance.
1674
+ * </li>
1675
+ * <li>
1676
+ * silent: if true, the custom event will not generate log messages.
1677
+ * This is false by default.
1678
+ * </li>
1679
+ * <li>
1680
+ * onSubscribeCallback: specifies a callback to execute when the
1681
+ * event has a new subscriber. This will fire immediately for
1682
+ * each queued subscriber if any exist prior to the creation of
1683
+ * the event.
1684
+ * </li>
1685
+ * </ul>
1686
+ *
1687
+ * @return {CustomEvent} the custom event
1688
+ *
1689
+ */
1690
+ createEvent: function(p_type, p_config) {
1691
+
1692
+ this.__yui_events = this.__yui_events || {};
1693
+ var opts = p_config || {};
1694
+ var events = this.__yui_events;
1695
+
1696
+ if (events[p_type]) {
1697
+ } else {
1698
+
1699
+ var scope = opts.scope || this;
1700
+ var silent = opts.silent || null;
1701
+
1702
+ var ce = new YAHOO.util.CustomEvent(p_type, scope, silent,
1703
+ YAHOO.util.CustomEvent.FLAT);
1704
+ events[p_type] = ce;
1705
+
1706
+ if (opts.onSubscribeCallback) {
1707
+ ce.subscribeEvent.subscribe(opts.onSubscribeCallback);
1708
+ }
1709
+
1710
+ this.__yui_subscribers = this.__yui_subscribers || {};
1711
+ var qs = this.__yui_subscribers[p_type];
1712
+
1713
+ if (qs) {
1714
+ for (var i=0; i<qs.length; ++i) {
1715
+ ce.subscribe(qs[i].fn, qs[i].obj, qs[i].override);
1716
+ }
1717
+ }
1718
+ }
1719
+
1720
+ return events[p_type];
1721
+ },
1722
+
1723
+ /**
1724
+ * Fire a custom event by name. The callback functions will be executed
1725
+ * from the scope specified when the event was created, and with the
1726
+ * following parameters:
1727
+ * <ul>
1728
+ * <li>The first argument fire() was executed with</li>
1729
+ * <li>The custom object (if any) that was passed into the subscribe()
1730
+ * method</li>
1731
+ * </ul>
1732
+ * @method fireEvent
1733
+ * @param p_type {string} the type, or name of the event
1734
+ * @param arguments {Object*} an arbitrary set of parameters to pass to
1735
+ * the handler.
1736
+ * @return {boolean} the return value from CustomEvent.fire, or null if
1737
+ * the custom event does not exist.
1738
+ */
1739
+ fireEvent: function(p_type, arg1, arg2, etc) {
1740
+
1741
+ this.__yui_events = this.__yui_events || {};
1742
+ var ce = this.__yui_events[p_type];
1743
+
1744
+ if (ce) {
1745
+ var args = [];
1746
+ for (var i=1; i<arguments.length; ++i) {
1747
+ args.push(arguments[i]);
1748
+ }
1749
+ return ce.fire.apply(ce, args);
1750
+ } else {
1751
+ return null;
1752
+ }
1753
+ },
1754
+
1755
+ /**
1756
+ * Returns true if the custom event of the provided type has been created
1757
+ * with createEvent.
1758
+ * @method hasEvent
1759
+ * @param type {string} the type, or name of the event
1760
+ */
1761
+ hasEvent: function(type) {
1762
+ if (this.__yui_events) {
1763
+ if (this.__yui_events[type]) {
1764
+ return true;
1765
+ }
1766
+ }
1767
+ return false;
1768
+ }
1769
+
1770
+ };
1771
+