~ted/lazr-js/annoying-debug-message

« back to all changes in this revision

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

  • Committer: Launchpad Patch Queue Manager
  • Date: 2010-09-09 14:20:30 UTC
  • mfrom: (182.1.3 yui-3.2)
  • Revision ID: launchpad@pqm.canonical.com-20100909142030-13w6vo0ixfysxc15
[r=beuno] Update lazr-js to yui-3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
3
Code licensed under the BSD License:
4
4
http://developer.yahoo.com/yui/license.html
5
 
version: 3.1.2
6
 
build: 56
 
5
version: 3.2.0
 
6
build: 2676
7
7
*/
8
8
/*
9
9
 * DOM event listener abstraction layer
21
21
    GLOBAL_ENV   = YUI.Env, 
22
22
    config       = YUI.config, 
23
23
    doc          = config.doc, 
24
 
    docElement   = doc.documentElement, 
25
 
    doScrollCap  = docElement.doScroll,
 
24
    docElement   = doc && doc.documentElement, 
 
25
    doScrollCap  = docElement && docElement.doScroll,
26
26
    add          = YUI.Env.add,
27
27
    remove       = YUI.Env.remove,
28
28
    targetEvent  = (doScrollCap) ? 'onreadystatechange' : 'DOMContentLoaded',
205
205
        63277: 34, // page down
206
206
        25:     9, // SHIFT-TAB (Safari provides a different key code in
207
207
                   // this case, even though the shiftKey modifier is set)
208
 
                63272: 46, // delete
209
 
                63273: 36, // home
210
 
                63275: 35  // end
 
208
        63272: 46, // delete
 
209
        63273: 36, // home
 
210
        63275: 35  // end
211
211
    },
212
212
 
213
213
    /**
250
250
    wrapper = wrapper || {};
251
251
 
252
252
    var e = ev, ot = currentTarget, d = Y.config.doc, b = d.body,
253
 
        x = e.pageX, y = e.pageY, c, t, 
 
253
        x = e.pageX, y = e.pageY, c, t, de = d.documentElement,
254
254
        overrides = wrapper.overrides || {};
255
255
 
256
256
    this.altKey   = e.altKey;
263
263
 
264
264
    //////////////////////////////////////////////////////
265
265
 
266
 
    if (!x && 0 !== x) {
267
 
        x = e.clientX || 0;
268
 
        y = e.clientY || 0;
 
266
    if (('clientX' in e) && (!x) && (0 !== x)) {
 
267
        x = e.clientX; 
 
268
        y = e.clientY;
269
269
 
270
270
        if (ua.ie) {
271
 
            x += Math.max(d.documentElement.scrollLeft, b.scrollLeft);
272
 
            y += Math.max(d.documentElement.scrollTop, b.scrollTop);
 
271
            x += (de.scrollLeft || b.scrollLeft || 0);
 
272
            y += (de.scrollTop  || b.scrollTop  || 0);
273
273
        }
274
274
    }
275
275
 
390
390
            e.cancelBubble = true;
391
391
        }
392
392
        wrapper.stopped = 1;
 
393
        this.stopped = 1;
393
394
    };
394
395
 
395
396
    /**
405
406
            this.stopPropagation();
406
407
        }
407
408
        wrapper.stopped = 2;
 
409
        this.stopped = 2;
408
410
    };
409
411
 
410
412
    /**
420
422
        }
421
423
        e.returnValue = returnValue || false;
422
424
        wrapper.prevented = 1;
 
425
        this.prevented = 1;
423
426
    };
424
427
 
425
428
    /**
439
442
        this.preventDefault();
440
443
    };
441
444
 
 
445
    if (this._touch) {
 
446
        this._touch(e, currentTarget, wrapper);
 
447
    }
 
448
 
442
449
};
443
450
 
444
451
})();
462
469
Y.Env.evt.dom_map = {};
463
470
 
464
471
var _eventenv = Y.Env.evt,
 
472
config = Y.config,
 
473
win = config.win,
465
474
add = YUI.Env.add,
466
475
remove = YUI.Env.remove,
467
476
 
468
477
onLoad = function() {
469
478
    YUI.Env.windowLoaded = true;
470
479
    Y.Event._load();
471
 
    remove(window, "load", onLoad);
 
480
    remove(win, "load", onLoad);
472
481
},
473
482
 
474
483
onUnload = function() {
475
484
    Y.Event._unload();
476
 
    remove(window, "unload", onUnload);
 
485
    remove(win, "unload", onUnload);
477
486
},
478
487
 
479
488
EVENT_READY = 'domready',
665
674
                    // set by the event system for lazy DOM listeners
666
675
                    if (availHandle.handle) {
667
676
                        availHandle.handle.detach();
668
 
                                                return;
 
677
                        return;
669
678
                    }
670
679
 
671
680
                    var i, j;
732
741
            return Event._attach(Y.Array(arguments, 0, true));
733
742
        },
734
743
 
735
 
                _createWrapper: function (el, type, capture, compat, facade) {
 
744
        _createWrapper: function (el, type, capture, compat, facade) {
736
745
 
737
746
            var cewrapper,
738
747
                ek  = Y.stamp(el),
739
 
                    key = 'event:' + ek + type;
 
748
                key = 'event:' + ek + type;
740
749
 
741
750
            if (false === facade) {
742
751
                key += 'native';
774
783
                cewrapper.fn = function(e) {
775
784
                    cewrapper.fire(Event.getEvent(e, el, (compat || (false === facade))));
776
785
                };
777
 
                                cewrapper.capture = capture;
 
786
                cewrapper.capture = capture;
778
787
            
779
 
                if (el == Y.config.win && type == "load") {
 
788
                if (el == win && type == "load") {
780
789
                    // window load happens once
781
790
                    cewrapper.fireOnce = true;
782
791
                    _windowLoadKey = key;
789
798
                add(el, type, cewrapper.fn, capture);
790
799
            }
791
800
 
792
 
                        return cewrapper;
793
 
                        
794
 
                },
 
801
            return cewrapper;
 
802
            
 
803
        },
795
804
 
796
 
        _attach: function(args, config) {
 
805
        _attach: function(args, conf) {
797
806
 
798
807
            var compat, 
799
808
                handles, oEl, cewrapper, context, 
800
809
                fireNow = false, ret,
801
810
                type = args[0],
802
811
                fn = args[1],
803
 
                el = args[2] || Y.config.win,
804
 
                facade = config && config.facade,
805
 
                capture = config && config.capture,
806
 
                overrides = config && config.overrides; 
 
812
                el = args[2] || win,
 
813
                facade = conf && conf.facade,
 
814
                capture = conf && conf.capture,
 
815
                overrides = conf && conf.overrides; 
807
816
 
808
817
            if (args[args.length-1] === COMPAT_ARG) {
809
818
                compat = true;
823
832
                
824
833
                Y.each(el, function(v, k) {
825
834
                    args[2] = v;
826
 
                    handles.push(Event._attach(args, config));
 
835
                    handles.push(Event._attach(args, conf));
827
836
                });
828
837
 
829
838
                // return (handles.length === 1) ? handles[0] : handles;
853
862
                            break;
854
863
                        default:
855
864
                            args[2] = oEl;
856
 
                            return Event._attach(args, config);
 
865
                            return Event._attach(args, conf);
857
866
                    }
858
867
                }
859
868
 
868
877
                    ret = this.onAvailable(el, function() {
869
878
                        // Y.log('lazy attach: ' + args);
870
879
                        
871
 
                        ret.handle = Event._attach(args, config);
 
880
                        ret.handle = Event._attach(args, conf);
872
881
 
873
882
                    }, Event, true, false, compat);
874
883
 
887
896
                el = Y.Node.getDOMNode(el);
888
897
            }
889
898
 
890
 
                        cewrapper = this._createWrapper(el, type, capture, compat, facade);
 
899
            cewrapper = this._createWrapper(el, type, capture, compat, facade);
891
900
            if (overrides) {
892
901
                Y.mix(cewrapper.overrides, overrides);
893
902
            }
894
903
 
895
 
            if (el == Y.config.win && type == "load") {
 
904
            if (el == win && type == "load") {
896
905
 
897
906
                // if the load is complete, fire immediately.
898
907
                // all subscribers, including the current one
1015
1024
         * @static
1016
1025
         */
1017
1026
        getEvent: function(e, el, noFacade) {
1018
 
            var ev = e || window.event;
 
1027
            var ev = e || win.event;
1019
1028
 
1020
1029
            return (noFacade) ? ev : 
1021
1030
                new Y.DOMEventFacade(ev, el, _wrappers['event:' + Y.stamp(el) + e.type]);
1250
1259
         */           
1251
1260
        getListeners: function(el, type) {
1252
1261
            var ek = Y.stamp(el, true), evts = _el_events[ek],
1253
 
                results=[] , key = (type) ? 'event:' + ek + type : null;
 
1262
                results=[] , key = (type) ? 'event:' + ek + type : null,
 
1263
                adapters = _eventenv.plugins;
1254
1264
 
1255
1265
            if (!evts) {
1256
1266
                return null;
1257
1267
            }
1258
1268
 
1259
1269
            if (key) {
 
1270
                // look for synthetic events
 
1271
                if (adapters[type] && adapters[type].eventDef) {
 
1272
                    key += '_synth';
 
1273
                }
 
1274
 
1260
1275
                if (evts[key]) {
1261
1276
                    results.push(evts[key]);
1262
1277
                }
1324
1339
 
1325
1340
Y.Event = Event;
1326
1341
 
1327
 
if (Y.config.injected || YUI.Env.windowLoaded) {
 
1342
if (config.injected || YUI.Env.windowLoaded) {
1328
1343
    onLoad();
1329
1344
} else {
1330
 
    add(window, "load", onLoad);
 
1345
    add(win, "load", onLoad);
1331
1346
}
1332
1347
 
1333
1348
// Process onAvailable/onContentReady items when when the DOM is ready in IE
1395
1410
};
1396
1411
 
1397
1412
 
1398
 
}, '3.1.2' ,{requires:['event-custom-base']});
 
1413
}, '3.2.0' ,{requires:['event-custom-base']});
1399
1414
YUI.add('event-delegate', function(Y) {
1400
1415
 
1401
1416
/**
1405
1420
 * @submodule event-delegate
1406
1421
 */
1407
1422
 
1408
 
var Event = Y.Event,
1409
 
        Lang = Y.Lang,
1410
 
 
1411
 
        delegates = {},
1412
 
        
1413
 
        specialTypes = {
1414
 
                mouseenter: "mouseover",
1415
 
                mouseleave: "mouseout"
1416
 
        },
1417
 
 
1418
 
        resolveTextNode = function(n) {
1419
 
            try {
1420
 
                if (n && 3 == n.nodeType) {
1421
 
                    return n.parentNode;
1422
 
                }
1423
 
            } catch(e) { }
1424
 
            return n;
1425
 
        },
1426
 
 
1427
 
    delegateHandler = function(delegateKey, e, el) {
1428
 
 
1429
 
        var target = resolveTextNode((e.target || e.srcElement)), 
1430
 
            tests  = delegates[delegateKey],
1431
 
            spec, 
1432
 
                        ename,
1433
 
                        matched,
1434
 
                        fn,
1435
 
                        ev;
1436
 
 
1437
 
 
1438
 
                var getMatch = function(el, selector, container) {
1439
 
                        
1440
 
                        var returnVal;
1441
 
                        
1442
 
                        if (!el || el === container) {
1443
 
                                returnVal = false;
1444
 
                        }
1445
 
                        else {
1446
 
                                returnVal = Y.Selector.test(el, selector, container) ? el: getMatch(el.parentNode, selector, container);
1447
 
                        }
1448
 
                        
1449
 
                        return returnVal;
1450
 
                        
1451
 
                };
1452
 
 
1453
 
 
1454
 
        for (spec in tests) {
1455
 
 
1456
 
            if (tests.hasOwnProperty(spec)) {
1457
 
 
1458
 
                ename  = tests[spec];
1459
 
                                fn      = tests.fn;
1460
 
                                matched = null;
1461
 
 
1462
 
 
1463
 
                                if (Y.Selector.test(target, spec, el)) {
1464
 
                                        matched = target;
1465
 
                                }
1466
 
                else if (Y.Selector.test(target, ((spec.replace(/,/gi, " *,")) + " *"), el)) {
1467
 
                     
1468
 
                 //  The target is a descendant of an element matching 
1469
 
                 //  the selector, so crawl up to find the ancestor that 
1470
 
                 //  matches the selector
1471
 
                 
1472
 
                 matched = getMatch(target, spec, el);
1473
 
                 
1474
 
                }
1475
 
 
1476
 
 
1477
 
                                if (matched) {
1478
 
 
1479
 
                    if (!ev) {
1480
 
                        ev = new Y.DOMEventFacade(e, el);
1481
 
                        ev.container = ev.currentTarget;
1482
 
                    }
1483
 
 
1484
 
                    ev.currentTarget = Y.one(matched);
1485
 
 
1486
 
                                        Y.publish(ename, {
1487
 
                                       contextFn: function() {
1488
 
                                           return ev.currentTarget;
1489
 
                                       }
1490
 
                                   });
1491
 
 
1492
 
                                        if (fn) {
1493
 
                                                fn(ev, ename);
1494
 
                                        }
1495
 
                                        else {
1496
 
                        Y.fire(ename, ev);                                                              
1497
 
                                        }
1498
 
                                        
1499
 
                                }
1500
 
 
1501
 
            }
1502
 
        }
1503
 
 
1504
 
    },
1505
 
 
1506
 
        attach = function (type, key, element) {
1507
 
 
1508
 
                var focusMethods = {
1509
 
                                focus: Event._attachFocus,
1510
 
                                blur: Event._attachBlur
1511
 
                        },
1512
 
 
1513
 
                        attachFn = focusMethods[type],
1514
 
 
1515
 
                        args = [type, 
1516
 
                        function (e) {
1517
 
                    delegateHandler(key, (e || window.event), element);
1518
 
                        }, 
1519
 
                        element];
1520
 
 
1521
 
 
1522
 
                if (attachFn) {
1523
 
                        return attachFn(args, { capture: true, facade: false });
1524
 
                }
1525
 
                else {
1526
 
                        return Event._attach(args, { facade: false });
1527
 
                }
1528
 
                
1529
 
        },
1530
 
 
1531
 
    sanitize = Y.cached(function(str) {
1532
 
        return str.replace(/[|,:]/g, '~');
1533
 
    });
1534
 
 
1535
 
 
 
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
};
1536
1631
 
1537
1632
/**
1538
1633
 * Sets up event delegation on a container element.  The delegated event
1539
 
 * will use a supplied selector to test if the target or one of the
1540
 
 * descendants of the target match it.  The supplied callback function 
1541
 
 * will only be executed if a match was encountered, and, in fact, 
1542
 
 * will be executed for each element that matches if you supply an 
1543
 
 * ambiguous selector.
 
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.
1544
1637
 *
1545
1638
 * The event object for the delegated event is supplied to the callback
1546
1639
 * function.  It is modified slightly in order to support all properties
1547
1640
 * that may be needed for event delegation.  'currentTarget' is set to
1548
 
 * the element that matched the delegation specifcation.  'container' is
1549
 
 * set to the element that the listener is bound to (this normally would
1550
 
 * be the 'currentTarget').
 
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.
1551
1650
 *
1552
1651
 * @method delegate
1553
1652
 * @param type {string} the event type to delegate
1554
1653
 * @param fn {function} the callback function to execute.  This function
1555
1654
 * will be provided the event object for the delegated event.
1556
1655
 * @param el {string|node} the element that is the delegation container
1557
 
 * @param spec {string} a selector that must match the target of the
1558
 
 * event.
 
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.
1559
1658
 * @param context optional argument that specifies what 'this' refers to.
1560
1659
 * @param args* 0..n additional arguments to pass on to the callback function.
1561
1660
 * These arguments will be added after the event object.
1562
1661
 * @return {EventHandle} the detach handle
1563
1662
 * @for YUI
1564
1663
 */
1565
 
Event.delegate = function (type, fn, el, spec) {
1566
 
 
1567
 
    if (!spec) {
1568
 
        Y.log('delegate: no spec, nothing to do', 'warn', 'event');
1569
 
        return false;
 
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();
1570
1760
    }
1571
1761
 
1572
 
 
1573
 
    var args = Y.Array(arguments, 0, true),         
1574
 
                element = el,   // HTML element serving as the delegation container
1575
 
                availHandle;    
1576
 
 
1577
 
 
1578
 
        if (Lang.isString(el)) {
1579
 
                
1580
 
                //      Y.Selector.query returns an array of matches unless specified 
1581
 
                //      to return just the first match.  Since the primary use case for
1582
 
                //      event delegation is to use a single event handler on a container,
1583
 
                //      Y.delegate doesn't currently support being able to bind a 
1584
 
                //      single listener to multiple containers.
1585
 
                
1586
 
                element = Y.Selector.query(el, null, true);
1587
 
                
1588
 
                if (!element) { // Not found, check using onAvailable
1589
 
 
1590
 
                        availHandle = Event.onAvailable(el, function() {
1591
 
 
1592
 
                                availHandle.handle = Event.delegate.apply(Event, args);
1593
 
 
1594
 
            }, Event, true, false);
1595
 
 
1596
 
            return availHandle;
1597
 
                        
1598
 
                }
1599
 
                
1600
 
        }
1601
 
 
1602
 
 
1603
 
        element = Y.Node.getDOMNode(element);
1604
 
 
1605
 
 
1606
 
        var     guid = Y.stamp(element),
 
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;
1607
2159
            
1608
 
        // The Custom Event for the delegation spec
1609
 
        ename = 'delegate:' + guid + type + sanitize(spec),
1610
 
 
1611
 
        // The key to the listener for the event type and container
1612
 
        delegateKey = type + guid,
1613
 
 
1614
 
                delegate = delegates[delegateKey],
1615
 
 
1616
 
                domEventHandle,
1617
 
                
1618
 
                ceHandle,
1619
 
                
1620
 
                listeners;
1621
 
        
1622
 
 
1623
 
    if (!delegate) {
1624
 
 
1625
 
                delegate = {};
1626
 
 
1627
 
                if (specialTypes[type]) {
1628
 
                        
1629
 
                        if (!Event._fireMouseEnter) {
1630
 
                                Y.log("Delegating a " + type + " event requires the event-mouseenter submodule.", "error", "Event");
1631
 
                                return false;                           
1632
 
                        }
1633
 
                        
1634
 
                        type = specialTypes[type];
1635
 
                        delegate.fn = Event._fireMouseEnter;
1636
 
                        
1637
 
                }
1638
 
 
1639
 
                //      Create the DOM Event wrapper that will fire the Custom Event
1640
 
 
1641
 
                domEventHandle = attach(type, delegateKey, element);
1642
 
 
1643
 
 
1644
 
                //      Hook into the _delete method for the Custom Event wrapper of this
1645
 
                //      DOM Event in order to clean up the 'delegates' map and unsubscribe
1646
 
                //      the associated Custom Event listeners fired by this DOM event
1647
 
                //      listener if/when the user calls "purgeElement" OR removes all 
1648
 
                //      listeners of the Custom Event.
1649
 
                
1650
 
                Y.after(function (sub) {
1651
 
 
1652
 
                        if (domEventHandle.sub == sub) {
1653
 
 
1654
 
                                //      Delete this event from the map of known delegates
1655
 
                                delete delegates[delegateKey];
1656
 
 
1657
 
                                Y.log("DOM event listener associated with the " + ename + " Custom Event removed.  Removing all " + ename + " listeners.", "info", "Event");
1658
 
 
1659
 
                                //      Unsubscribe all listeners of the Custom Event fired 
1660
 
                                //      by this DOM event.
1661
 
                                Y.detachAll(ename);
1662
 
                                
1663
 
                        }
1664
 
 
1665
 
                }, domEventHandle.evt, "_delete");
1666
 
                        
1667
 
                delegate.handle = domEventHandle;
1668
 
 
1669
 
        delegates[delegateKey] = delegate;
1670
 
 
1671
 
    }
1672
 
 
1673
 
 
1674
 
        listeners = delegate.listeners;
1675
 
 
1676
 
        delegate.listeners = listeners ? (listeners + 1) : 1;
1677
 
    delegate[spec] = ename;
1678
 
 
1679
 
 
1680
 
    args[0] = ename;
1681
 
 
1682
 
    // Remove element, delegation spec
1683
 
    args.splice(2, 2);
1684
 
        
1685
 
 
1686
 
    // Subscribe to the Custom Event for the delegation spec
1687
 
 
1688
 
        ceHandle = Y.on.apply(Y, args);
1689
 
 
1690
 
 
1691
 
        //      Hook into the detach method of the handle in order to clean up the 
1692
 
        //      'delegates' map and remove the associated DOM event handler 
1693
 
        //      responsible for firing this Custom Event if all listener for this 
1694
 
        //      event have been removed.
1695
 
 
1696
 
        Y.after(function () {
1697
 
                        
1698
 
                delegate.listeners = (delegate.listeners - 1);
1699
 
                
1700
 
                if (delegate.listeners === 0) {
1701
 
                        Y.log("No more listeners for the " + ename + " Custom Event.  Removing its associated DOM event listener.", "info", "Event");
1702
 
                        delegate.handle.detach();
1703
 
                }
1704
 
 
1705
 
        }, ceHandle, "detach");
1706
 
 
1707
 
    return ceHandle;
1708
 
        
 
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;
1709
2392
};
1710
2393
 
1711
 
Y.delegate = Event.delegate;
1712
 
 
1713
 
 
1714
 
}, '3.1.2' ,{requires:['node-base']});
 
2394
 
 
2395
}, '3.2.0' ,{requires:['node-base', 'event-custom']});
1715
2396
YUI.add('event-mousewheel', function(Y) {
1716
2397
 
1717
2398
/**
1761
2442
};
1762
2443
 
1763
2444
 
1764
 
}, '3.1.2' ,{requires:['node-base']});
 
2445
}, '3.2.0' ,{requires:['node-base']});
1765
2446
YUI.add('event-mouseenter', function(Y) {
1766
2447
 
1767
2448
/**
1768
 
 * Adds support for mouseenter/mouseleave events
 
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
 *
1769
2470
 * @module event
1770
2471
 * @submodule event-mouseenter
1771
2472
 */
1772
 
var Event = Y.Event,
1773
 
        Lang = Y.Lang,
1774
 
 
1775
 
        plugins = Y.Env.evt.plugins,
1776
 
        
1777
 
        listeners = {},
1778
 
 
1779
 
        eventConfig = {
1780
 
 
1781
 
        on: function(type, fn, el) {
1782
 
 
1783
 
                    var args = Y.Array(arguments, 0, true),         
1784
 
                                element = el,
1785
 
                                availHandle;
1786
 
 
1787
 
 
1788
 
                        if (Lang.isString(el)) {
1789
 
 
1790
 
                                //      Need to use Y.all because if el is a string it could be a 
1791
 
                                //      selector that returns a NodeList
1792
 
 
1793
 
                                element = Y.all(el);
1794
 
 
1795
 
                                if (element.size() === 0) { // Not found, check using onAvailable
1796
 
 
1797
 
                            availHandle = Event.onAvailable(el, function() {
1798
 
 
1799
 
                                availHandle.handle = Y.on.apply(Y, args);
1800
 
 
1801
 
                            }, Event, true, false);
1802
 
                
1803
 
                                        return availHandle;
1804
 
 
1805
 
                                }
1806
 
 
1807
 
                        }
1808
 
                        
1809
 
 
1810
 
                var sDOMEvent = (type === "mouseenter") ? "mouseover" : "mouseout",
1811
 
 
1812
 
                                //      The name of the custom event
1813
 
                                sEventName = type + ":" + Y.stamp(element) + sDOMEvent,
1814
 
 
1815
 
                                listener = listeners[sEventName],
1816
 
 
1817
 
                                domEventHandle,
1818
 
                                
1819
 
                                ceHandle,
1820
 
                                
1821
 
                                nListeners;
1822
 
 
1823
 
 
1824
 
                        //      Bind an actual DOM event listener that will call the 
1825
 
                        //      the custom event                                
1826
 
                        if (!listener) {
1827
 
                                
1828
 
                                domEventHandle = Y.on(sDOMEvent, Y.rbind(Event._fireMouseEnter, Y, sEventName), element);
1829
 
 
1830
 
                                //      Hook into the _delete method for the Custom Event wrapper of this
1831
 
                                //      DOM Event in order to clean up the 'listeners' map and unsubscribe
1832
 
                                //      the associated Custom Event listeners fired by this DOM event
1833
 
                                //      listener if/when the user calls "purgeElement" OR removes all 
1834
 
                                //      listeners of the Custom Event.
1835
 
 
1836
 
                                Y.after(function (sub) {
1837
 
 
1838
 
                                        if (domEventHandle.sub == sub) {
1839
 
 
1840
 
                                                //      Delete this event from the map of known mouseenter 
1841
 
                                                //      and mouseleave listeners
1842
 
                                                delete listeners[sEventName];
1843
 
 
1844
 
                                                Y.log("DOM event listener associated with the " + sEventName + " Custom Event removed.  Removing all " + sEventName + " listeners.", "info", "Event");
1845
 
 
1846
 
                                                //      Unsubscribe all listeners of the Custom Event fired 
1847
 
                                                //      by this DOM event.
1848
 
                                                Y.detachAll(sEventName);
1849
 
 
1850
 
                                        }
1851
 
 
1852
 
                                }, domEventHandle.evt, "_delete");
1853
 
                                
1854
 
 
1855
 
                                listener = {};                          
1856
 
                                listener.handle = domEventHandle;                               
1857
 
 
1858
 
                                listeners[sEventName] = listener;
1859
 
 
1860
 
                        }
1861
 
 
1862
 
                        nListeners = listener.count;
1863
 
 
1864
 
                        listener.count = nListeners ? (nListeners + 1) : 1;
1865
 
 
1866
 
                args[0] = sEventName;
1867
 
 
1868
 
                // Remove the element from the args
1869
 
                        args.splice(2, 1);
1870
 
 
1871
 
                // Subscribe to the custom event
1872
 
                ceHandle = Y.on.apply(Y, args);
1873
 
        
1874
 
                        //      Hook into the detach method of the handle in order to clean up the 
1875
 
                        //      'listeners' map and remove the associated DOM event handler 
1876
 
                        //      responsible for firing this Custom Event if all listener for this 
1877
 
                        //      event have been removed.
1878
 
 
1879
 
                        Y.after(function () {
1880
 
 
1881
 
                                listener.count = (listener.count - 1);
1882
 
 
1883
 
                                if (listener.count === 0) {
1884
 
                                        Y.log("No more listeners for the " + sEventName + " Custom Event.  Removing its associated DOM event listener.", "info", "Event");
1885
 
                                        listener.handle.detach();
1886
 
                                }
1887
 
 
1888
 
                        }, ceHandle, "detach"); 
1889
 
        
1890
 
        
1891
 
                        return ceHandle;
1892
 
 
1893
 
            }
1894
 
 
1895
 
        };
1896
 
        
1897
 
 
1898
 
Event._fireMouseEnter = function (e, eventName) {
1899
 
 
1900
 
        var relatedTarget = e.relatedTarget,
1901
 
                currentTarget = e.currentTarget;
1902
 
 
1903
 
        if (currentTarget !== relatedTarget && 
1904
 
                !currentTarget.contains(relatedTarget)) {
1905
 
 
1906
 
                Y.publish(eventName, {
1907
 
               contextFn: function() {
1908
 
                   return currentTarget;
1909
 
               }
1910
 
           });                  
1911
 
 
1912
 
                Y.fire(eventName, e);
1913
 
 
1914
 
        }
1915
 
 
1916
 
};      
1917
 
 
1918
 
 
1919
 
/**
1920
 
 * Sets up a "mouseenter" listener&#151;a listener that is called the first time 
1921
 
 * the user's mouse enters the specified element(s).
1922
 
 * 
1923
 
 * @event mouseenter
1924
 
 * @param type {string} "mouseenter"
1925
 
 * @param fn {function} The method the event invokes.
1926
 
 * @param el {string|node} The element(s) to assign the listener to.
1927
 
 * @param spec {string} Optional.  String representing a selector that must 
1928
 
 * match the target of the event in order for the listener to be called.
1929
 
 * @return {EventHandle} the detach handle
1930
 
 * @for YUI
1931
 
 */
1932
 
plugins.mouseenter = eventConfig;
1933
 
 
1934
 
/**
1935
 
* Sets up a "mouseleave" listener&#151;a listener that is called the first time 
1936
 
* the user's mouse leaves the specified element(s).
1937
 
1938
 
* @event mouseleave
1939
 
* @param type {string} "mouseleave"
1940
 
* @param fn {function} The method the event invokes.
1941
 
* @param el {string|node} The element(s) to assign the listener to.
1942
 
* @param spec {string} Optional.  String representing a selector that must 
1943
 
* match the target of the event in order for the listener to be called.
1944
 
* @return {EventHandle} the detach handle
1945
 
* @for YUI
1946
 
 */
1947
 
plugins.mouseleave = eventConfig;
1948
 
 
1949
 
 
1950
 
}, '3.1.2' ,{requires:['node-base']});
 
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']});
1951
2508
YUI.add('event-key', function(Y) {
1952
2509
 
1953
2510
/**
2051
2608
};
2052
2609
 
2053
2610
 
2054
 
}, '3.1.2' ,{requires:['node-base']});
 
2611
}, '3.2.0' ,{requires:['node-base']});
2055
2612
YUI.add('event-focus', function(Y) {
2056
2613
 
2057
2614
/**
2058
 
 * Adds focus and blur event listener support.  These events normally
2059
 
 * do not bubble, so this adds support for that so these events
2060
 
 * can be used in event delegation scenarios.
 
2615
 * Adds bubbling and delegation support to DOM events focus and blur.
2061
2616
 * 
2062
2617
 * @module event
2063
2618
 * @submodule event-focus
2064
2619
 */
2065
 
(function() {
2066
 
 
2067
 
var UA = Y.UA,
2068
 
        Event = Y.Event,
2069
 
        plugins = Y.Env.evt.plugins,
2070
 
        ie = UA.ie,
2071
 
        bUseMutation = (UA.opera || UA.webkit),
2072
 
        eventNames = {
2073
 
                focus: (ie ? 'focusin' : (bUseMutation ? 'DOMFocusIn' : 'focus')),
2074
 
                blur: (ie ? 'focusout' : (bUseMutation ? 'DOMFocusOut' : 'blur'))
2075
 
        },
2076
 
 
2077
 
        //      Only need to use capture phase for Gecko since it doesn't support 
2078
 
        //      focusin, focusout, DOMFocusIn, or DOMFocusOut
2079
 
    CAPTURE_CONFIG = { capture: (UA.gecko ? true : false) },
2080
 
 
2081
 
 
2082
 
        attach = function (args, config) {
2083
 
 
2084
 
            var a = Y.Array(args, 0, true),
2085
 
            el = args[2];
2086
 
 
2087
 
        config.overrides = config.overrides || {};
2088
 
        config.overrides.type = args[0];
2089
 
        
2090
 
        if (el) {
 
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) {
2091
2632
            if (Y.DOM.isWindow(el)) {
2092
 
                config.capture = false;
2093
 
            }
2094
 
            else {
2095
 
                        a[0] = eventNames[a[0]];
2096
 
                    }
 
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();
2097
2738
        }
2098
 
 
2099
 
            return Event._attach(a, config);
2100
 
 
2101
 
        },
2102
 
        
2103
 
        eventAdapter = {
2104
 
 
2105
 
                on: function () {
2106
 
                        return attach(arguments, CAPTURE_CONFIG);
2107
 
                }
2108
 
 
2109
 
        };
2110
 
 
2111
 
 
2112
 
Event._attachFocus = attach;
2113
 
Event._attachBlur = attach;
2114
 
 
2115
 
/**
2116
 
 * Adds a DOM focus listener.  Uses the focusin event in IE, 
2117
 
 * DOMFocusIn for Opera and Webkit, and the capture phase for Gecko so that
2118
 
 * the event propagates in a way that enables event delegation.
2119
 
 *
2120
 
 * @for YUI
2121
 
 * @event focus
2122
 
 * @param type {string} 'focus'
2123
 
 * @param fn {function} the callback function to execute
2124
 
 * @param o {string|HTMLElement|collection} the element(s) to bind
2125
 
 * @param context optional context object
2126
 
 * @param args 0..n additional arguments to provide to the listener.
2127
 
 * @return {EventHandle} the detach handle
2128
 
 */
2129
 
plugins.focus = eventAdapter;
2130
 
 
2131
 
/**
2132
 
 * Adds a DOM blur listener.  Uses the focusout event in IE, 
2133
 
 * DOMFocusOut for Opera and Webkit, and the capture phase for Gecko so that
2134
 
 * the event propagates in a way that enables event delegation.
2135
 
 *
2136
 
 * @for YUI
2137
 
 * @event blur
2138
 
 * @param type {string} 'blur'
2139
 
 * @param fn {function} the callback function to execute
2140
 
 * @param o {string|HTMLElement|collection} the element(s) to bind
2141
 
 * @param context optional context object
2142
 
 * @param args 0..n additional arguments to provide to the listener.
2143
 
 * @return {EventHandle} the detach handle
2144
 
 */
2145
 
plugins.blur = eventAdapter;
2146
 
 
2147
 
})();
2148
 
 
2149
 
 
2150
 
}, '3.1.2' ,{requires:['node-base']});
 
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']});
2151
2760
YUI.add('event-resize', function(Y) {
2152
2761
 
2153
2762
/**
2211
2820
})();
2212
2821
 
2213
2822
 
2214
 
}, '3.1.2' ,{requires:['node-base']});
2215
 
 
2216
 
 
2217
 
YUI.add('event', function(Y){}, '3.1.2' ,{use:['event-base', 'event-delegate', 'event-mousewheel', 'event-mouseenter', 'event-key', 'event-focus', 'event-resize']});
 
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']});
2218
2827