adhearsion 0.7.6 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
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
+