~launchpad-pqm/lazr-js/toolchain

« back to all changes in this revision

Viewing changes to src-js/lazrjs/yui/event/event-debug.js

  • Committer: Sidnei da Silva
  • Date: 2009-11-16 00:51:29 UTC
  • mto: This revision was merged to the branch mainline in revision 154.
  • Revision ID: sidnei.da.silva@canonical.com-20091116005129-8ibwjlboa38glaw5
- Improved generation of skin modules and revamped combo service to make it more twisty.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
 
Code licensed under the BSD License:
4
 
http://developer.yahoo.com/yui/license.html
5
 
version: 3.2.0
6
 
build: 2676
7
 
*/
8
 
/*
9
 
 * DOM event listener abstraction layer
10
 
 * @module event
11
 
 * @submodule event-base
12
 
 */
13
 
 
14
 
(function() {
15
 
 
16
 
// Unlike most of the library, this code has to be executed as soon as it is
17
 
// introduced into the page -- and it should only be executed one time
18
 
// regardless of the number of instances that use it.
19
 
 
20
 
var stateChangeListener,
21
 
    GLOBAL_ENV   = YUI.Env, 
22
 
    config       = YUI.config, 
23
 
    doc          = config.doc, 
24
 
    docElement   = doc && doc.documentElement, 
25
 
    doScrollCap  = docElement && docElement.doScroll,
26
 
    add          = YUI.Env.add,
27
 
    remove       = YUI.Env.remove,
28
 
    targetEvent  = (doScrollCap) ? 'onreadystatechange' : 'DOMContentLoaded',
29
 
    pollInterval = config.pollInterval || 40,
30
 
    _ready       = function(e) {
31
 
                     GLOBAL_ENV._ready();
32
 
                 };
33
 
 
34
 
if (!GLOBAL_ENV._ready) {
35
 
    GLOBAL_ENV._ready = function() {
36
 
        if (!GLOBAL_ENV.DOMReady) {
37
 
            GLOBAL_ENV.DOMReady = true;
38
 
            remove(doc, targetEvent, _ready); // remove DOMContentLoaded listener
39
 
        }
40
 
    };
41
 
 
42
 
/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
43
 
// Internet Explorer: use the doScroll() method on the root element.  This isolates what 
44
 
// appears to be a safe moment to manipulate the DOM prior to when the document's readyState 
45
 
// suggests it is safe to do so.
46
 
    if (doScrollCap) {
47
 
        if (self !== self.top) {
48
 
            stateChangeListener = function() {
49
 
                if (doc.readyState == 'complete') {
50
 
                    remove(doc, targetEvent, stateChangeListener); // remove onreadystatechange listener
51
 
                    _ready();
52
 
                }
53
 
            };
54
 
            add(doc, targetEvent, stateChangeListener); // add onreadystatechange listener
55
 
        } else {
56
 
            GLOBAL_ENV._dri = setInterval(function() {
57
 
                try {
58
 
                    docElement.doScroll('left');
59
 
                    clearInterval(GLOBAL_ENV._dri);
60
 
                    GLOBAL_ENV._dri = null;
61
 
                    _ready();
62
 
                } catch (domNotReady) { }
63
 
            }, pollInterval); 
64
 
        }
65
 
    } else { // FireFox, Opera, Safari 3+ provide an event for this moment.
66
 
        add(doc, targetEvent, _ready); // add DOMContentLoaded listener
67
 
    }
68
 
}
69
 
 
70
 
})();
71
 
YUI.add('event-base', function(Y) {
72
 
 
73
 
(function() {
74
 
/*
75
 
 * DOM event listener abstraction layer
76
 
 * @module event
77
 
 * @submodule event-base
78
 
 */
79
 
 
80
 
var GLOBAL_ENV = YUI.Env,
81
 
    
82
 
    yready = function() {
83
 
        Y.fire('domready');
84
 
    };
85
 
 
86
 
/**
87
 
 * The domready event fires at the moment the browser's DOM is
88
 
 * usable. In most cases, this is before images are fully
89
 
 * downloaded, allowing you to provide a more responsive user
90
 
 * interface.
91
 
 *
92
 
 * In YUI 3, domready subscribers will be notified immediately if
93
 
 * that moment has already passed when the subscription is created.
94
 
 *
95
 
 * One exception is if the yui.js file is dynamically injected into
96
 
 * the page.  If this is done, you must tell the YUI instance that
97
 
 * you did this in order for DOMReady (and window load events) to
98
 
 * fire normally.  That configuration option is 'injected' -- set
99
 
 * it to true if the yui.js script is not included inline.
100
 
 *
101
 
 * This method is part of the 'event-ready' module, which is a
102
 
 * submodule of 'event'.  
103
 
 *
104
 
 * @event domready
105
 
 * @for YUI
106
 
 */
107
 
Y.publish('domready', {
108
 
    fireOnce: true,
109
 
    async: true
110
 
});
111
 
 
112
 
if (GLOBAL_ENV.DOMReady) {
113
 
    // console.log('DOMReady already fired', 'info', 'event');
114
 
    yready();
115
 
} else {
116
 
    // console.log('setting up before listener', 'info', 'event');
117
 
    // console.log('env: ' + YUI.Env.windowLoaded, 'info', 'event');
118
 
    Y.before(yready, GLOBAL_ENV, "_ready");
119
 
}
120
 
 
121
 
})();
122
 
(function() {
123
 
 
124
 
/**
125
 
 * Custom event engine, DOM event listener abstraction layer, synthetic DOM 
126
 
 * events.
127
 
 * @module event
128
 
 * @submodule event-base
129
 
 */
130
 
 
131
 
/**
132
 
 * Wraps a DOM event, properties requiring browser abstraction are
133
 
 * fixed here.  Provids a security layer when required.
134
 
 * @class DOMEventFacade
135
 
 * @param ev {Event} the DOM event
136
 
 * @param currentTarget {HTMLElement} the element the listener was attached to
137
 
 * @param wrapper {Event.Custom} the custom event wrapper for this DOM event
138
 
 */
139
 
 
140
 
/*
141
 
 * @TODO constants? LEFTBUTTON, MIDDLEBUTTON, RIGHTBUTTON, keys
142
 
 */
143
 
 
144
 
/*
145
 
 
146
 
var whitelist = {
147
 
    altKey          : 1,
148
 
    // "button"          : 1, // we supply
149
 
    // "bubbles"         : 1, // needed?
150
 
    // "cancelable"      : 1, // needed? 
151
 
    // "charCode"        : 1, // we supply
152
 
    cancelBubble    : 1,
153
 
    // "currentTarget"   : 1, // we supply
154
 
    ctrlKey         : 1,
155
 
    clientX         : 1, // needed?
156
 
    clientY         : 1, // needed?
157
 
    detail          : 1, // not fully implemented
158
 
    // "fromElement"     : 1,
159
 
    keyCode         : 1,
160
 
    // "height"          : 1, // needed?
161
 
    // "initEvent"       : 1, // need the init events?
162
 
    // "initMouseEvent"  : 1,
163
 
    // "initUIEvent"     : 1,
164
 
    // "layerX"          : 1, // needed?
165
 
    // "layerY"          : 1, // needed?
166
 
    metaKey         : 1,
167
 
    // "modifiers"       : 1, // needed?
168
 
    // "offsetX"         : 1, // needed?
169
 
    // "offsetY"         : 1, // needed?
170
 
    // "preventDefault"  : 1, // we supply
171
 
    // "reason"          : 1, // IE proprietary
172
 
    // "relatedTarget"   : 1,
173
 
    // "returnValue"     : 1, // needed?
174
 
    shiftKey        : 1,
175
 
    // "srcUrn"          : 1, // IE proprietary
176
 
    // "srcElement"      : 1,
177
 
    // "srcFilter"       : 1, IE proprietary
178
 
    // "stopPropagation" : 1, // we supply
179
 
    // "target"          : 1,
180
 
    // "timeStamp"       : 1, // needed?
181
 
    // "toElement"       : 1,
182
 
    type            : 1,
183
 
    // "view"            : 1,
184
 
    // "which"           : 1, // we supply
185
 
    // "width"           : 1, // needed?
186
 
    x               : 1,
187
 
    y               : 1
188
 
},
189
 
 
190
 
*/
191
 
 
192
 
    var ua = Y.UA,
193
 
 
194
 
    /**
195
 
     * webkit key remapping required for Safari < 3.1
196
 
     * @property webkitKeymap
197
 
     * @private
198
 
     */
199
 
    webkitKeymap = {
200
 
        63232: 38, // up
201
 
        63233: 40, // down
202
 
        63234: 37, // left
203
 
        63235: 39, // right
204
 
        63276: 33, // page up
205
 
        63277: 34, // page down
206
 
        25:     9, // SHIFT-TAB (Safari provides a different key code in
207
 
                   // this case, even though the shiftKey modifier is set)
208
 
        63272: 46, // delete
209
 
        63273: 36, // home
210
 
        63275: 35  // end
211
 
    },
212
 
 
213
 
    /**
214
 
     * Returns a wrapped node.  Intended to be used on event targets,
215
 
     * so it will return the node's parent if the target is a text
216
 
     * node.
217
 
     *
218
 
     * If accessing a property of the node throws an error, this is
219
 
     * probably the anonymous div wrapper Gecko adds inside text
220
 
     * nodes.  This likely will only occur when attempting to access
221
 
     * the relatedTarget.  In this case, we now return null because
222
 
     * the anonymous div is completely useless and we do not know
223
 
     * what the related target was because we can't even get to
224
 
     * the element's parent node.
225
 
     *
226
 
     * @method resolve
227
 
     * @private
228
 
     */
229
 
    resolve = function(n) {
230
 
        try {
231
 
            if (n && 3 == n.nodeType) {
232
 
                n = n.parentNode;
233
 
            }
234
 
        } catch(e) { 
235
 
            return null;
236
 
        }
237
 
 
238
 
        return Y.one(n);
239
 
    };
240
 
 
241
 
 
242
 
// provide a single event with browser abstractions resolved
243
 
//
244
 
// include all properties for both browers?
245
 
// include only DOM2 spec properties?
246
 
// provide browser-specific facade?
247
 
 
248
 
Y.DOMEventFacade = function(ev, currentTarget, wrapper) {
249
 
 
250
 
    wrapper = wrapper || {};
251
 
 
252
 
    var e = ev, ot = currentTarget, d = Y.config.doc, b = d.body,
253
 
        x = e.pageX, y = e.pageY, c, t, de = d.documentElement,
254
 
        overrides = wrapper.overrides || {};
255
 
 
256
 
    this.altKey   = e.altKey;
257
 
    this.ctrlKey  = e.ctrlKey;
258
 
    this.metaKey  = e.metaKey;
259
 
    this.shiftKey = e.shiftKey;
260
 
    this.type     = overrides.type || e.type;
261
 
    this.clientX  = e.clientX;
262
 
    this.clientY  = e.clientY;
263
 
 
264
 
    //////////////////////////////////////////////////////
265
 
 
266
 
    if (('clientX' in e) && (!x) && (0 !== x)) {
267
 
        x = e.clientX; 
268
 
        y = e.clientY;
269
 
 
270
 
        if (ua.ie) {
271
 
            x += (de.scrollLeft || b.scrollLeft || 0);
272
 
            y += (de.scrollTop  || b.scrollTop  || 0);
273
 
        }
274
 
    }
275
 
 
276
 
    this._yuifacade = true;
277
 
 
278
 
    /**
279
 
     * The native event
280
 
     * @property _event
281
 
     */
282
 
    this._event = e;
283
 
 
284
 
    /**
285
 
     * The X location of the event on the page (including scroll)
286
 
     * @property pageX
287
 
     * @type int
288
 
     */
289
 
    this.pageX = x;
290
 
 
291
 
    /**
292
 
     * The Y location of the event on the page (including scroll)
293
 
     * @property pageY
294
 
     * @type int
295
 
     */
296
 
    this.pageY = y;
297
 
 
298
 
    //////////////////////////////////////////////////////
299
 
 
300
 
    c = e.keyCode || e.charCode || 0;
301
 
 
302
 
    if (ua.webkit && (c in webkitKeymap)) {
303
 
        c = webkitKeymap[c];
304
 
    }
305
 
 
306
 
    /**
307
 
     * The keyCode for key events.  Uses charCode if keyCode is not available
308
 
     * @property keyCode
309
 
     * @type int
310
 
     */
311
 
    this.keyCode = c;
312
 
 
313
 
    /**
314
 
     * The charCode for key events.  Same as keyCode
315
 
     * @property charCode
316
 
     * @type int
317
 
     */
318
 
    this.charCode = c;
319
 
 
320
 
    //////////////////////////////////////////////////////
321
 
 
322
 
    /**
323
 
     * The button that was pushed.
324
 
     * @property button
325
 
     * @type int
326
 
     */
327
 
    this.button = e.which || e.button;
328
 
 
329
 
    /**
330
 
     * The button that was pushed.  Same as button.
331
 
     * @property which
332
 
     * @type int
333
 
     */
334
 
    this.which = this.button;
335
 
 
336
 
    //////////////////////////////////////////////////////
337
 
 
338
 
    /**
339
 
     * Node reference for the targeted element
340
 
     * @propery target
341
 
     * @type Node
342
 
     */
343
 
    this.target = resolve(e.target || e.srcElement);
344
 
 
345
 
    /**
346
 
     * Node reference for the element that the listener was attached to.
347
 
     * @propery currentTarget
348
 
     * @type Node
349
 
     */
350
 
    this.currentTarget = resolve(ot);
351
 
 
352
 
    t = e.relatedTarget;
353
 
 
354
 
    if (!t) {
355
 
        if (e.type == "mouseout") {
356
 
            t = e.toElement;
357
 
        } else if (e.type == "mouseover") {
358
 
            t = e.fromElement;
359
 
        }
360
 
    }
361
 
 
362
 
    /**
363
 
     * Node reference to the relatedTarget
364
 
     * @propery relatedTarget
365
 
     * @type Node
366
 
     */
367
 
    this.relatedTarget = resolve(t);
368
 
 
369
 
    /**
370
 
     * Number representing the direction and velocity of the movement of the mousewheel.
371
 
     * Negative is down, the higher the number, the faster.  Applies to the mousewheel event.
372
 
     * @property wheelDelta
373
 
     * @type int
374
 
     */
375
 
    if (e.type == "mousewheel" || e.type == "DOMMouseScroll") {
376
 
        this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
377
 
    }
378
 
 
379
 
    //////////////////////////////////////////////////////
380
 
    // methods
381
 
 
382
 
    /**
383
 
     * Stops the propagation to the next bubble target
384
 
     * @method stopPropagation
385
 
     */
386
 
    this.stopPropagation = function() {
387
 
        if (e.stopPropagation) {
388
 
            e.stopPropagation();
389
 
        } else {
390
 
            e.cancelBubble = true;
391
 
        }
392
 
        wrapper.stopped = 1;
393
 
        this.stopped = 1;
394
 
    };
395
 
 
396
 
    /**
397
 
     * Stops the propagation to the next bubble target and
398
 
     * prevents any additional listeners from being exectued
399
 
     * on the current target.
400
 
     * @method stopImmediatePropagation
401
 
     */
402
 
    this.stopImmediatePropagation = function() {
403
 
        if (e.stopImmediatePropagation) {
404
 
            e.stopImmediatePropagation();
405
 
        } else {
406
 
            this.stopPropagation();
407
 
        }
408
 
        wrapper.stopped = 2;
409
 
        this.stopped = 2;
410
 
    };
411
 
 
412
 
    /**
413
 
     * Prevents the event's default behavior
414
 
     * @method preventDefault
415
 
     * @param returnValue {string} sets the returnValue of the event to this value
416
 
     * (rather than the default false value).  This can be used to add a customized 
417
 
     * confirmation query to the beforeunload event).
418
 
     */
419
 
    this.preventDefault = function(returnValue) {
420
 
        if (e.preventDefault) {
421
 
            e.preventDefault();
422
 
        }
423
 
        e.returnValue = returnValue || false;
424
 
        wrapper.prevented = 1;
425
 
        this.prevented = 1;
426
 
    };
427
 
 
428
 
    /**
429
 
     * Stops the event propagation and prevents the default
430
 
     * event behavior.
431
 
     * @method halt
432
 
     * @param immediate {boolean} if true additional listeners
433
 
     * on the current target will not be executed
434
 
     */
435
 
    this.halt = function(immediate) {
436
 
        if (immediate) {
437
 
            this.stopImmediatePropagation();
438
 
        } else {
439
 
            this.stopPropagation();
440
 
        }
441
 
 
442
 
        this.preventDefault();
443
 
    };
444
 
 
445
 
    if (this._touch) {
446
 
        this._touch(e, currentTarget, wrapper);
447
 
    }
448
 
 
449
 
};
450
 
 
451
 
})();
452
 
(function() {
453
 
/**
454
 
 * DOM event listener abstraction layer
455
 
 * @module event
456
 
 * @submodule event-base
457
 
 */
458
 
 
459
 
/**
460
 
 * The event utility provides functions to add and remove event listeners,
461
 
 * event cleansing.  It also tries to automatically remove listeners it
462
 
 * registers during the unload event.
463
 
 *
464
 
 * @class Event
465
 
 * @static
466
 
 */
467
 
 
468
 
Y.Env.evt.dom_wrappers = {};
469
 
Y.Env.evt.dom_map = {};
470
 
 
471
 
var _eventenv = Y.Env.evt,
472
 
config = Y.config,
473
 
win = config.win,
474
 
add = YUI.Env.add,
475
 
remove = YUI.Env.remove,
476
 
 
477
 
onLoad = function() {
478
 
    YUI.Env.windowLoaded = true;
479
 
    Y.Event._load();
480
 
    remove(win, "load", onLoad);
481
 
},
482
 
 
483
 
onUnload = function() {
484
 
    Y.Event._unload();
485
 
    remove(win, "unload", onUnload);
486
 
},
487
 
 
488
 
EVENT_READY = 'domready',
489
 
 
490
 
COMPAT_ARG = '~yui|2|compat~',
491
 
 
492
 
shouldIterate = function(o) {
493
 
    try {
494
 
        return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) && !o.tagName && !o.alert);
495
 
    } catch(ex) {
496
 
        Y.log("collection check failure", "warn", "event");
497
 
        return false;
498
 
    }
499
 
 
500
 
},
501
 
 
502
 
Event = function() {
503
 
 
504
 
    /**
505
 
     * True after the onload event has fired
506
 
     * @property _loadComplete
507
 
     * @type boolean
508
 
     * @static
509
 
     * @private
510
 
     */
511
 
    var _loadComplete =  false,
512
 
 
513
 
    /**
514
 
     * The number of times to poll after window.onload.  This number is
515
 
     * increased if additional late-bound handlers are requested after
516
 
     * the page load.
517
 
     * @property _retryCount
518
 
     * @static
519
 
     * @private
520
 
     */
521
 
    _retryCount = 0,
522
 
 
523
 
    /**
524
 
     * onAvailable listeners
525
 
     * @property _avail
526
 
     * @static
527
 
     * @private
528
 
     */
529
 
    _avail = [],
530
 
 
531
 
    /**
532
 
     * Custom event wrappers for DOM events.  Key is 
533
 
     * 'event:' + Element uid stamp + event type
534
 
     * @property _wrappers
535
 
     * @type Y.Event.Custom
536
 
     * @static
537
 
     * @private
538
 
     */
539
 
    _wrappers = _eventenv.dom_wrappers,
540
 
 
541
 
    _windowLoadKey = null,
542
 
 
543
 
    /**
544
 
     * Custom event wrapper map DOM events.  Key is 
545
 
     * Element uid stamp.  Each item is a hash of custom event
546
 
     * wrappers as provided in the _wrappers collection.  This
547
 
     * provides the infrastructure for getListeners.
548
 
     * @property _el_events
549
 
     * @static
550
 
     * @private
551
 
     */
552
 
    _el_events = _eventenv.dom_map;
553
 
 
554
 
    return {
555
 
 
556
 
        /**
557
 
         * The number of times we should look for elements that are not
558
 
         * in the DOM at the time the event is requested after the document
559
 
         * has been loaded.  The default is 1000@amp;40 ms, so it will poll
560
 
         * for 40 seconds or until all outstanding handlers are bound
561
 
         * (whichever comes first).
562
 
         * @property POLL_RETRYS
563
 
         * @type int
564
 
         * @static
565
 
         * @final
566
 
         */
567
 
        POLL_RETRYS: 1000,
568
 
 
569
 
        /**
570
 
         * The poll interval in milliseconds
571
 
         * @property POLL_INTERVAL
572
 
         * @type int
573
 
         * @static
574
 
         * @final
575
 
         */
576
 
        POLL_INTERVAL: 40,
577
 
 
578
 
        /**
579
 
         * addListener/removeListener can throw errors in unexpected scenarios.
580
 
         * These errors are suppressed, the method returns false, and this property
581
 
         * is set
582
 
         * @property lastError
583
 
         * @static
584
 
         * @type Error
585
 
         */
586
 
        lastError: null,
587
 
 
588
 
 
589
 
        /**
590
 
         * poll handle
591
 
         * @property _interval
592
 
         * @static
593
 
         * @private
594
 
         */
595
 
        _interval: null,
596
 
 
597
 
        /**
598
 
         * document readystate poll handle
599
 
         * @property _dri
600
 
         * @static
601
 
         * @private
602
 
         */
603
 
         _dri: null,
604
 
 
605
 
        /**
606
 
         * True when the document is initially usable
607
 
         * @property DOMReady
608
 
         * @type boolean
609
 
         * @static
610
 
         */
611
 
        DOMReady: false,
612
 
 
613
 
        /**
614
 
         * @method startInterval
615
 
         * @static
616
 
         * @private
617
 
         */
618
 
        startInterval: function() {
619
 
            if (!Event._interval) {
620
 
Event._interval = setInterval(Y.bind(Event._poll, Event), Event.POLL_INTERVAL);
621
 
            }
622
 
        },
623
 
 
624
 
        /**
625
 
         * Executes the supplied callback when the item with the supplied
626
 
         * id is found.  This is meant to be used to execute behavior as
627
 
         * soon as possible as the page loads.  If you use this after the
628
 
         * initial page load it will poll for a fixed time for the element.
629
 
         * The number of times it will poll and the frequency are
630
 
         * configurable.  By default it will poll for 10 seconds.
631
 
         *
632
 
         * <p>The callback is executed with a single parameter:
633
 
         * the custom object parameter, if provided.</p>
634
 
         *
635
 
         * @method onAvailable
636
 
         *
637
 
         * @param {string||string[]}   id the id of the element, or an array
638
 
         * of ids to look for.
639
 
         * @param {function} fn what to execute when the element is found.
640
 
         * @param {object}   p_obj an optional object to be passed back as
641
 
         *                   a parameter to fn.
642
 
         * @param {boolean|object}  p_override If set to true, fn will execute
643
 
         *                   in the context of p_obj, if set to an object it
644
 
         *                   will execute in the context of that object
645
 
         * @param checkContent {boolean} check child node readiness (onContentReady)
646
 
         * @static
647
 
         * @deprecated Use Y.on("available")
648
 
         */
649
 
        // @TODO fix arguments
650
 
        onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) {
651
 
 
652
 
            var a = Y.Array(id), i, availHandle;
653
 
 
654
 
            // Y.log('onAvailable registered for: ' + id);
655
 
 
656
 
            for (i=0; i<a.length; i=i+1) {
657
 
                _avail.push({ 
658
 
                    id:         a[i], 
659
 
                    fn:         fn, 
660
 
                    obj:        p_obj, 
661
 
                    override:   p_override, 
662
 
                    checkReady: checkContent,
663
 
                    compat:     compat 
664
 
                });
665
 
            }
666
 
            _retryCount = this.POLL_RETRYS;
667
 
 
668
 
            // We want the first test to be immediate, but async
669
 
            setTimeout(Y.bind(Event._poll, Event), 0);
670
 
 
671
 
            availHandle = new Y.EventHandle({
672
 
 
673
 
                _delete: function() {
674
 
                    // set by the event system for lazy DOM listeners
675
 
                    if (availHandle.handle) {
676
 
                        availHandle.handle.detach();
677
 
                        return;
678
 
                    }
679
 
 
680
 
                    var i, j;
681
 
 
682
 
                    // otherwise try to remove the onAvailable listener(s)
683
 
                    for (i = 0; i < a.length; i++) {
684
 
                        for (j = 0; j < _avail.length; j++) {
685
 
                            if (a[i] === _avail[j].id) {
686
 
                                _avail.splice(j, 1);
687
 
                            }
688
 
                        }
689
 
                    }
690
 
                }
691
 
 
692
 
            });
693
 
 
694
 
            return availHandle;
695
 
        },
696
 
 
697
 
        /**
698
 
         * Works the same way as onAvailable, but additionally checks the
699
 
         * state of sibling elements to determine if the content of the
700
 
         * available element is safe to modify.
701
 
         *
702
 
         * <p>The callback is executed with a single parameter:
703
 
         * the custom object parameter, if provided.</p>
704
 
         *
705
 
         * @method onContentReady
706
 
         *
707
 
         * @param {string}   id the id of the element to look for.
708
 
         * @param {function} fn what to execute when the element is ready.
709
 
         * @param {object}   p_obj an optional object to be passed back as
710
 
         *                   a parameter to fn.
711
 
         * @param {boolean|object}  p_override If set to true, fn will execute
712
 
         *                   in the context of p_obj.  If an object, fn will
713
 
         *                   exectute in the context of that object
714
 
         *
715
 
         * @static
716
 
         * @deprecated Use Y.on("contentready")
717
 
         */
718
 
        // @TODO fix arguments
719
 
        onContentReady: function(id, fn, p_obj, p_override, compat) {
720
 
            return this.onAvailable(id, fn, p_obj, p_override, true, compat);
721
 
        },
722
 
 
723
 
        /**
724
 
         * Adds an event listener
725
 
         *
726
 
         * @method attach
727
 
         *
728
 
         * @param {String}   type     The type of event to append
729
 
         * @param {Function} fn        The method the event invokes
730
 
         * @param {String|HTMLElement|Array|NodeList} el An id, an element 
731
 
         *  reference, or a collection of ids and/or elements to assign the 
732
 
         *  listener to.
733
 
         * @param {Object}   context optional context object
734
 
         * @param {Boolean|object}  args 0..n arguments to pass to the callback
735
 
         * @return {EventHandle} an object to that can be used to detach the listener
736
 
         *                     
737
 
         * @static
738
 
         */
739
 
 
740
 
        attach: function(type, fn, el, context) {
741
 
            return Event._attach(Y.Array(arguments, 0, true));
742
 
        },
743
 
 
744
 
        _createWrapper: function (el, type, capture, compat, facade) {
745
 
 
746
 
            var cewrapper,
747
 
                ek  = Y.stamp(el),
748
 
                key = 'event:' + ek + type;
749
 
 
750
 
            if (false === facade) {
751
 
                key += 'native';
752
 
            }
753
 
            if (capture) {
754
 
                key += 'capture';
755
 
            }
756
 
 
757
 
 
758
 
            cewrapper = _wrappers[key];
759
 
            
760
 
 
761
 
            if (!cewrapper) {
762
 
                // create CE wrapper
763
 
                cewrapper = Y.publish(key, {
764
 
                    silent: true,
765
 
                    bubbles: false,
766
 
                    contextFn: function() {
767
 
                        if (compat) {
768
 
                            return cewrapper.el;
769
 
                        } else {
770
 
                            cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el);
771
 
                            return cewrapper.nodeRef;
772
 
                        }
773
 
                    }
774
 
                });
775
 
 
776
 
                cewrapper.overrides = {};
777
 
            
778
 
                // for later removeListener calls
779
 
                cewrapper.el = el;
780
 
                cewrapper.key = key;
781
 
                cewrapper.domkey = ek;
782
 
                cewrapper.type = type;
783
 
                cewrapper.fn = function(e) {
784
 
                    cewrapper.fire(Event.getEvent(e, el, (compat || (false === facade))));
785
 
                };
786
 
                cewrapper.capture = capture;
787
 
            
788
 
                if (el == win && type == "load") {
789
 
                    // window load happens once
790
 
                    cewrapper.fireOnce = true;
791
 
                    _windowLoadKey = key;
792
 
                }
793
 
            
794
 
                _wrappers[key] = cewrapper;
795
 
                _el_events[ek] = _el_events[ek] || {};
796
 
                _el_events[ek][key] = cewrapper;
797
 
            
798
 
                add(el, type, cewrapper.fn, capture);
799
 
            }
800
 
 
801
 
            return cewrapper;
802
 
            
803
 
        },
804
 
 
805
 
        _attach: function(args, conf) {
806
 
 
807
 
            var compat, 
808
 
                handles, oEl, cewrapper, context, 
809
 
                fireNow = false, ret,
810
 
                type = args[0],
811
 
                fn = args[1],
812
 
                el = args[2] || win,
813
 
                facade = conf && conf.facade,
814
 
                capture = conf && conf.capture,
815
 
                overrides = conf && conf.overrides; 
816
 
 
817
 
            if (args[args.length-1] === COMPAT_ARG) {
818
 
                compat = true;
819
 
                // trimmedArgs.pop();
820
 
            }
821
 
 
822
 
            if (!fn || !fn.call) {
823
 
// throw new TypeError(type + " attach call failed, callback undefined");
824
 
Y.log(type + " attach call failed, invalid callback", "error", "event");
825
 
                return false;
826
 
            }
827
 
 
828
 
            // The el argument can be an array of elements or element ids.
829
 
            if (shouldIterate(el)) {
830
 
 
831
 
                handles=[];
832
 
                
833
 
                Y.each(el, function(v, k) {
834
 
                    args[2] = v;
835
 
                    handles.push(Event._attach(args, conf));
836
 
                });
837
 
 
838
 
                // return (handles.length === 1) ? handles[0] : handles;
839
 
                return new Y.EventHandle(handles);
840
 
 
841
 
            // If the el argument is a string, we assume it is 
842
 
            // actually the id of the element.  If the page is loaded
843
 
            // we convert el to the actual element, otherwise we 
844
 
            // defer attaching the event until the element is
845
 
            // ready
846
 
            } else if (Y.Lang.isString(el)) {
847
 
 
848
 
                // oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el);
849
 
 
850
 
                if (compat) {
851
 
                    oEl = Y.DOM.byId(el);
852
 
                } else {
853
 
 
854
 
                    oEl = Y.Selector.query(el);
855
 
 
856
 
                    switch (oEl.length) {
857
 
                        case 0:
858
 
                            oEl = null;
859
 
                            break;
860
 
                        case 1:
861
 
                            oEl = oEl[0];
862
 
                            break;
863
 
                        default:
864
 
                            args[2] = oEl;
865
 
                            return Event._attach(args, conf);
866
 
                    }
867
 
                }
868
 
 
869
 
                if (oEl) {
870
 
 
871
 
                    el = oEl;
872
 
 
873
 
                // Not found = defer adding the event until the element is available
874
 
                } else {
875
 
 
876
 
                    // Y.log(el + ' not found');
877
 
                    ret = this.onAvailable(el, function() {
878
 
                        // Y.log('lazy attach: ' + args);
879
 
                        
880
 
                        ret.handle = Event._attach(args, conf);
881
 
 
882
 
                    }, Event, true, false, compat);
883
 
 
884
 
                    return ret;
885
 
 
886
 
                }
887
 
            }
888
 
 
889
 
            // Element should be an html element or node
890
 
            if (!el) {
891
 
                Y.log("unable to attach event " + type, "warn", "event");
892
 
                return false;
893
 
            }
894
 
 
895
 
            if (Y.Node && el instanceof Y.Node) {
896
 
                el = Y.Node.getDOMNode(el);
897
 
            }
898
 
 
899
 
            cewrapper = this._createWrapper(el, type, capture, compat, facade);
900
 
            if (overrides) {
901
 
                Y.mix(cewrapper.overrides, overrides);
902
 
            }
903
 
 
904
 
            if (el == win && type == "load") {
905
 
 
906
 
                // if the load is complete, fire immediately.
907
 
                // all subscribers, including the current one
908
 
                // will be notified.
909
 
                if (YUI.Env.windowLoaded) {
910
 
                    fireNow = true;
911
 
                }
912
 
            }
913
 
 
914
 
            if (compat) {
915
 
                args.pop();
916
 
            }
917
 
 
918
 
            context = args[3];
919
 
 
920
 
            // set context to the Node if not specified
921
 
            // ret = cewrapper.on.apply(cewrapper, trimmedArgs);
922
 
            ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null);
923
 
 
924
 
            if (fireNow) {
925
 
                cewrapper.fire();
926
 
            }
927
 
 
928
 
            return ret;
929
 
 
930
 
        },
931
 
 
932
 
        /**
933
 
         * Removes an event listener.  Supports the signature the event was bound
934
 
         * with, but the preferred way to remove listeners is using the handle
935
 
         * that is returned when using Y.on
936
 
         *
937
 
         * @method detach
938
 
         *
939
 
         * @param {String} type the type of event to remove.
940
 
         * @param {Function} fn the method the event invokes.  If fn is
941
 
         * undefined, then all event handlers for the type of event are 
942
 
         * removed.
943
 
         * @param {String|HTMLElement|Array|NodeList|EventHandle} el An 
944
 
         * event handle, an id, an element reference, or a collection 
945
 
         * of ids and/or elements to remove the listener from.
946
 
         * @return {boolean} true if the unbind was successful, false otherwise.
947
 
         * @static
948
 
         */
949
 
        detach: function(type, fn, el, obj) {
950
 
 
951
 
            var args=Y.Array(arguments, 0, true), compat, l, ok, i,
952
 
                id, ce;
953
 
 
954
 
            if (args[args.length-1] === COMPAT_ARG) {
955
 
                compat = true;
956
 
                // args.pop();
957
 
            }
958
 
 
959
 
            if (type && type.detach) {
960
 
                return type.detach();
961
 
            }
962
 
 
963
 
            // The el argument can be a string
964
 
            if (typeof el == "string") {
965
 
 
966
 
                // el = (compat) ? Y.DOM.byId(el) : Y.all(el);
967
 
                if (compat) {
968
 
                    el = Y.DOM.byId(el);
969
 
                } else {
970
 
                    el = Y.Selector.query(el);
971
 
                    l = el.length;
972
 
                    if (l < 1) {
973
 
                        el = null;
974
 
                    } else if (l == 1) {
975
 
                        el = el[0];
976
 
                    }
977
 
                }
978
 
                // return Event.detach.apply(Event, args);
979
 
            } 
980
 
            
981
 
            if (!el) {
982
 
                return false;
983
 
            }
984
 
 
985
 
            if (el.detach) {
986
 
                args.splice(2, 1);
987
 
                return el.detach.apply(el, args);
988
 
            // The el argument can be an array of elements or element ids.
989
 
            } else if (shouldIterate(el)) {
990
 
                ok = true;
991
 
                for (i=0, l=el.length; i<l; ++i) {
992
 
                    args[2] = el[i];
993
 
                    ok = ( Y.Event.detach.apply(Y.Event, args) && ok );
994
 
                }
995
 
 
996
 
                return ok;
997
 
            }
998
 
 
999
 
            if (!type || !fn || !fn.call) {
1000
 
                return this.purgeElement(el, false, type);
1001
 
            }
1002
 
 
1003
 
            id = 'event:' + Y.stamp(el) + type;
1004
 
            ce = _wrappers[id];
1005
 
 
1006
 
            if (ce) {
1007
 
                return ce.detach(fn);
1008
 
            } else {
1009
 
                return false;
1010
 
            }
1011
 
 
1012
 
        },
1013
 
 
1014
 
        /**
1015
 
         * Finds the event in the window object, the caller's arguments, or
1016
 
         * in the arguments of another method in the callstack.  This is
1017
 
         * executed automatically for events registered through the event
1018
 
         * manager, so the implementer should not normally need to execute
1019
 
         * this function at all.
1020
 
         * @method getEvent
1021
 
         * @param {Event} e the event parameter from the handler
1022
 
         * @param {HTMLElement} el the element the listener was attached to
1023
 
         * @return {Event} the event 
1024
 
         * @static
1025
 
         */
1026
 
        getEvent: function(e, el, noFacade) {
1027
 
            var ev = e || win.event;
1028
 
 
1029
 
            return (noFacade) ? ev : 
1030
 
                new Y.DOMEventFacade(ev, el, _wrappers['event:' + Y.stamp(el) + e.type]);
1031
 
        },
1032
 
 
1033
 
        /**
1034
 
         * Generates an unique ID for the element if it does not already 
1035
 
         * have one.
1036
 
         * @method generateId
1037
 
         * @param el the element to create the id for
1038
 
         * @return {string} the resulting id of the element
1039
 
         * @static
1040
 
         */
1041
 
        generateId: function(el) {
1042
 
            var id = el.id;
1043
 
 
1044
 
            if (!id) {
1045
 
                id = Y.stamp(el);
1046
 
                el.id = id;
1047
 
            }
1048
 
 
1049
 
            return id;
1050
 
        },
1051
 
 
1052
 
        /**
1053
 
         * We want to be able to use getElementsByTagName as a collection
1054
 
         * to attach a group of events to.  Unfortunately, different 
1055
 
         * browsers return different types of collections.  This function
1056
 
         * tests to determine if the object is array-like.  It will also 
1057
 
         * fail if the object is an array, but is empty.
1058
 
         * @method _isValidCollection
1059
 
         * @param o the object to test
1060
 
         * @return {boolean} true if the object is array-like and populated
1061
 
         * @deprecated was not meant to be used directly
1062
 
         * @static
1063
 
         * @private
1064
 
         */
1065
 
        _isValidCollection: shouldIterate,
1066
 
 
1067
 
        /**
1068
 
         * hook up any deferred listeners
1069
 
         * @method _load
1070
 
         * @static
1071
 
         * @private
1072
 
         */
1073
 
        _load: function(e) {
1074
 
            if (!_loadComplete) {
1075
 
                // Y.log('Load Complete', 'info', 'event');
1076
 
                _loadComplete = true;
1077
 
 
1078
 
                // Just in case DOMReady did not go off for some reason
1079
 
                // E._ready();
1080
 
                if (Y.fire) {
1081
 
                    Y.fire(EVENT_READY);
1082
 
                }
1083
 
 
1084
 
                // Available elements may not have been detected before the
1085
 
                // window load event fires. Try to find them now so that the
1086
 
                // the user is more likely to get the onAvailable notifications
1087
 
                // before the window load notification
1088
 
                Event._poll();
1089
 
            }
1090
 
        },
1091
 
 
1092
 
        /**
1093
 
         * Polling function that runs before the onload event fires, 
1094
 
         * attempting to attach to DOM Nodes as soon as they are 
1095
 
         * available
1096
 
         * @method _poll
1097
 
         * @static
1098
 
         * @private
1099
 
         */
1100
 
        _poll: function() {
1101
 
            if (this.locked) {
1102
 
                return;
1103
 
            }
1104
 
 
1105
 
            if (Y.UA.ie && !YUI.Env.DOMReady) {
1106
 
                // Hold off if DOMReady has not fired and check current
1107
 
                // readyState to protect against the IE operation aborted
1108
 
                // issue.
1109
 
                this.startInterval();
1110
 
                return;
1111
 
            }
1112
 
 
1113
 
            this.locked = true;
1114
 
 
1115
 
            // Y.log.debug("poll");
1116
 
            // keep trying until after the page is loaded.  We need to 
1117
 
            // check the page load state prior to trying to bind the 
1118
 
            // elements so that we can be certain all elements have been 
1119
 
            // tested appropriately
1120
 
            var i, len, item, el, notAvail, executeItem,
1121
 
                tryAgain = !_loadComplete;
1122
 
 
1123
 
            if (!tryAgain) {
1124
 
                tryAgain = (_retryCount > 0);
1125
 
            }
1126
 
 
1127
 
            // onAvailable
1128
 
            notAvail = [];
1129
 
 
1130
 
            executeItem = function (el, item) {
1131
 
                var context, ov = item.override;
1132
 
                if (item.compat) {
1133
 
                    if (item.override) {
1134
 
                        if (ov === true) {
1135
 
                            context = item.obj;
1136
 
                        } else {
1137
 
                            context = ov;
1138
 
                        }
1139
 
                    } else {
1140
 
                        context = el;
1141
 
                    }
1142
 
                    item.fn.call(context, item.obj);
1143
 
                } else {
1144
 
                    context = item.obj || Y.one(el);
1145
 
                    item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []);
1146
 
                }
1147
 
            };
1148
 
 
1149
 
            // onAvailable
1150
 
            for (i=0,len=_avail.length; i<len; ++i) {
1151
 
                item = _avail[i];
1152
 
                if (item && !item.checkReady) {
1153
 
 
1154
 
                    // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
1155
 
                    el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
1156
 
 
1157
 
                    if (el) {
1158
 
                        // Y.log('avail: ' + el);
1159
 
                        executeItem(el, item);
1160
 
                        _avail[i] = null;
1161
 
                    } else {
1162
 
                        // Y.log('NOT avail: ' + el);
1163
 
                        notAvail.push(item);
1164
 
                    }
1165
 
                }
1166
 
            }
1167
 
 
1168
 
            // onContentReady
1169
 
            for (i=0,len=_avail.length; i<len; ++i) {
1170
 
                item = _avail[i];
1171
 
                if (item && item.checkReady) {
1172
 
 
1173
 
                    // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
1174
 
                    el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
1175
 
 
1176
 
                    if (el) {
1177
 
                        // The element is available, but not necessarily ready
1178
 
                        // @todo should we test parentNode.nextSibling?
1179
 
                        if (_loadComplete || (el.get && el.get('nextSibling')) || el.nextSibling) {
1180
 
                            executeItem(el, item);
1181
 
                            _avail[i] = null;
1182
 
                        }
1183
 
                    } else {
1184
 
                        notAvail.push(item);
1185
 
                    }
1186
 
                }
1187
 
            }
1188
 
 
1189
 
            _retryCount = (notAvail.length === 0) ? 0 : _retryCount - 1;
1190
 
 
1191
 
            if (tryAgain) {
1192
 
                // we may need to strip the nulled out items here
1193
 
                this.startInterval();
1194
 
            } else {
1195
 
                clearInterval(this._interval);
1196
 
                this._interval = null;
1197
 
            }
1198
 
 
1199
 
            this.locked = false;
1200
 
 
1201
 
            return;
1202
 
 
1203
 
        },
1204
 
 
1205
 
        /**
1206
 
         * Removes all listeners attached to the given element via addListener.
1207
 
         * Optionally, the node's children can also be purged.
1208
 
         * Optionally, you can specify a specific type of event to remove.
1209
 
         * @method purgeElement
1210
 
         * @param {HTMLElement} el the element to purge
1211
 
         * @param {boolean} recurse recursively purge this element's children
1212
 
         * as well.  Use with caution.
1213
 
         * @param {string} type optional type of listener to purge. If
1214
 
         * left out, all listeners will be removed
1215
 
         * @static
1216
 
         */
1217
 
        purgeElement: function(el, recurse, type) {
1218
 
            // var oEl = (Y.Lang.isString(el)) ? Y.one(el) : el,
1219
 
            var oEl = (Y.Lang.isString(el)) ?  Y.Selector.query(el, null, true) : el,
1220
 
                lis = this.getListeners(oEl, type), i, len, props, children, child;
1221
 
 
1222
 
            if (recurse && oEl) {
1223
 
                lis = lis || [];
1224
 
                children = Y.Selector.query('*', oEl);
1225
 
                i = 0;
1226
 
                len = children.length;
1227
 
                for (; i < len; ++i) {
1228
 
                    child = this.getListeners(children[i], type);
1229
 
                    if (child) {
1230
 
                        lis = lis.concat(child);
1231
 
                    }
1232
 
                }
1233
 
            }
1234
 
 
1235
 
            if (lis) {
1236
 
                i = 0;
1237
 
                len = lis.length;
1238
 
                for (; i < len; ++i) {
1239
 
                    props = lis[i];
1240
 
                    props.detachAll();
1241
 
                    remove(props.el, props.type, props.fn, props.capture);
1242
 
                    delete _wrappers[props.key];
1243
 
                    delete _el_events[props.domkey][props.key];
1244
 
                }
1245
 
            }
1246
 
 
1247
 
        },
1248
 
 
1249
 
 
1250
 
        /**
1251
 
         * Returns all listeners attached to the given element via addListener.
1252
 
         * Optionally, you can specify a specific type of event to return.
1253
 
         * @method getListeners
1254
 
         * @param el {HTMLElement|string} the element or element id to inspect 
1255
 
         * @param type {string} optional type of listener to return. If
1256
 
         * left out, all listeners will be returned
1257
 
         * @return {Y.Custom.Event} the custom event wrapper for the DOM event(s)
1258
 
         * @static
1259
 
         */           
1260
 
        getListeners: function(el, type) {
1261
 
            var ek = Y.stamp(el, true), evts = _el_events[ek],
1262
 
                results=[] , key = (type) ? 'event:' + ek + type : null,
1263
 
                adapters = _eventenv.plugins;
1264
 
 
1265
 
            if (!evts) {
1266
 
                return null;
1267
 
            }
1268
 
 
1269
 
            if (key) {
1270
 
                // look for synthetic events
1271
 
                if (adapters[type] && adapters[type].eventDef) {
1272
 
                    key += '_synth';
1273
 
                }
1274
 
 
1275
 
                if (evts[key]) {
1276
 
                    results.push(evts[key]);
1277
 
                }
1278
 
 
1279
 
                // get native events as well
1280
 
                key += 'native';
1281
 
                if (evts[key]) {
1282
 
                    results.push(evts[key]);
1283
 
                }
1284
 
 
1285
 
            } else {
1286
 
                Y.each(evts, function(v, k) {
1287
 
                    results.push(v);
1288
 
                });
1289
 
            }
1290
 
 
1291
 
            return (results.length) ? results : null;
1292
 
        },
1293
 
 
1294
 
        /**
1295
 
         * Removes all listeners registered by pe.event.  Called 
1296
 
         * automatically during the unload event.
1297
 
         * @method _unload
1298
 
         * @static
1299
 
         * @private
1300
 
         */
1301
 
        _unload: function(e) {
1302
 
            Y.each(_wrappers, function(v, k) {
1303
 
                v.detachAll();
1304
 
                remove(v.el, v.type, v.fn, v.capture);
1305
 
                delete _wrappers[k];
1306
 
                delete _el_events[v.domkey][k];
1307
 
            });
1308
 
        },
1309
 
 
1310
 
        
1311
 
        /**
1312
 
         * Adds a DOM event directly without the caching, cleanup, context adj, etc
1313
 
         *
1314
 
         * @method nativeAdd
1315
 
         * @param {HTMLElement} el      the element to bind the handler to
1316
 
         * @param {string}      type   the type of event handler
1317
 
         * @param {function}    fn      the callback to invoke
1318
 
         * @param {boolen}      capture capture or bubble phase
1319
 
         * @static
1320
 
         * @private
1321
 
         */
1322
 
        nativeAdd: add,
1323
 
 
1324
 
        /**
1325
 
         * Basic remove listener
1326
 
         *
1327
 
         * @method nativeRemove
1328
 
         * @param {HTMLElement} el      the element to bind the handler to
1329
 
         * @param {string}      type   the type of event handler
1330
 
         * @param {function}    fn      the callback to invoke
1331
 
         * @param {boolen}      capture capture or bubble phase
1332
 
         * @static
1333
 
         * @private
1334
 
         */
1335
 
        nativeRemove: remove
1336
 
    };
1337
 
 
1338
 
}();
1339
 
 
1340
 
Y.Event = Event;
1341
 
 
1342
 
if (config.injected || YUI.Env.windowLoaded) {
1343
 
    onLoad();
1344
 
} else {
1345
 
    add(win, "load", onLoad);
1346
 
}
1347
 
 
1348
 
// Process onAvailable/onContentReady items when when the DOM is ready in IE
1349
 
if (Y.UA.ie) {
1350
 
    Y.on(EVENT_READY, Event._poll, Event, true);
1351
 
}
1352
 
 
1353
 
Y.on("unload", onUnload);
1354
 
 
1355
 
Event.Custom = Y.CustomEvent;
1356
 
Event.Subscriber = Y.Subscriber;
1357
 
Event.Target = Y.EventTarget;
1358
 
Event.Handle = Y.EventHandle;
1359
 
Event.Facade = Y.EventFacade;
1360
 
 
1361
 
Event._poll();
1362
 
 
1363
 
})();
1364
 
 
1365
 
/**
1366
 
 * DOM event listener abstraction layer
1367
 
 * @module event
1368
 
 * @submodule event-base
1369
 
 */
1370
 
 
1371
 
/**
1372
 
 * Executes the callback as soon as the specified element 
1373
 
 * is detected in the DOM.
1374
 
 * @event available
1375
 
 * @param type {string} 'available'
1376
 
 * @param fn {function} the callback function to execute.
1377
 
 * @param el {string|HTMLElement|collection} the element(s) to attach
1378
 
 * @param context optional argument that specifies what 'this' refers to.
1379
 
 * @param args* 0..n additional arguments to pass on to the callback function.
1380
 
 * These arguments will be added after the event object.
1381
 
 * @return {EventHandle} the detach handle
1382
 
 * @for YUI
1383
 
 */
1384
 
Y.Env.evt.plugins.available = {
1385
 
    on: function(type, fn, id, o) {
1386
 
        var a = arguments.length > 4 ?  Y.Array(arguments, 4, true) : [];
1387
 
        return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
1388
 
    }
1389
 
};
1390
 
 
1391
 
/**
1392
 
 * Executes the callback as soon as the specified element 
1393
 
 * is detected in the DOM with a nextSibling property
1394
 
 * (indicating that the element's children are available)
1395
 
 * @event contentready
1396
 
 * @param type {string} 'contentready'
1397
 
 * @param fn {function} the callback function to execute.
1398
 
 * @param el {string|HTMLElement|collection} the element(s) to attach
1399
 
 * @param context optional argument that specifies what 'this' refers to.
1400
 
 * @param args* 0..n additional arguments to pass on to the callback function.
1401
 
 * These arguments will be added after the event object.
1402
 
 * @return {EventHandle} the detach handle
1403
 
 * @for YUI
1404
 
 */
1405
 
Y.Env.evt.plugins.contentready = {
1406
 
    on: function(type, fn, id, o) {
1407
 
        var a = arguments.length > 4 ?  Y.Array(arguments, 4, true) : [];
1408
 
        return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
1409
 
    }
1410
 
};
1411
 
 
1412
 
 
1413
 
}, '3.2.0' ,{requires:['event-custom-base']});
1414
 
YUI.add('event-delegate', function(Y) {
1415
 
 
1416
 
/**
1417
 
 * Adds event delegation support to the library.
1418
 
 * 
1419
 
 * @module event
1420
 
 * @submodule event-delegate
1421
 
 */
1422
 
 
1423
 
var toArray          = Y.Array,
1424
 
    YLang            = Y.Lang,
1425
 
    isString         = YLang.isString,
1426
 
    selectorTest     = Y.Selector.test,
1427
 
    detachCategories = Y.Env.evt.handles;
1428
 
 
1429
 
/**
1430
 
 * <p>Sets up event delegation on a container element.  The delegated event
1431
 
 * will use a supplied selector or filtering function to test if the event
1432
 
 * references at least one node that should trigger the subscription
1433
 
 * callback.</p>
1434
 
 *
1435
 
 * <p>Selector string filters will trigger the callback if the event originated
1436
 
 * from a node that matches it or is contained in a node that matches it.
1437
 
 * Function filters are called for each Node up the parent axis to the
1438
 
 * subscribing container node, and receive at each level the Node and the event
1439
 
 * object.  The function should return true (or a truthy value) if that Node
1440
 
 * should trigger the subscription callback.  Note, it is possible for filters
1441
 
 * to match multiple Nodes for a single event.  In this case, the delegate
1442
 
 * callback will be executed for each matching Node.</p>
1443
 
 *
1444
 
 * <p>For each matching Node, the callback will be executed with its 'this'
1445
 
 * object set to the Node matched by the filter (unless a specific context was
1446
 
 * provided during subscription), and the provided event's
1447
 
 * <code>currentTarget</code> will also be set to the matching Node.  The
1448
 
 * containing Node from which the subscription was originally made can be
1449
 
 * referenced as <code>e.container</code>.
1450
 
 *
1451
 
 * @method delegate
1452
 
 * @param type {String} the event type to delegate
1453
 
 * @param fn {Function} the callback function to execute.  This function
1454
 
 *              will be provided the event object for the delegated event.
1455
 
 * @param el {String|node} the element that is the delegation container
1456
 
 * @param spec {string|Function} a selector that must match the target of the
1457
 
 *              event or a function to test target and its parents for a match
1458
 
 * @param context optional argument that specifies what 'this' refers to.
1459
 
 * @param args* 0..n additional arguments to pass on to the callback function.
1460
 
 *              These arguments will be added after the event object.
1461
 
 * @return {EventHandle} the detach handle
1462
 
 * @for YUI
1463
 
 */
1464
 
function delegate(type, fn, el, filter) {
1465
 
    var args     = toArray(arguments, 0, true),
1466
 
        query    = isString(el) ? el : null,
1467
 
        typeBits = type.split(/\|/),
1468
 
        synth, container, categories, cat, handle;
1469
 
 
1470
 
    if (typeBits.length > 1) {
1471
 
        cat  = typeBits.shift();
1472
 
        type = typeBits.shift();
1473
 
    }
1474
 
 
1475
 
    synth = Y.Node.DOM_EVENTS[type];
1476
 
 
1477
 
    if (YLang.isObject(synth) && synth.delegate) {
1478
 
        handle = synth.delegate.apply(synth, arguments);
1479
 
    }
1480
 
 
1481
 
    if (!handle) {
1482
 
        if (!type || !fn || !el || !filter) {
1483
 
            Y.log("delegate requires type, callback, parent, & filter", "warn");
1484
 
            return;
1485
 
        }
1486
 
 
1487
 
        container = (query) ? Y.Selector.query(query, null, true) : el;
1488
 
 
1489
 
        if (!container && isString(el)) {
1490
 
            handle = Y.on('available', function () {
1491
 
                Y.mix(handle, Y.delegate.apply(Y, args), true);
1492
 
            }, el);
1493
 
        }
1494
 
 
1495
 
        if (!handle && container) {
1496
 
            args.splice(2, 2, container); // remove the filter
1497
 
 
1498
 
            if (isString(filter)) {
1499
 
                filter = Y.delegate.compileFilter(filter);
1500
 
            }
1501
 
 
1502
 
            handle = Y.on.apply(Y, args);
1503
 
            handle.sub.filter  = filter;
1504
 
            handle.sub._notify = delegate.notifySub;
1505
 
        }
1506
 
    }
1507
 
 
1508
 
    if (handle && cat) {
1509
 
        categories = detachCategories[cat]  || (detachCategories[cat] = {});
1510
 
        categories = categories[type] || (categories[type] = []);
1511
 
        categories.push(handle);
1512
 
    }
1513
 
 
1514
 
    return handle;
1515
 
}
1516
 
 
1517
 
/**
1518
 
 * Overrides the <code>_notify</code> method on the normal DOM subscription to inject the filtering logic and only proceed in the case of a match.
1519
 
 * 
1520
 
 * @method delegate.notifySub
1521
 
 * @param thisObj {Object} default 'this' object for the callback
1522
 
 * @param args {Array} arguments passed to the event's <code>fire()</code>
1523
 
 * @param ce {CustomEvent} the custom event managing the DOM subscriptions for
1524
 
 *              the subscribed event on the subscribing node.
1525
 
 * @return {Boolean} false if the event was stopped
1526
 
 * @private
1527
 
 * @static
1528
 
 * @since 3.2.0
1529
 
 */
1530
 
delegate.notifySub = function (thisObj, args, ce) {
1531
 
    // Preserve args for other subscribers
1532
 
    args = args.slice();
1533
 
    if (this.args) {
1534
 
        args.push.apply(args, this.args);
1535
 
    }
1536
 
 
1537
 
    // Only notify subs if the event occurred on a targeted element
1538
 
    var e             = args[0],
1539
 
        currentTarget = delegate._applyFilter(this.filter, args),
1540
 
        container     = e.currentTarget,
1541
 
        i, ret, target;
1542
 
 
1543
 
    if (currentTarget) {
1544
 
        // Support multiple matches up the the container subtree
1545
 
        currentTarget = toArray(currentTarget);
1546
 
 
1547
 
        for (i = currentTarget.length - 1; i >= 0; --i) {
1548
 
            target = currentTarget[i];
1549
 
 
1550
 
            // New facade to avoid corrupting facade sent to direct subs
1551
 
            args[0] = new Y.DOMEventFacade(e, target, ce);
1552
 
 
1553
 
            args[0].container = container;
1554
 
        
1555
 
            thisObj = this.context || target;
1556
 
 
1557
 
            ret = this.fn.apply(thisObj, args);
1558
 
 
1559
 
            if (ret === false) { // stop further notifications
1560
 
                break;
1561
 
            }
1562
 
        }
1563
 
 
1564
 
        return ret;
1565
 
    }
1566
 
};
1567
 
 
1568
 
/**
1569
 
 * <p>Compiles a selector string into a filter function to identify whether
1570
 
 * Nodes along the parent axis of an event's target should trigger event
1571
 
 * notification.</p>
1572
 
 *
1573
 
 * <p>This function is memoized, so previously compiled filter functions are
1574
 
 * returned if the same selector string is provided.</p>
1575
 
 *
1576
 
 * <p>This function may be useful when defining synthetic events for delegate
1577
 
 * handling.</p>
1578
 
 *
1579
 
 * @method delegate.compileFilter
1580
 
 * @param selector {String} the selector string to base the filtration on
1581
 
 * @return {Function}
1582
 
 * @since 3.2.0
1583
 
 * @static
1584
 
 */
1585
 
delegate.compileFilter = Y.cached(function (selector) {
1586
 
    return function (target, e) {
1587
 
        return selectorTest(target._node, selector, e.currentTarget._node);
1588
 
    };
1589
 
});
1590
 
 
1591
 
/**
1592
 
 * Walks up the parent axis of an event's target, and tests each element
1593
 
 * against a supplied filter function.  If any Nodes satisfy the filter, the
1594
 
 * delegated callback will be triggered for each.
1595
 
 *
1596
 
 * @method delegate._applyFilter
1597
 
 * @param filter {Function} boolean function to test for inclusion in event
1598
 
 *                  notification
1599
 
 * @param args {Array} the arguments that would be passed to subscribers
1600
 
 * @return {Node|Node[]|undefined} The Node or Nodes that satisfy the filter
1601
 
 * @protected
1602
 
 */
1603
 
delegate._applyFilter = function (filter, args) {
1604
 
    var e         = args[0],
1605
 
        container = e.currentTarget,
1606
 
        target    = e.target,
1607
 
        match     = [];
1608
 
 
1609
 
    // passing target as the first arg rather than leaving well enough alone
1610
 
    // making 'this' in the filter function refer to the target.  This is to
1611
 
    // support bound filter functions.
1612
 
    args.unshift(target);
1613
 
 
1614
 
    while (target && target !== container) {
1615
 
        // filter(target, e, extra args...) - this === target
1616
 
        if (filter.apply(target, args)) {
1617
 
            match.push(target);
1618
 
        }
1619
 
        args[0] = target = target.get('parentNode');
1620
 
    }
1621
 
 
1622
 
    if (match.length <= 1) {
1623
 
        match = match[0]; // single match or undefined
1624
 
    }
1625
 
 
1626
 
    // remove the target
1627
 
    args.shift();
1628
 
 
1629
 
    return match;
1630
 
};
1631
 
 
1632
 
/**
1633
 
 * Sets up event delegation on a container element.  The delegated event
1634
 
 * will use a supplied filter to test if the callback should be executed.
1635
 
 * This filter can be either a selector string or a function that returns
1636
 
 * a Node to use as the currentTarget for the event.
1637
 
 *
1638
 
 * The event object for the delegated event is supplied to the callback
1639
 
 * function.  It is modified slightly in order to support all properties
1640
 
 * that may be needed for event delegation.  'currentTarget' is set to
1641
 
 * the element that matched the selector string filter or the Node returned
1642
 
 * from the filter function.  'container' is set to the element that the
1643
 
 * listener is delegated from (this normally would be the 'currentTarget').
1644
 
 *
1645
 
 * Filter functions will be called with the arguments that would be passed to
1646
 
 * the callback function, including the event object as the first parameter.
1647
 
 * The function should return false (or a falsey value) if the success criteria
1648
 
 * aren't met, and the Node to use as the event's currentTarget and 'this'
1649
 
 * object if they are.
1650
 
 *
1651
 
 * @method delegate
1652
 
 * @param type {string} the event type to delegate
1653
 
 * @param fn {function} the callback function to execute.  This function
1654
 
 * will be provided the event object for the delegated event.
1655
 
 * @param el {string|node} the element that is the delegation container
1656
 
 * @param filter {string|function} a selector that must match the target of the
1657
 
 * event or a function that returns a Node or false.
1658
 
 * @param context optional argument that specifies what 'this' refers to.
1659
 
 * @param args* 0..n additional arguments to pass on to the callback function.
1660
 
 * These arguments will be added after the event object.
1661
 
 * @return {EventHandle} the detach handle
1662
 
 * @for YUI
1663
 
 */
1664
 
Y.delegate = Y.Event.delegate = delegate;
1665
 
 
1666
 
 
1667
 
}, '3.2.0' ,{requires:['node-base']});
1668
 
YUI.add('event-synthetic', function(Y) {
1669
 
 
1670
 
/**
1671
 
 * Define new DOM events that can be subscribed to from Nodes.
1672
 
 *
1673
 
 * @module event
1674
 
 * @submodule event-synthetic
1675
 
 */
1676
 
var DOMMap   = Y.Env.evt.dom_map,
1677
 
    toArray  = Y.Array,
1678
 
    YLang    = Y.Lang,
1679
 
    isObject = YLang.isObject,
1680
 
    isString = YLang.isString,
1681
 
    query    = Y.Selector.query,
1682
 
    noop     = function () {};
1683
 
 
1684
 
/**
1685
 
 * <p>The triggering mechanism used by SyntheticEvents.</p>
1686
 
 *
1687
 
 * <p>Implementers should not instantiate these directly.  Use the Notifier
1688
 
 * provided to the event's implemented <code>on(node, sub, notifier)</code> or
1689
 
 * <code>delegate(node, sub, notifier, filter)</code> methods.</p>
1690
 
 *
1691
 
 * @class SyntheticEvent.Notifier
1692
 
 * @constructor
1693
 
 * @param handle {EventHandle} the detach handle for the subscription to an
1694
 
 *              internal custom event used to execute the callback passed to
1695
 
 *              on(..) or delegate(..)
1696
 
 * @param emitFacade {Boolean} take steps to ensure the first arg received by
1697
 
 *              the subscription callback is an event facade
1698
 
 * @private
1699
 
 * @since 3.2.0
1700
 
 */
1701
 
function Notifier(handle, emitFacade) {
1702
 
    this.handle     = handle;
1703
 
    this.emitFacade = emitFacade;
1704
 
}
1705
 
 
1706
 
/**
1707
 
 * <p>Executes the subscription callback, passing the firing arguments as the
1708
 
 * first parameters to that callback. For events that are configured with
1709
 
 * emitFacade=true, it is common practice to pass the triggering DOMEventFacade
1710
 
 * as the first parameter.  Barring a proper DOMEventFacade or EventFacade
1711
 
 * (from a CustomEvent), a new EventFacade will be generated.  In that case, if
1712
 
 * fire() is called with a simple object, it will be mixed into the facade.
1713
 
 * Otherwise, the facade will be prepended to the callback parameters.</p>
1714
 
 *
1715
 
 * <p>For notifiers provided to delegate logic, the first argument should be an
1716
 
 * object with a &quot;currentTarget&quot; property to identify what object to
1717
 
 * default as 'this' in the callback.  Typically this is gleaned from the
1718
 
 * DOMEventFacade or EventFacade, but if configured with emitFacade=false, an
1719
 
 * object must be provided.  In that case, the object will be removed from the
1720
 
 * callback parameters.</p>
1721
 
 *
1722
 
 * <p>Additional arguments passed during event subscription will be
1723
 
 * automatically added after those passed to fire().</p>
1724
 
 *
1725
 
 * @method fire
1726
 
 * @param e {EventFacade|DOMEventFacade|Object|any} (see description)
1727
 
 * @param arg* {any} additional arguments received by all subscriptions
1728
 
 * @private
1729
 
 */
1730
 
Notifier.prototype.fire = function (e) {
1731
 
    // first arg to delegate notifier should be an object with currentTarget
1732
 
    var args     = toArray(arguments, 0, true),
1733
 
        handle   = this.handle,
1734
 
        ce       = handle.evt,
1735
 
        sub      = handle.sub,
1736
 
        thisObj  = sub.context,
1737
 
        delegate = sub.filter,
1738
 
        event    = e || {};
1739
 
 
1740
 
    if (this.emitFacade) {
1741
 
        if (!e || !e.preventDefault) {
1742
 
            event = ce._getFacade();
1743
 
 
1744
 
            if (isObject(e) && !e.preventDefault) {
1745
 
                Y.mix(event, e, true);
1746
 
                args[0] = event;
1747
 
            } else {
1748
 
                args.unshift(event);
1749
 
            }
1750
 
        }
1751
 
 
1752
 
        event.type    = ce.type;
1753
 
        event.details = args.slice();
1754
 
 
1755
 
        if (delegate) {
1756
 
            event.container = ce.host;
1757
 
        }
1758
 
    } else if (delegate && isObject(e) && e.currentTarget) {
1759
 
        args.shift();
1760
 
    }
1761
 
 
1762
 
    sub.context = thisObj || event.currentTarget || ce.host;
1763
 
    ce.fire.apply(ce, args);
1764
 
    sub.context = thisObj; // reset for future firing
1765
 
};
1766
 
 
1767
 
 
1768
 
/**
1769
 
 * <p>Wrapper class for the integration of new events into the YUI event
1770
 
 * infrastructure.  Don't instantiate this object directly, use
1771
 
 * <code>Y.Event.define(type, config)</code>.  See that method for details.</p>
1772
 
 *
1773
 
 * <p>Properties that MAY or SHOULD be specified in the configuration are noted
1774
 
 * below and in the description of <code>Y.Event.define</code>.</p>
1775
 
 *
1776
 
 * @class SyntheticEvent
1777
 
 * @constructor
1778
 
 * @param cfg {Object} Implementation pieces and configuration
1779
 
 * @since 3.1.0
1780
 
 * @in event-synthetic
1781
 
 */
1782
 
function SyntheticEvent() {
1783
 
    this._init.apply(this, arguments);
1784
 
}
1785
 
 
1786
 
Y.mix(SyntheticEvent, {
1787
 
    Notifier: Notifier,
1788
 
 
1789
 
    /**
1790
 
     * Returns the array of subscription handles for a node for the given event
1791
 
     * type.  Passing true as the third argument will create a registry entry
1792
 
     * in the event system's DOM map to host the array if one doesn't yet exist.
1793
 
     *
1794
 
     * @method getRegistry
1795
 
     * @param node {Node} the node
1796
 
     * @param type {String} the event
1797
 
     * @param create {Boolean} create a registration entry to host a new array
1798
 
     *                  if one doesn't exist.
1799
 
     * @return {Array}
1800
 
     * @static
1801
 
     * @protected
1802
 
     * @since 3.2.0
1803
 
     */
1804
 
    getRegistry: function (node, type, create) {
1805
 
        var el     = node._node,
1806
 
            yuid   = Y.stamp(el),
1807
 
            key    = 'event:' + yuid + type + '_synth',
1808
 
            events = DOMMap[yuid] || (DOMMap[yuid] = {});
1809
 
 
1810
 
        if (!events[key] && create) {
1811
 
            events[key] = {
1812
 
                type      : '_synth',
1813
 
                fn        : noop,
1814
 
                capture   : false,
1815
 
                el        : el,
1816
 
                key       : key,
1817
 
                domkey    : yuid,
1818
 
                notifiers : [],
1819
 
 
1820
 
                detachAll : function () {
1821
 
                    var notifiers = this.notifiers,
1822
 
                        i = notifiers.length;
1823
 
 
1824
 
                    while (--i >= 0) {
1825
 
                        notifiers[i].detach();
1826
 
                    }
1827
 
                }
1828
 
            };
1829
 
        }
1830
 
 
1831
 
        return (events[key]) ? events[key].notifiers : null;
1832
 
    },
1833
 
 
1834
 
    /**
1835
 
     * Alternate <code>_delete()</code> method for the CustomEvent object
1836
 
     * created to manage SyntheticEvent subscriptions.
1837
 
     *
1838
 
     * @method _deleteSub
1839
 
     * @param sub {Subscription} the subscription to clean up
1840
 
     * @private
1841
 
     * @since 3.2.0
1842
 
     */
1843
 
    _deleteSub: function (sub) {
1844
 
        if (sub && sub.fn) {
1845
 
            var synth = this.eventDef,
1846
 
                method = (sub.filter) ? 'detachDelegate' : 'detach';
1847
 
 
1848
 
            this.subscribers = {};
1849
 
            this.subCount = 0;
1850
 
 
1851
 
            synth[method](sub.node, sub, this.notifier, sub.filter);
1852
 
            synth._unregisterSub(sub);
1853
 
 
1854
 
            delete sub.fn;
1855
 
            delete sub.node;
1856
 
            delete sub.context;
1857
 
        }
1858
 
    },
1859
 
 
1860
 
    prototype: {
1861
 
        constructor: SyntheticEvent,
1862
 
 
1863
 
        /**
1864
 
         * Construction logic for the event.
1865
 
         *
1866
 
         * @method _init
1867
 
         * @protected
1868
 
         */
1869
 
        _init: function () {
1870
 
            var config = this.publishConfig || (this.publishConfig = {});
1871
 
 
1872
 
            // The notification mechanism handles facade creation
1873
 
            this.emitFacade = ('emitFacade' in config) ?
1874
 
                                config.emitFacade :
1875
 
                                true;
1876
 
            config.emitFacade  = false;
1877
 
        },
1878
 
 
1879
 
        /**
1880
 
         * <p>Implementers MAY provide this method definition.</p>
1881
 
         *
1882
 
         * <p>Implement this function if the event supports a different
1883
 
         * subscription signature.  This function is used by both
1884
 
         * <code>on()</code> and <code>delegate()</code>.  The second parameter
1885
 
         * indicates that the event is being subscribed via
1886
 
         * <code>delegate()</code>.</p>
1887
 
         *
1888
 
         * <p>Implementations must remove extra arguments from the args list
1889
 
         * before returning.  The required args for <code>on()</code>
1890
 
         * subscriptions are</p>
1891
 
         * <pre><code>[type, callback, target, context, argN...]</code></pre>
1892
 
         *
1893
 
         * <p>The required args for <code>delegate()</code>
1894
 
         * subscriptions are</p>
1895
 
         *
1896
 
         * <pre><code>[type, callback, target, filter, context, argN...]</code></pre>
1897
 
         *
1898
 
         * <p>The return value from this function will be stored on the
1899
 
         * subscription in the '_extra' property for reference elsewhere.</p>
1900
 
         *
1901
 
         * @method processArgs
1902
 
         * @param args {Array} parmeters passed to Y.on(..) or Y.delegate(..)
1903
 
         * @param delegate {Boolean} true if the subscription is from Y.delegate
1904
 
         * @return {any}
1905
 
         */
1906
 
        processArgs: noop,
1907
 
 
1908
 
        /**
1909
 
         * <p>Implementers MAY override this property.</p>
1910
 
         *
1911
 
         * <p>Whether to prevent multiple subscriptions to this event that are
1912
 
         * classified as being the same.  By default, this means the subscribed
1913
 
         * callback is the same function.  See the <code>subMatch</code>
1914
 
         * method.  Setting this to true will impact performance for high volume
1915
 
         * events.</p>
1916
 
         *
1917
 
         * @property preventDups
1918
 
         * @type {Boolean}
1919
 
         * @default false
1920
 
         */
1921
 
        //preventDups  : false,
1922
 
 
1923
 
        /**
1924
 
         * <p>Implementers SHOULD provide this method definition.</p>
1925
 
         *
1926
 
         * Implementation logic for subscriptions done via <code>node.on(type,
1927
 
         * fn)</code> or <code>Y.on(type, fn, target)</code>.  This
1928
 
         * function should set up the monitor(s) that will eventually fire the
1929
 
         * event.  Typically this involves subscribing to at least one DOM
1930
 
         * event.  It is recommended to store detach handles from any DOM
1931
 
         * subscriptions to make for easy cleanup in the <code>detach</code>
1932
 
         * method.  Typically these handles are added to the <code>sub</code>
1933
 
         * object.  Also for SyntheticEvents that leverage a single DOM
1934
 
         * subscription under the hood, it is recommended to pass the DOM event
1935
 
         * object to <code>notifier.fire(e)</code>.  (The event name on the
1936
 
         * object will be updated).
1937
 
         *
1938
 
         * @method on
1939
 
         * @param node {Node} the node the subscription is being applied to
1940
 
         * @param sub {Subscription} the object to track this subscription
1941
 
         * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to
1942
 
         *              trigger the execution of the subscribers
1943
 
         */
1944
 
        on: noop,
1945
 
 
1946
 
        /**
1947
 
         * <p>Implementers SHOULD provide this method definition.</p>
1948
 
         *
1949
 
         * <p>Implementation logic for detaching subscriptions done via
1950
 
         * <code>node.on(type, fn)</code>.  This function should clean up any
1951
 
         * subscriptions made in the <code>on()</code> phase.</p>
1952
 
         *
1953
 
         * @method detach
1954
 
         * @param node {Node} the node the subscription was applied to
1955
 
         * @param sub {Subscription} the object tracking this subscription
1956
 
         * @param notifier {SyntheticEvent.Notifier} the Notifier used to
1957
 
         *              trigger the execution of the subscribers
1958
 
         */
1959
 
        detach: noop,
1960
 
 
1961
 
        /**
1962
 
         * <p>Implementers SHOULD provide this method definition.</p>
1963
 
         *
1964
 
         * <p>Implementation logic for subscriptions done via
1965
 
         * <code>node.delegate(type, fn, filter)</code> or
1966
 
         * <code>Y.delegate(type, fn, container, filter)</code>.  Like with
1967
 
         * <code>on()</code> above, this function should monitor the environment
1968
 
         * for the event being fired, and trigger subscription execution by
1969
 
         * calling <code>notifier.fire(e)</code>.</p>
1970
 
         *
1971
 
         * <p>This function receives a fourth argument, which is the filter
1972
 
         * used to identify which Node's are of interest to the subscription.
1973
 
         * The filter will be either a boolean function that accepts a target
1974
 
         * Node for each hierarchy level as the event bubbles, or a selector
1975
 
         * string.  To translate selector strings into filter functions, use
1976
 
         * <code>Y.delegate.compileFilter(filter)</code>.</p>
1977
 
         *
1978
 
         * @method delegate
1979
 
         * @param node {Node} the node the subscription is being applied to
1980
 
         * @param sub {Subscription} the object to track this subscription
1981
 
         * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to
1982
 
         *              trigger the execution of the subscribers
1983
 
         * @param filter {String|Function} Selector string or function that
1984
 
         *              accepts an event object and returns null, a Node, or an
1985
 
         *              array of Nodes matching the criteria for processing.
1986
 
         * @since 3.2.0
1987
 
         */
1988
 
        delegate       : noop,
1989
 
 
1990
 
        /**
1991
 
         * <p>Implementers SHOULD provide this method definition.</p>
1992
 
         *
1993
 
         * <p>Implementation logic for detaching subscriptions done via
1994
 
         * <code>node.delegate(type, fn, filter)</code> or
1995
 
         * <code>Y.delegate(type, fn, container, filter)</code>.  This function
1996
 
         * should clean up any subscriptions made in the
1997
 
         * <code>delegate()</code> phase.</p>
1998
 
         *
1999
 
         * @method detachDelegate
2000
 
         * @param node {Node} the node the subscription was applied to
2001
 
         * @param sub {Subscription} the object tracking this subscription
2002
 
         * @param notifier {SyntheticEvent.Notifier} the Notifier used to
2003
 
         *              trigger the execution of the subscribers
2004
 
         * @param filter {String|Function} Selector string or function that
2005
 
         *              accepts an event object and returns null, a Node, or an
2006
 
         *              array of Nodes matching the criteria for processing.
2007
 
         * @since 3.2.0
2008
 
         */
2009
 
        detachDelegate : noop,
2010
 
 
2011
 
        /**
2012
 
         * Sets up the boilerplate for detaching the event and facilitating the
2013
 
         * execution of subscriber callbacks.
2014
 
         *
2015
 
         * @method _on
2016
 
         * @param args {Array} array of arguments passed to
2017
 
         *              <code>Y.on(...)</code> or <code>Y.delegate(...)</code>
2018
 
         * @param delegate {Boolean} true if called from
2019
 
         * <code>Y.delegate(...)</code>
2020
 
         * @return {EventHandle} the detach handle for this subscription
2021
 
         * @private
2022
 
         * since 3.2.0
2023
 
         */
2024
 
        _on: function (args, delegate) {
2025
 
            var handles  = [],
2026
 
                selector = args[2],
2027
 
                method   = delegate ? 'delegate' : 'on',
2028
 
                nodes, handle;
2029
 
 
2030
 
            // Can't just use Y.all because it doesn't support window (yet?)
2031
 
            nodes = (isString(selector)) ? query(selector) : toArray(selector);
2032
 
 
2033
 
            if (!nodes.length && isString(selector)) {
2034
 
                handle = Y.on('available', function () {
2035
 
                    Y.mix(handle, Y[method].apply(Y, args), true);
2036
 
                }, selector);
2037
 
 
2038
 
                return handle;
2039
 
            }
2040
 
 
2041
 
            Y.each(nodes, function (node) {
2042
 
                var subArgs = args.slice(),
2043
 
                    extra, filter;
2044
 
 
2045
 
                node = Y.one(node);
2046
 
 
2047
 
                if (node) {
2048
 
                    extra = this.processArgs(subArgs, delegate);
2049
 
 
2050
 
                    if (delegate) {
2051
 
                        filter = subArgs.splice(3, 1)[0];
2052
 
                    }
2053
 
 
2054
 
                    // (type, fn, el, thisObj, ...) => (fn, thisObj, ...)
2055
 
                    subArgs.splice(0, 4, subArgs[1], subArgs[3]);
2056
 
 
2057
 
                    if (!this.preventDups || !this.getSubs(node, args,null,true)) {
2058
 
                        handle = this._getNotifier(node, subArgs, extra,filter);
2059
 
 
2060
 
                        this[method](node, handle.sub, handle.notifier, filter);
2061
 
 
2062
 
                        handles.push(handle);
2063
 
                    }
2064
 
                }
2065
 
            }, this);
2066
 
 
2067
 
            return (handles.length === 1) ?
2068
 
                handles[0] :
2069
 
                new Y.EventHandle(handles);
2070
 
        },
2071
 
 
2072
 
        /**
2073
 
         * Creates a new Notifier object for use by this event's
2074
 
         * <code>on(...)</code> or <code>delegate(...)</code> implementation.
2075
 
         *
2076
 
         * @method _getNotifier
2077
 
         * @param node {Node} the Node hosting the event
2078
 
         * @param args {Array} the subscription arguments passed to either
2079
 
         *              <code>Y.on(...)</code> or <code>Y.delegate(...)</code>
2080
 
         *              after running through <code>processArgs(args)</code> to
2081
 
         *              normalize the argument signature
2082
 
         * @param extra {any} Extra data parsed from
2083
 
         *              <code>processArgs(args)</code>
2084
 
         * @param filter {String|Function} the selector string or function
2085
 
         *              filter passed to <code>Y.delegate(...)</code> (not
2086
 
         *              present when called from <code>Y.on(...)</code>)
2087
 
         * @return {SyntheticEvent.Notifier}
2088
 
         * @private
2089
 
         * @since 3.2.0
2090
 
         */
2091
 
        _getNotifier: function (node, args, extra, filter) {
2092
 
            var dispatcher = new Y.CustomEvent(this.type, this.publishConfig),
2093
 
                handle     = dispatcher.on.apply(dispatcher, args),
2094
 
                notifier   = new Notifier(handle, this.emitFacade),
2095
 
                registry   = SyntheticEvent.getRegistry(node, this.type, true),
2096
 
                sub        = handle.sub;
2097
 
 
2098
 
            handle.notifier   = notifier;
2099
 
 
2100
 
            sub.node   = node;
2101
 
            sub.filter = filter;
2102
 
            sub._extra = extra;
2103
 
 
2104
 
            Y.mix(dispatcher, {
2105
 
                eventDef     : this,
2106
 
                notifier     : notifier,
2107
 
                host         : node,       // I forget what this is for
2108
 
                currentTarget: node,       // for generating facades
2109
 
                target       : node,       // for generating facades
2110
 
                el           : node._node, // For category detach
2111
 
 
2112
 
                _delete      : SyntheticEvent._deleteSub
2113
 
            }, true);
2114
 
 
2115
 
            registry.push(handle);
2116
 
 
2117
 
            return handle;
2118
 
        },
2119
 
 
2120
 
        /**
2121
 
         * Removes the subscription from the Notifier registry.
2122
 
         *
2123
 
         * @method _unregisterSub
2124
 
         * @param sub {Subscription} the subscription
2125
 
         * @private
2126
 
         * @since 3.2.0
2127
 
         */
2128
 
        _unregisterSub: function (sub) {
2129
 
            var notifiers = SyntheticEvent.getRegistry(sub.node, this.type),
2130
 
                i;
2131
 
                
2132
 
            if (notifiers) {
2133
 
                for (i = notifiers.length - 1; i >= 0; --i) {
2134
 
                    if (notifiers[i].sub === sub) {
2135
 
                        notifiers.splice(i, 1);
2136
 
                        break;
2137
 
                    }
2138
 
                }
2139
 
            }
2140
 
        },
2141
 
 
2142
 
        /**
2143
 
         * Removes the subscription(s) from the internal subscription dispatch
2144
 
         * mechanism.  See <code>SyntheticEvent._deleteSub</code>.
2145
 
         *
2146
 
         * @method _detach
2147
 
         * @param args {Array} The arguments passed to
2148
 
         *                  <code>node.detach(...)</code>
2149
 
         * @private
2150
 
         * @since 3.2.0
2151
 
         */
2152
 
        _detach: function (args) {
2153
 
            // Can't use Y.all because it doesn't support window (yet?)
2154
 
            // TODO: Does Y.all support window now?
2155
 
            var target = args[2],
2156
 
                els    = (isString(target)) ?
2157
 
                            query(target) : toArray(target),
2158
 
                node, i, len, handles, j;
2159
 
            
2160
 
            // (type, fn, el, context, filter?) => (type, fn, context, filter?)
2161
 
            args.splice(2, 1);
2162
 
 
2163
 
            for (i = 0, len = els.length; i < len; ++i) {
2164
 
                node = Y.one(els[i]);
2165
 
 
2166
 
                if (node) {
2167
 
                    handles = this.getSubs(node, args);
2168
 
 
2169
 
                    if (handles) {
2170
 
                        for (j = handles.length - 1; j >= 0; --j) {
2171
 
                            handles[j].detach();
2172
 
                        }
2173
 
                    }
2174
 
                }
2175
 
            }
2176
 
        },
2177
 
 
2178
 
        /**
2179
 
         * Returns the detach handles of subscriptions on a node that satisfy a
2180
 
         * search/filter function.  By default, the filter used is the
2181
 
         * <code>subMatch</code> method.
2182
 
         *
2183
 
         * @method getSubs
2184
 
         * @param node {Node} the node hosting the event
2185
 
         * @param args {Array} the array of original subscription args passed
2186
 
         *              to <code>Y.on(...)</code> (before
2187
 
         *              <code>processArgs</code>
2188
 
         * @param filter {Function} function used to identify a subscription
2189
 
         *              for inclusion in the returned array
2190
 
         * @param first {Boolean} stop after the first match (used to check for
2191
 
         *              duplicate subscriptions)
2192
 
         * @return {Array} detach handles for the matching subscriptions
2193
 
         */
2194
 
        getSubs: function (node, args, filter, first) {
2195
 
            var notifiers = SyntheticEvent.getRegistry(node, this.type),
2196
 
                handles = [],
2197
 
                i, len, handle;
2198
 
 
2199
 
            if (notifiers) {
2200
 
                if (!filter) {
2201
 
                    filter = this.subMatch;
2202
 
                }
2203
 
 
2204
 
                for (i = 0, len = notifiers.length; i < len; ++i) {
2205
 
                    handle = notifiers[i];
2206
 
                    if (filter.call(this, handle.sub, args)) {
2207
 
                        if (first) {
2208
 
                            return handle;
2209
 
                        } else {
2210
 
                            handles.push(notifiers[i]);
2211
 
                        }
2212
 
                    }
2213
 
                }
2214
 
            }
2215
 
 
2216
 
            return handles.length && handles;
2217
 
        },
2218
 
 
2219
 
        /**
2220
 
         * <p>Implementers MAY override this to define what constitutes a
2221
 
         * &quot;same&quot; subscription.  Override implementations should
2222
 
         * consider the lack of a comparator as a match, so calling
2223
 
         * <code>getSubs()</code> with no arguments will return all subs.</p>
2224
 
         *
2225
 
         * <p>Compares a set of subscription arguments against a Subscription
2226
 
         * object to determine if they match.  The default implementation
2227
 
         * compares the callback function against the second argument passed to
2228
 
         * <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p>
2229
 
         *
2230
 
         * @method subMatch
2231
 
         * @param sub {Subscription} the existing subscription
2232
 
         * @param args {Array} the calling arguments passed to
2233
 
         *                  <code>Y.on(...)</code> etc.
2234
 
         * @return {Boolean} true if the sub can be described by the args
2235
 
         *                  present
2236
 
         * @since 3.2.0
2237
 
         */
2238
 
        subMatch: function (sub, args) {
2239
 
            // Default detach cares only about the callback matching
2240
 
            return !args[1] || sub.fn === args[1];
2241
 
        }
2242
 
    }
2243
 
}, true);
2244
 
 
2245
 
Y.SyntheticEvent = SyntheticEvent;
2246
 
 
2247
 
/**
2248
 
 * <p>Defines a new event in the DOM event system.  Implementers are
2249
 
 * responsible for monitoring for a scenario whereby the event is fired.  A
2250
 
 * notifier object is provided to the functions identified below.  When the
2251
 
 * criteria defining the event are met, call notifier.fire( [args] ); to
2252
 
 * execute event subscribers.</p>
2253
 
 *
2254
 
 * <p>The first parameter is the name of the event.  The second parameter is a
2255
 
 * configuration object which define the behavior of the event system when the
2256
 
 * new event is subscribed to or detached from.  The methods that should be
2257
 
 * defined in this configuration object are <code>on</code>,
2258
 
 * <code>detach</code>, <code>delegate</code>, and <code>detachDelegate</code>.
2259
 
 * You are free to define any other methods or properties needed to define your
2260
 
 * event.  Be aware, however, that since the object is used to subclass
2261
 
 * SyntheticEvent, you should avoid method names used by SyntheticEvent unless
2262
 
 * your intention is to override the default behavior.</p>
2263
 
 *
2264
 
 * <p>This is a list of properties and methods that you can or should specify
2265
 
 * in the configuration object:</p>
2266
 
 *
2267
 
 * <dl>
2268
 
 *   <dt><code>on</code></dt>
2269
 
 *       <dd><code>function (node, subscription, notifier)</code> The
2270
 
 *       implementation logic for subscription.  Any special setup you need to
2271
 
 *       do to create the environment for the event being fired--E.g. native
2272
 
 *       DOM event subscriptions.  Store subscription related objects and
2273
 
 *       state on the <code>subscription</code> object.  When the
2274
 
 *       criteria have been met to fire the synthetic event, call
2275
 
 *       <code>notifier.fire(e)</code>.  See Notifier's <code>fire()</code>
2276
 
 *       method for details about what to pass as parameters.</dd>
2277
 
 *
2278
 
 *   <dt><code>detach</code></dt>
2279
 
 *       <dd><code>function (node, subscription, notifier)</code> The
2280
 
 *       implementation logic for cleaning up a detached subscription. E.g.
2281
 
 *       detach any DOM subscriptions added in <code>on</code>.</dd>
2282
 
 *
2283
 
 *   <dt><code>delegate</code></dt>
2284
 
 *       <dd><code>function (node, subscription, notifier, filter)</code> The
2285
 
 *       implementation logic for subscription via <code>Y.delegate</code> or
2286
 
 *       <code>node.delegate</code>.  The filter is typically either a selector
2287
 
 *       string or a function.  You can use
2288
 
 *       <code>Y.delegate.compileFilter(selectorString)</code> to create a
2289
 
 *       filter function from a selector string if needed.  The filter function
2290
 
 *       expects an event object as input and should output either null, a
2291
 
 *       matching Node, or an array of matching Nodes.  Otherwise, this acts
2292
 
 *       like <code>on</code> DOM event subscriptions.  Store subscription
2293
 
 *       related objects and information on the <code>subscription</code>
2294
 
 *       object.  When the criteria have been met to fire the synthetic event,
2295
 
 *       call <code>notifier.fire(e)</code> as noted above.</dd>
2296
 
 *
2297
 
 *   <dt><code>detachDelegate</code></dt>
2298
 
 *       <dd><code>function (node, subscription, notifier)</code> The
2299
 
 *       implementation logic for cleaning up a detached delegate subscription.
2300
 
 *       E.g. detach any DOM delegate subscriptions added in
2301
 
 *       <code>delegate</code>.</dd>
2302
 
 *
2303
 
 *   <dt><code>publishConfig</code></dt>
2304
 
 *       <dd>(Object) The configuration object that will be used to instantiate
2305
 
 *       the underlying CustomEvent. See Notifier's <code>fire</code> method
2306
 
 *       for details.</dd>
2307
 
 *
2308
 
 *   <dt><code>processArgs</code></dt
2309
 
 *       <dd>
2310
 
 *          <p><code>function (argArray, fromDelegate)</code> Optional method
2311
 
 *          to extract any additional arguments from the subscription
2312
 
 *          signature.  Using this allows <code>on</code> or
2313
 
 *          <code>delegate</code> signatures like
2314
 
 *          <code>node.on(&quot;hover&quot;, overCallback,
2315
 
 *          outCallback)</code>.</p>
2316
 
 *          <p>When processing an atypical argument signature, make sure the
2317
 
 *          args array is returned to the normal signature before returning
2318
 
 *          from the function.  For example, in the &quot;hover&quot; example
2319
 
 *          above, the <code>outCallback</code> needs to be <code>splice</code>d
2320
 
 *          out of the array.  The expected signature of the args array for
2321
 
 *          <code>on()</code> subscriptions is:</p>
2322
 
 *          <pre>
2323
 
 *              <code>[type, callback, target, contextOverride, argN...]</code>
2324
 
 *          </pre>
2325
 
 *          <p>And for <code>delegate()</code>:</p>
2326
 
 *          <pre>
2327
 
 *              <code>[type, callback, target, filter, contextOverride, argN...]</code>
2328
 
 *          </pre>
2329
 
 *          <p>where <code>target</code> is the node the event is being
2330
 
 *          subscribed for.  You can see these signatures documented for
2331
 
 *          <code>Y.on()</code> and <code>Y.delegate()</code> respectively.</p>
2332
 
 *          <p>Whatever gets returned from the function will be stored on the
2333
 
 *          <code>subscription</code> object under
2334
 
 *          <code>subscription._extra</code>.</p></dd>
2335
 
 *   <dt><code>subMatch</code></dt>
2336
 
 *       <dd>
2337
 
 *           <p><code>function (sub, args)</code>  Compares a set of
2338
 
 *           subscription arguments against a Subscription object to determine
2339
 
 *           if they match.  The default implementation compares the callback
2340
 
 *           function against the second argument passed to
2341
 
 *           <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p>
2342
 
 *       </dd>
2343
 
 * </dl>
2344
 
 *
2345
 
 * @method Event.define
2346
 
 * @param type {String} the name of the event
2347
 
 * @param config {Object} the prototype definition for the new event (see above)
2348
 
 * @param force {Boolean} override an existing event (use with caution)
2349
 
 * @static
2350
 
 * @return {SyntheticEvent} the subclass implementation instance created to
2351
 
 *              handle event subscriptions of this type
2352
 
 * @for Event
2353
 
 * @since 3.1.0
2354
 
 * @in event-synthetic
2355
 
 */
2356
 
Y.Event.define = function (type, config, force) {
2357
 
    if (!config) {
2358
 
        config = {};
2359
 
    }
2360
 
 
2361
 
    var eventDef = (isObject(type)) ? type : Y.merge({ type: type }, config),
2362
 
        Impl, synth;
2363
 
 
2364
 
    if (force || !Y.Node.DOM_EVENTS[eventDef.type]) {
2365
 
        Impl = function () {
2366
 
            SyntheticEvent.apply(this, arguments);
2367
 
        };
2368
 
        Y.extend(Impl, SyntheticEvent, eventDef);
2369
 
        synth = new Impl();
2370
 
 
2371
 
        type = synth.type;
2372
 
 
2373
 
        Y.Node.DOM_EVENTS[type] = Y.Env.evt.plugins[type] = {
2374
 
            eventDef: synth,
2375
 
 
2376
 
            on: function () {
2377
 
                return synth._on(toArray(arguments));
2378
 
            },
2379
 
 
2380
 
            delegate: function () {
2381
 
                return synth._on(toArray(arguments), true);
2382
 
            },
2383
 
 
2384
 
            detach: function () {
2385
 
                return synth._detach(toArray(arguments));
2386
 
            }
2387
 
        };
2388
 
 
2389
 
    }
2390
 
 
2391
 
    return synth;
2392
 
};
2393
 
 
2394
 
 
2395
 
}, '3.2.0' ,{requires:['node-base', 'event-custom']});
2396
 
YUI.add('event-mousewheel', function(Y) {
2397
 
 
2398
 
/**
2399
 
 * Adds mousewheel event support
2400
 
 * @module event
2401
 
 * @submodule event-mousewheel
2402
 
 */
2403
 
var DOM_MOUSE_SCROLL = 'DOMMouseScroll',
2404
 
    fixArgs = function(args) {
2405
 
        var a = Y.Array(args, 0, true), target;
2406
 
        if (Y.UA.gecko) {
2407
 
            a[0] = DOM_MOUSE_SCROLL;
2408
 
            target = Y.config.win;
2409
 
        } else {
2410
 
            target = Y.config.doc;
2411
 
        }
2412
 
 
2413
 
        if (a.length < 3) {
2414
 
            a[2] = target;
2415
 
        } else {
2416
 
            a.splice(2, 0, target);
2417
 
        }
2418
 
 
2419
 
        return a;
2420
 
    };
2421
 
 
2422
 
/**
2423
 
 * Mousewheel event.  This listener is automatically attached to the
2424
 
 * correct target, so one should not be supplied.  Mouse wheel 
2425
 
 * direction and velocity is stored in the 'mouseDelta' field.
2426
 
 * @event mousewheel
2427
 
 * @param type {string} 'mousewheel'
2428
 
 * @param fn {function} the callback to execute
2429
 
 * @param context optional context object
2430
 
 * @param args 0..n additional arguments to provide to the listener.
2431
 
 * @return {EventHandle} the detach handle
2432
 
 * @for YUI
2433
 
 */
2434
 
Y.Env.evt.plugins.mousewheel = {
2435
 
    on: function() {
2436
 
        return Y.Event._attach(fixArgs(arguments));
2437
 
    },
2438
 
 
2439
 
    detach: function() {
2440
 
        return Y.Event.detach.apply(Y.Event, fixArgs(arguments));
2441
 
    }
2442
 
};
2443
 
 
2444
 
 
2445
 
}, '3.2.0' ,{requires:['node-base']});
2446
 
YUI.add('event-mouseenter', function(Y) {
2447
 
 
2448
 
/**
2449
 
 * <p>Adds subscription and delegation support for mouseenter and mouseleave
2450
 
 * events.  Unlike mouseover and mouseout, these events aren't fired from child
2451
 
 * elements of a subscribed node.</p>
2452
 
 *
2453
 
 * <p>This avoids receiving three mouseover notifications from a setup like</p>
2454
 
 *
2455
 
 * <pre><code>div#container > p > a[href]</code></pre>
2456
 
 *
2457
 
 * <p>where</p>
2458
 
 *
2459
 
 * <pre><code>Y.one('#container').on('mouseover', callback)</code></pre>
2460
 
 *
2461
 
 * <p>When the mouse moves over the link, one mouseover event is fired from
2462
 
 * #container, then when the mouse moves over the p, another mouseover event is
2463
 
 * fired and bubbles to #container, causing a second notification, and finally
2464
 
 * when the mouse moves over the link, a third mouseover event is fired and
2465
 
 * bubbles to #container for a third notification.</p>
2466
 
 *
2467
 
 * <p>By contrast, using mouseenter instead of mouseover, the callback would be
2468
 
 * executed only once when the mouse moves over #container.</p>
2469
 
 *
2470
 
 * @module event
2471
 
 * @submodule event-mouseenter
2472
 
 */
2473
 
function notify(e, notifier) {
2474
 
    var current = e.currentTarget,
2475
 
        related = e.relatedTarget;
2476
 
 
2477
 
    if (current !== related && !current.contains(related)) {
2478
 
        notifier.fire(e);
2479
 
    }
2480
 
}
2481
 
 
2482
 
var config = {
2483
 
    proxyType: "mouseover",
2484
 
 
2485
 
    on: function (node, sub, notifier) {
2486
 
        sub.onHandle = node.on(this.proxyType, notify, null, notifier);
2487
 
    },
2488
 
 
2489
 
    detach: function (node, sub) {
2490
 
        sub.onHandle.detach();
2491
 
    },
2492
 
 
2493
 
    delegate: function (node, sub, notifier, filter) {
2494
 
        sub.delegateHandle =
2495
 
            Y.delegate(this.proxyType, notify, node, filter, null, notifier);
2496
 
    },
2497
 
 
2498
 
    detachDelegate: function (node, sub) {
2499
 
        sub.delegateHandle.detach();
2500
 
    }
2501
 
};
2502
 
 
2503
 
Y.Event.define("mouseenter", config, true);
2504
 
Y.Event.define("mouseleave", Y.merge(config, { proxyType: "mouseout" }), true);
2505
 
 
2506
 
 
2507
 
}, '3.2.0' ,{requires:['event-synthetic']});
2508
 
YUI.add('event-key', function(Y) {
2509
 
 
2510
 
/**
2511
 
 * Functionality to listen for one or more specific key combinations.
2512
 
 * @module event
2513
 
 * @submodule event-key
2514
 
 */
2515
 
 
2516
 
/**
2517
 
 * Add a key listener.  The listener will only be notified if the
2518
 
 * keystroke detected meets the supplied specification.  The
2519
 
 * spec consists of the key event type, followed by a colon,
2520
 
 * followed by zero or more comma separated key codes, followed
2521
 
 * by zero or more modifiers delimited by a plus sign.  Ex:
2522
 
 * press:12,65+shift+ctrl
2523
 
 * @event key
2524
 
 * @for YUI
2525
 
 * @param type {string} 'key'
2526
 
 * @param fn {function} the function to execute
2527
 
 * @param id {string|HTMLElement|collection} the element(s) to bind
2528
 
 * @param spec {string} the keyCode and modifier specification
2529
 
 * @param o optional context object
2530
 
 * @param args 0..n additional arguments to provide to the listener.
2531
 
 * @return {Event.Handle} the detach handle
2532
 
 */
2533
 
Y.Env.evt.plugins.key = {
2534
 
 
2535
 
    on: function(type, fn, id, spec, o) {
2536
 
        var a = Y.Array(arguments, 0, true), parsed, etype, criteria, ename;
2537
 
 
2538
 
        parsed = spec && spec.split(':');
2539
 
 
2540
 
        if (!spec || spec.indexOf(':') == -1 || !parsed[1]) {
2541
 
Y.log('Illegal key spec, creating a regular keypress listener instead.', 'info', 'event');
2542
 
            a[0] = 'key' + ((parsed && parsed[0]) || 'press');
2543
 
            return Y.on.apply(Y, a);
2544
 
        }
2545
 
 
2546
 
        // key event type: 'down', 'up', or 'press'
2547
 
        etype = parsed[0];
2548
 
 
2549
 
        // list of key codes optionally followed by modifiers
2550
 
        criteria = (parsed[1]) ? parsed[1].split(/,|\+/) : null;
2551
 
 
2552
 
        // the name of the custom event that will be created for the spec
2553
 
        ename = (Y.Lang.isString(id) ? id : Y.stamp(id)) + spec;
2554
 
 
2555
 
        ename = ename.replace(/,/g, '_');
2556
 
 
2557
 
        if (!Y.getEvent(ename)) {
2558
 
 
2559
 
            // subscribe spec validator to the DOM event
2560
 
            Y.on(type + etype, function(e) {
2561
 
 
2562
 
                // Y.log('keylistener: ' + e.keyCode);
2563
 
                
2564
 
                var passed = false, failed = false, i, crit, critInt;
2565
 
 
2566
 
                for (i=0; i<criteria.length; i=i+1) {
2567
 
                    crit = criteria[i]; 
2568
 
                    critInt = parseInt(crit, 10);
2569
 
 
2570
 
                    // pass this section if any supplied keyCode 
2571
 
                    // is found
2572
 
                    if (Y.Lang.isNumber(critInt)) {
2573
 
 
2574
 
                        if (e.charCode === critInt) {
2575
 
                            // Y.log('passed: ' + crit);
2576
 
                            passed = true;
2577
 
                        } else {
2578
 
                            failed = true;
2579
 
                            // Y.log('failed: ' + crit);
2580
 
                        }
2581
 
 
2582
 
                    // only check modifier if no keyCode was specified
2583
 
                    // or the keyCode check was successful.  pass only 
2584
 
                    // if every modifier passes
2585
 
                    } else if (passed || !failed) {
2586
 
                        passed = (e[crit + 'Key']);
2587
 
                        failed = !passed;
2588
 
                        // Y.log(crit + ": " + passed);
2589
 
                    }                    
2590
 
                }
2591
 
 
2592
 
                // fire spec custom event if spec if met
2593
 
                if (passed) {
2594
 
                    Y.fire(ename, e);
2595
 
                }
2596
 
 
2597
 
            }, id);
2598
 
 
2599
 
        }
2600
 
 
2601
 
        // subscribe supplied listener to custom event for spec validator
2602
 
        // remove element and spec.
2603
 
        a.splice(2, 2);
2604
 
        a[0] = ename;
2605
 
 
2606
 
        return Y.on.apply(Y, a);
2607
 
    }
2608
 
};
2609
 
 
2610
 
 
2611
 
}, '3.2.0' ,{requires:['node-base']});
2612
 
YUI.add('event-focus', function(Y) {
2613
 
 
2614
 
/**
2615
 
 * Adds bubbling and delegation support to DOM events focus and blur.
2616
 
 * 
2617
 
 * @module event
2618
 
 * @submodule event-focus
2619
 
 */
2620
 
var Event    = Y.Event,
2621
 
    YLang    = Y.Lang,
2622
 
    isString = YLang.isString,
2623
 
    useActivate = YLang.isFunction(
2624
 
        Y.DOM.create('<p onbeforeactivate=";">').onbeforeactivate);
2625
 
 
2626
 
function define(type, proxy, directEvent) {
2627
 
    var nodeDataKey = '_' + type + 'Notifiers';
2628
 
 
2629
 
    Y.Event.define(type, {
2630
 
 
2631
 
        _attach: function (el, notifier, delegate) {
2632
 
            if (Y.DOM.isWindow(el)) {
2633
 
                return Event._attach([type, function (e) {
2634
 
                    notifier.fire(e);
2635
 
                }, el]);
2636
 
            } else {
2637
 
                return Event._attach(
2638
 
                    [proxy, this._proxy, el, this, notifier, delegate],
2639
 
                    { capture: true });
2640
 
            }
2641
 
        },
2642
 
 
2643
 
        _proxy: function (e, notifier, delegate) {
2644
 
            var node       = e.target,
2645
 
                notifiers  = node.getData(nodeDataKey),
2646
 
                yuid       = Y.stamp(e.currentTarget._node),
2647
 
                defer      = (useActivate || e.target !== e.currentTarget),
2648
 
                sub        = notifier.handle.sub,
2649
 
                filterArgs = [node, e].concat(sub.args || []),
2650
 
                directSub;
2651
 
                
2652
 
            notifier.currentTarget = (delegate) ? node : e.currentTarget;
2653
 
            notifier.container     = (delegate) ? e.currentTarget : null;
2654
 
 
2655
 
            if (!sub.filter || sub.filter.apply(node, filterArgs)) {
2656
 
                // Maintain a list to handle subscriptions from nested
2657
 
                // containers div#a>div#b>input #a.on(focus..) #b.on(focus..),
2658
 
                // use one focus or blur subscription that fires notifiers from
2659
 
                // #b then #a to emulate bubble sequence.
2660
 
                if (!notifiers) {
2661
 
                    notifiers = {};
2662
 
                    node.setData(nodeDataKey, notifiers);
2663
 
 
2664
 
                    // only subscribe to the element's focus if the target is
2665
 
                    // not the current target (
2666
 
                    if (defer) {
2667
 
                        directSub = Event._attach(
2668
 
                            [directEvent, this._notify, node._node]).sub;
2669
 
                        directSub.once = true;
2670
 
                    }
2671
 
                }
2672
 
 
2673
 
                if (!notifiers[yuid]) {
2674
 
                    notifiers[yuid] = [];
2675
 
                }
2676
 
 
2677
 
                notifiers[yuid].push(notifier);
2678
 
 
2679
 
                if (!defer) {
2680
 
                    this._notify(e);
2681
 
                }
2682
 
            }
2683
 
        },
2684
 
 
2685
 
        _notify: function (e, container) {
2686
 
            var node        = e.currentTarget,
2687
 
                notifiers   = node.getData(nodeDataKey),
2688
 
                              // document.get('ownerDocument') returns null
2689
 
                doc         = node.get('ownerDocument') || node,
2690
 
                target      = node,
2691
 
                nots        = [],
2692
 
                notifier, i, len;
2693
 
 
2694
 
            if (notifiers) {
2695
 
                // Walk up the parent axis until the origin node, 
2696
 
                while (target && target !== doc) {
2697
 
                    nots.push.apply(nots, notifiers[Y.stamp(target)] || []);
2698
 
                    target = target.get('parentNode');
2699
 
                }
2700
 
                nots.push.apply(nots, notifiers[Y.stamp(doc)] || []);
2701
 
 
2702
 
                for (i = 0, len = nots.length; i < len; ++i) {
2703
 
                    notifier = nots[i];
2704
 
                    e.currentTarget = nots[i].currentTarget;
2705
 
 
2706
 
                    if (notifier.container) {
2707
 
                        e.container = notifier.container;
2708
 
                    } else {
2709
 
                        delete e.container;
2710
 
                    }
2711
 
 
2712
 
                    notifier.fire(e);
2713
 
                }
2714
 
 
2715
 
                // clear the notifications list (mainly for delegation)
2716
 
                node.clearData(nodeDataKey);
2717
 
            }
2718
 
        },
2719
 
 
2720
 
        on: function (node, sub, notifier) {
2721
 
            sub.onHandle = this._attach(node._node, notifier);
2722
 
        },
2723
 
 
2724
 
        detach: function (node, sub) {
2725
 
            sub.onHandle.detach();
2726
 
        },
2727
 
 
2728
 
        delegate: function (node, sub, notifier, filter) {
2729
 
            if (isString(filter)) {
2730
 
                sub.filter = Y.delegate.compileFilter(filter);
2731
 
            }
2732
 
 
2733
 
            sub.delegateHandle = this._attach(node._node, notifier, true);
2734
 
        },
2735
 
 
2736
 
        detachDelegate: function (node, sub) {
2737
 
            sub.delegateHandle.detach();
2738
 
        }
2739
 
    }, true);
2740
 
}
2741
 
 
2742
 
// For IE, we need to defer to focusin rather than focus because
2743
 
// `el.focus(); doSomething();` executes el.onbeforeactivate, el.onactivate,
2744
 
// el.onfocusin, doSomething, then el.onfocus.  All others support capture
2745
 
// phase focus, which executes before doSomething.  To guarantee consistent
2746
 
// behavior for this use case, IE's direct subscriptions are made against
2747
 
// focusin so subscribers will be notified before js following el.focus() is
2748
 
// executed.
2749
 
if (useActivate) {
2750
 
    //     name     capture phase       direct subscription
2751
 
    define("focus", "beforeactivate",   "focusin");
2752
 
    define("blur",  "beforedeactivate", "focusout");
2753
 
} else {
2754
 
    define("focus", "focus", "focus");
2755
 
    define("blur",  "blur",  "blur");
2756
 
}
2757
 
 
2758
 
 
2759
 
}, '3.2.0' ,{requires:['event-synthetic']});
2760
 
YUI.add('event-resize', function(Y) {
2761
 
 
2762
 
/**
2763
 
 * Adds a window resize event that has its behavior normalized to fire at the
2764
 
 * end of the resize rather than constantly during the resize.
2765
 
 * @module event
2766
 
 * @submodule event-resize
2767
 
 */
2768
 
(function() {
2769
 
 
2770
 
var detachHandle,
2771
 
 
2772
 
    timerHandle,
2773
 
 
2774
 
    CE_NAME = 'window:resize',
2775
 
 
2776
 
    handler = function(e) {
2777
 
 
2778
 
        if (Y.UA.gecko) {
2779
 
 
2780
 
            Y.fire(CE_NAME, e);
2781
 
 
2782
 
        } else {
2783
 
 
2784
 
            if (timerHandle) {
2785
 
                timerHandle.cancel();
2786
 
            }
2787
 
 
2788
 
            timerHandle = Y.later(Y.config.windowResizeDelay || 40, Y, function() {
2789
 
                Y.fire(CE_NAME, e);
2790
 
            });
2791
 
        }
2792
 
        
2793
 
    };
2794
 
 
2795
 
 
2796
 
/**
2797
 
 * Firefox fires the window resize event once when the resize action
2798
 
 * finishes, other browsers fire the event periodically during the
2799
 
 * resize.  This code uses timeout logic to simulate the Firefox 
2800
 
 * behavior in other browsers.
2801
 
 * @event windowresize
2802
 
 * @for YUI
2803
 
 */
2804
 
Y.Env.evt.plugins.windowresize = {
2805
 
 
2806
 
    on: function(type, fn) {
2807
 
 
2808
 
        // check for single window listener and add if needed
2809
 
        if (!detachHandle) {
2810
 
            detachHandle = Y.Event._attach(['resize', handler]);
2811
 
        }
2812
 
 
2813
 
        var a = Y.Array(arguments, 0, true);
2814
 
        a[0] = CE_NAME;
2815
 
 
2816
 
        return Y.on.apply(Y, a);
2817
 
    }
2818
 
};
2819
 
 
2820
 
})();
2821
 
 
2822
 
 
2823
 
}, '3.2.0' ,{requires:['node-base']});
2824
 
 
2825
 
 
2826
 
YUI.add('event', function(Y){}, '3.2.0' ,{use:['event-base', 'event-delegate', 'event-synthetic', 'event-mousewheel', 'event-mouseenter', 'event-key', 'event-focus', 'event-resize']});
2827