2
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
3
Code licensed under the BSD License:
4
http://developer.yahoo.net/yui/license.txt
11
YUI.add("event", function(Y) {
14
* Subscribes to the yui:load event, which fires when a Y.use operation
17
* @param f {Function} the function to execute
18
* @param c Optional execution context
19
* @param args* 0..n Additional arguments to append
20
* to the signature provided when the event fires.
21
* @return {YUI} the YUI instance
23
// Y.ready = function(f, c) {
24
// var a = arguments, m = (a.length > 1) ? Y.bind.apply(Y, a) : f;
25
// Y.on("yui:load", m);
30
* Attach an event listener, either to a DOM object
31
* or to an Event.Target.
32
* @param type {string} the event type
33
* @param f {Function} the function to execute
34
* @param o the Event.Target or element to attach to
35
* @param context Optional execution context
36
* @param args* 0..n additional arguments to append
37
* to the signature provided when the event fires.
40
* @return {Event.Handle} a handle object for
41
* unsubscribing to this event.
43
Y.on = function(type, f, o) {
45
if (type.indexOf(':') > -1) {
46
var cat = type.split(':');
49
return Y.subscribe.apply(Y, arguments);
52
return Y.Event.attach.apply(Y.Event, arguments);
58
* Detach an event listener (either a custom event or a
61
* @param type the type of event, or a Event.Handle to
62
* for the subscription. If the Event.Handle is passed
63
* in, the other parameters are not used.
64
* @param f {Function} the subscribed function
65
* @param o the object or element the listener is subscribed
68
* @return {YUI} the YUI instance
70
Y.detach = function(type, f, o) {
71
if (Y.Lang.isObject(type) && type.detach) {
73
} else if (type.indexOf(':') > -1) {
74
var cat = type.split(':');
77
return Y.unsubscribe.apply(Y, arguments);
80
return Y.Event.detach.apply(Y.Event, arguments);
85
* Executes the callback before a DOM event, custom event
86
* or method. If the first argument is a function, it
87
* is assumed the target is a method.
89
* For DOM and custom events:
90
* type, callback, context, 1-n arguments
93
* callback, object (method host), methodName, context, 1-n arguments
96
* @return unsubscribe handle
98
Y.before = function(type, f, o) {
100
// callback, object, sMethod
101
if (Y.Lang.isFunction(type)) {
102
return Y.Do.before.apply(Y.Do, arguments);
109
* Executes the callback after a DOM event, custom event
110
* or method. If the first argument is a function, it
111
* is assumed the target is a method.
115
* For DOM and custom events:
116
* type, callback, context, 1-n arguments
119
* callback, object (method host), methodName, context, 1-n arguments
122
* @return {Event.Handle} unsubscribe handle
124
Y.after = function(type, f, o) {
125
if (Y.Lang.isFunction(type)) {
126
return Y.Do.after.apply(Y.Do, arguments);
143
* Method displacement
144
* @submodule event-aop
147
YUI.add("aop", function(Y) {
153
* Allows for the insertion of methods that are executed before or after
161
* Cache of objects touched by the utility
168
* Execute the supplied method before the specified function
170
* @param fn {Function} the function to execute
171
* @param obj the object hosting the method to displace
172
* @param sFn {string} the name of the method to displace
173
* @param c The execution context for fn
174
* @return {string} handle for the subscription
177
before: function(fn, obj, sFn, c) {
180
var a = [fn, c].concat(Y.Array(arguments, 4, true));
181
f = Y.bind.apply(Y, a);
184
return this._inject(BEFORE, f, obj, sFn);
188
* Execute the supplied method after the specified function
190
* @param fn {Function} the function to execute
191
* @param obj the object hosting the method to displace
192
* @param sFn {string} the name of the method to displace
193
* @param c The execution context for fn
194
* @return {string} handle for the subscription
197
after: function(fn, obj, sFn, c) {
200
var a = [fn, c].concat(Y.Array(arguments, 4, true));
201
f = Y.bind.apply(Y, a);
204
return this._inject(AFTER, f, obj, sFn);
208
* Execute the supplied method after the specified function
210
* @param when {string} before or after
211
* @param fn {Function} the function to execute
212
* @param obj the object hosting the method to displace
213
* @param sFn {string} the name of the method to displace
214
* @param c The execution context for fn
215
* @return {string} handle for the subscription
219
_inject: function(when, fn, obj, sFn) {
222
var id = Y.stamp(obj);
224
if (! this.objs[id]) {
225
// create a map entry for the obj if it doesn't exist
228
var o = this.objs[id];
231
// create a map entry for the method if it doesn't exist
232
o[sFn] = new Y.Do.Method(obj, sFn);
234
// re-route the method to our wrapper
237
return o[sFn].exec.apply(o[sFn], arguments);
242
var sid = id + Y.stamp(fn) + sFn;
244
// register the callback
245
o[sFn].register(sid, fn, when);
252
* Detach a before or after subscription
254
* @param sid {string} the subscription handle
256
detach: function(sid) {
257
delete this.before[sid];
258
delete this.after[sid];
261
_unload: function(e, me) {
266
//////////////////////////////////////////////////////////////////////////
269
* Wrapper for a displaced method with aop enabled
272
* @param obj The object to operate on
273
* @param sFn The name of the method to displace
275
Y.Do.Method = function(obj, sFn) {
277
this.methodName = sFn;
278
this.method = obj[sFn];
286
* Register a aop subscriber
288
* @param sid {string} the subscriber id
289
* @param fn {Function} the function to execute
290
* @param when {string} when to execute the function
292
Y.Do.Method.prototype.register = function (sid, fn, when) {
294
// this.after.push(fn);
295
this.after[sid] = fn;
297
// this.before.push(fn);
298
this.before[sid] = fn;
303
* Execute the wrapped method
306
Y.Do.Method.prototype.exec = function () {
308
var args = Y.Array(arguments, 0, true),
313
// for (i=0; i<this.before.length; ++i) {
315
if (bf.hasOwnProperty(i)) {
316
ret = bf[i].apply(this.obj, args);
318
// Stop processing if an Error is returned
319
if (ret && ret.constructor == Y.Do.Error) {
321
// Check for altered arguments
322
} else if (ret && ret.constructor == Y.Do.AlterArgs) {
329
ret = this.method.apply(this.obj, args);
331
// execute after methods.
332
// for (i=0; i<this.after.length; ++i) {
334
if (af.hasOwnProperty(i)) {
335
newRet = af[i].apply(this.obj, args);
336
// Stop processing if an Error is returned
337
if (newRet && newRet.constructor == Y.Do.Error) {
338
return newRet.retVal;
339
// Check for a new return value
340
} else if (newRet && newRet.constructor == Y.Do.AlterReturn) {
341
ret = newRet.newRetVal;
349
//////////////////////////////////////////////////////////////////////////
352
* Return an Error object when you want to terminate the execution
353
* of all subsequent method calls
356
Y.Do.Error = function(msg, retVal) {
358
this.retVal = retVal;
362
* Return an AlterArgs object when you want to change the arguments that
363
* were passed into the function. An example would be a service that scrubs
364
* out illegal characters prior to executing the core business logic.
365
* @class Do.AlterArgs
367
Y.Do.AlterArgs = function(msg, newArgs) {
369
this.newArgs = newArgs;
373
* Return an AlterReturn object when you want to change the result returned
374
* from the core method to the caller
375
* @class Do.AlterReturn
377
Y.Do.AlterReturn = function(msg, newRetVal) {
379
this.newRetVal = newRetVal;
382
//////////////////////////////////////////////////////////////////////////
384
// Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
389
* @submodule event-custom
392
YUI.add("event-custom", function(Y) {
394
var onsubscribeType = "_event:onsub",
437
* Return value from all subscribe operations
438
* @class Event.Handle
440
* @param evt {Event.Custom} the custom event
441
* @param sub {Event.Subscriber} the subscriber
443
Y.EventHandle = function(evt, sub) {
452
* The subscriber object
453
* @type Event.Subscriber
458
Y.EventHandle.prototype = {
460
* Detaches this subscriber
464
this.evt._delete(this.sub);
469
* The Event.Custom class lets you define events for your application
470
* that can be subscribed to by one or more independent component.
472
* @param {String} type The type of event, which is passed to the callback
473
* when the event fires
474
* @param {Object} context The context the event will fire from. "this" will
475
* refer to this object in the callback. Default value:
476
* the window object. The listener can override this.
477
* @param {boolean} silent pass true to prevent the event from writing to
479
* @class Event.Custom
482
Y.CustomEvent = function(type, o) {
484
// if (arguments.length > 2) {
489
this.id = Y.stamp(this);
492
* The type of event, returned to subscribers when the event fires
499
* The context the the event will fire from by default. Defaults to the YUI
508
* If 0, this event does not broadcast. If 1, the YUI instance is notified
509
* every time this event fires. If 2, the YUI instance and the YUI global
510
* (if event is enabled on the global) are notified every time this event
512
* @property broadcast
518
* By default all custom events are logged in the debug build, set silent
519
* to true to disable debug outpu for this event.
524
this.queuable = false;
527
* The subscribers to this event
528
* @property subscribers
529
* @type Event.Subscriber{}
531
this.subscribers = {};
534
* The publisher has configured this event
535
* @property configured
539
// this.configured = true;
542
* 'After' subscribers
544
* @type Event.Subscriber{}
549
* This event has fired if true
558
* This event should only fire one time if true, and if
559
* it has fired, any new subscribers should be notified
566
this.fireOnce = false;
569
* Flag for stopPropagation that is modified during fire()
570
* 1 means to stop propagation to bubble targets. 2 means
571
* to also stop additional subscribers on this target.
578
* Flag for preventDefault that is modified during fire().
579
* if it is not 0, the default behavior for this event
580
* @property prevented
586
* Specifies the host for this custom event. This is used
587
* to enable event bubbling
594
* The default function to execute after event listeners
595
* have fire, but only if the default action was not
597
* @property defaultFn
600
this.defaultFn = null;
603
* The function to execute if a subscriber calls
604
* stopPropagation or stopImmediatePropagation
605
* @property stoppedFn
608
this.stoppedFn = null;
611
* The function to execute if a subscriber calls
613
* @property preventedFn
616
this.preventedFn = null;
619
* Specifies whether or not this event's default function
620
* can be cancelled by a subscriber by executing preventDefault()
621
* on the event facade
622
* @property preventable
626
this.preventable = true;
629
* Specifies whether or not a subscriber can stop the event propagation
630
* via stopPropagation(), stopImmediatePropagation(), or halt()
637
this.emitFacade = false;
639
this.applyConfig(o, true);
642
// Only add subscribe events for events that are not generated by
644
if (type !== onsubscribeType) {
647
* Custom events provide a custom event that fires whenever there is
648
* a new subscriber to the event. This provides an opportunity to
649
* handle the case where there is a non-repeating event that has
650
* already fired has a new subscriber.
652
* @event subscribeEvent
653
* @type Y.Event.Custom
654
* @param {Function} fn The function to execute
655
* @param {Object} obj An object to be passed along when the event
657
* @param {boolean|Object} override If true, the obj passed in becomes
658
* the execution context of the listener.
659
* if an object, that object becomes the
660
* the execution context.
662
this.subscribeEvent = new Y.CustomEvent(onsubscribeType, {
670
Y.CustomEvent.prototype = {
675
* Apply configuration properties. Only applies the CONFIG whitelist
676
* @method applyConfig
677
* @param o hash of properties to apply
678
* @param force {boolean} if true, properties that exist on the event
679
* will be overwritten.
681
applyConfig: function(o, force) {
683
Y.mix(this, o, force, CONFIGS);
687
_subscribe: function(fn, obj, args, when) {
690
Y.fail("Invalid callback for CE: " + this.type);
693
var se = this.subscribeEvent;
695
se.fire.apply(se, args);
698
var s = new Y.Subscriber(fn, obj, args, when);
701
if (this.fireOnce && this.fired) {
704
// setTimeout(Y.bind(this._notify, this, s), 0);
705
Y.later(0, this, this._notify, s);
709
this.afters[s.id] = s;
711
this.subscribers[s.id] = s;
714
return new Y.EventHandle(this, s);
719
* Listen for this event
721
* @param {Function} fn The function to execute
722
* @param {Object} obj An object to be passed along when the event fires
723
* @param args* 1..n params to provide to the listener
724
* @return {Event.Handle} unsubscribe handle
726
subscribe: function(fn, obj) {
727
return this._subscribe(fn, obj, Y.Array(arguments, 2, true));
731
* Listen for this event after the normal subscribers have been notified and
732
* the default behavior has been applied. If a normal subscriber prevents the
733
* default behavior, it also prevents after listeners from firing.
735
* @param {Function} fn The function to execute
736
* @param {Object} obj An object to be passed along when the event fires
737
* @param args* 1..n params to provide to the listener
738
* @return {Event.Handle} unsubscribe handle
740
after: function(fn, obj) {
741
return this._subscribe(fn, obj, Y.Array(arguments, 2, true), AFTER);
745
* Unsubscribes subscribers.
746
* @method unsubscribe
747
* @param {Function} fn The subscribed function to remove, if not supplied
748
* all will be removed
749
* @param {Object} obj The custom object passed to subscribe. This is
750
* optional, but if supplied will be used to
751
* disambiguate multiple listeners that are the same
752
* (e.g., you subscribe many object using a function
753
* that lives on the prototype)
754
* @return {boolean} True if the subscriber was found and detached.
756
unsubscribe: function(fn, obj) {
758
// if arg[0] typeof unsubscribe handle
759
if (fn && fn.detach) {
764
return this.unsubscribeAll();
767
var found = false, subs = this.subscribers;
768
for (var i in subs) {
769
if (subs.hasOwnProperty(i)) {
771
if (s && s.contains(fn, obj)) {
781
_getFacade: function(args) {
783
var ef = this._facade;
786
ef = new Y.Event.Facade(this, this.currentTarget);
789
// if the first argument is an object literal, apply the
790
// properties to the event facade
791
var o = args && args[0];
792
if (Y.Lang.isObject(o, true) && !o._yuifacade) {
796
// update the details field with the arguments
797
ef.details = this.details;
798
ef.target = this.target;
799
ef.currentTarget = this.currentTarget;
809
* Notify a single subscriber
811
* @param s {Event.Subscriber} the subscriber
812
* @param args {Array} the arguments array to apply to the listener
815
_notify: function(s, args, ef) {
820
// emit an Event.Facade if this is that sort of event
821
// if (this.emitFacade && (!args[0] || !args[0]._yuifacade)) {
822
if (this.emitFacade) {
824
// @TODO object literal support to fire makes it possible for
825
// config info to be passed if we wish.
828
ef = this._getFacade(args);
834
ret = s.notify(this.context, args);
836
if (false === ret || this.stopped > 1) {
844
* Logger abstraction to centralize the application of the silent flag
846
* @param msg {string} message to log
847
* @param cat {string} log category
849
log: function(msg, cat) {
850
var es = Y.Env._eventstack, s = es && es.silent;
851
// if (!s && !this.silent) {
857
* Notifies the subscribers. The callback functions will be executed
858
* from the context specified when the event was created, and with the
859
* following parameters:
861
* <li>The type of event</li>
862
* <li>All of the arguments fire() was executed with as an array</li>
863
* <li>The custom object (if any) that was passed into the subscribe()
867
* @param {Object*} arguments an arbitrary set of parameters to pass to
869
* @return {boolean} false if one of the subscribers returned false,
874
var es = Y.Env._eventstack;
878
// var b = this.bubbles, h = this.host;
880
// b = (h._yuievt.targets.length);
883
// es.silent = (es.silent || this.silent);
885
// queue this event if the current item in the queue bubbles
886
// if (b && this.queuable && this.type != es.next.type) {
887
if (this.queuable && this.type != es.next.type) {
890
es.queue.push([this, arguments]);
896
Y.Env._eventstack = {
897
// id of the first event in the stack
901
logging: (this.type === 'yui:log'),
907
es = Y.Env._eventstack;
912
if (this.fireOnce && this.fired) {
917
// var subs = this.subscribers.slice(), len=subs.length,
918
var subs = Y.merge(this.subscribers), s,
919
args=Y.Array(arguments, 0, true), i;
923
this.target = this.target || this.host;
925
this.currentTarget = this.host || this.currentTarget;
928
this.details = args.slice(); // original arguments in the details
932
es.lastLogState = es.logging;
936
if (this.emitFacade) {
937
ef = this._getFacade(args);
942
if (subs.hasOwnProperty(i)) {
945
es.logging = (es.logging || (this.type === 'yui:log'));
949
// stopImmediatePropagation
950
if (this.stopped == 2) {
956
ret = this._notify(s, args, ef);
964
es.logging = (es.lastLogState);
966
// bubble if this is hosted in an event target and propagation has not been stopped
967
// @TODO check if we need to worry about defaultFn order
968
if (this.bubbles && this.host && !this.stopped) {
971
ret = this.host.bubble(this);
973
this.stopped = Math.max(this.stopped, es.stopped);
974
this.prevented = Math.max(this.prevented, es.prevented);
977
// execute the default behavior if not prevented
978
// @TODO need context
979
if (this.defaultFn && !this.prevented) {
980
this.defaultFn.apply(this.host || this, args);
983
// process after listeners. If the default behavior was
984
// prevented, the after events don't fire.
985
if (!this.prevented && this.stopped < 2) {
986
subs = Y.merge(this.afters);
988
if (subs.hasOwnProperty(i)) {
991
es.logging = (es.logging || (this.type === 'yui:log'));
995
// stopImmediatePropagation
996
if (this.stopped == 2) {
1002
ret = this._notify(s, args, ef);
1003
if (false === ret) {
1012
if (es.id === this.id) {
1013
// console.log('clearing stack: ' + es.id + ', ' + this);
1015
// reset propragation properties while processing the rest of the queue
1017
// process queued events
1018
var queue = es.queue;
1020
while (queue.length) {
1021
// q[0] = the event, q[1] = arguments to fire
1022
var q = queue.pop(), ce = q[0];
1027
// set up stack to allow the next item to be processed
1030
ret = ce.fire.apply(ce, q[1]);
1033
Y.Env._eventstack = null;
1036
return (ret !== false);
1040
* Removes all listeners
1041
* @method unsubscribeAll
1042
* @return {int} The number of listeners unsubscribed
1044
unsubscribeAll: function() {
1045
var subs = this.subscribers, i;
1047
if (subs.hasOwnProperty(i)) {
1048
this._delete(subs[i]);
1052
this.subscribers={};
1059
* @param subscriber object
1062
_delete: function(s) {
1067
delete this.subscribers[s.id];
1068
delete this.afters[s.id];
1076
toString: function() {
1077
// return "{ CE '" + this.type + "' " + "id: " + this.id +
1078
// ", host: " + (this.host && Y.stamp(this.host) + " }");
1083
* Stop propagation to bubble targets
1084
* @method stopPropagation
1086
stopPropagation: function() {
1088
Y.Env._eventstack.stopped = 1;
1089
if (this.stoppedFn) {
1090
this.stoppedFn.call(this.host || this, this);
1095
* Stops propagation to bubble targets, and prevents any remaining
1096
* subscribers on the current target from executing.
1097
* @method stopImmediatePropagation
1099
stopImmediatePropagation: function() {
1101
Y.Env._eventstack.stopped = 2;
1102
if (this.stoppedFn) {
1103
this.stoppedFn.call(this.host || this, this);
1108
* Prevents the execution of this event's defaultFn
1109
* @method preventDefault
1111
preventDefault: function() {
1112
if (this.preventable) {
1114
Y.Env._eventstack.prevented = 1;
1116
if (this.preventedFn) {
1117
this.preventedFn.call(this.host || this, this);
1123
/////////////////////////////////////////////////////////////////////
1126
* Stores the subscriber information to be used when the event fires.
1127
* @param {Function} fn The wrapped function to execute
1128
* @param {Object} obj An object to be passed along when the event fires
1129
* @param {Array} args subscribe() additional arguments
1131
* @class Event.Subscriber
1134
Y.Subscriber = function(fn, obj, args) {
1137
* The callback that will be execute when the event fires
1138
* This is wrapped by Y.bind if obj was supplied.
1145
* An optional custom object that will passed to the callback when
1153
* Unique subscriber id
1157
this.id = Y.stamp(this);
1160
* Optional additional arguments supplied to subscribe(). If present,
1161
* these will be appended to the arguments supplied to fire()
1165
// this.args = args;
1170
var a = (args) ? Y.Array(args) : [];
1172
m = Y.bind.apply(Y, a);
1177
* fn bound to obj with additional arguments applied via Y.bind
1178
* @property wrappedFn
1185
Y.Subscriber.prototype = {
1188
* Executes the subscriber.
1190
* @param defaultContext The execution context if not overridden
1192
* @param args {Array} Arguments array for the subscriber
1194
notify: function(defaultContext, args) {
1195
var c = this.obj || defaultContext, ret = true;
1198
ret = this.wrappedFn.apply(c, args);
1200
Y.fail(this + ' failed: ' + e.message, e);
1207
* Returns true if the fn and obj match this objects properties.
1208
* Used by the unsubscribe method to match the right subscriber.
1211
* @param {Function} fn the function to execute
1212
* @param {Object} obj an object to be passed along when the event fires
1213
* @return {boolean} true if the supplied arguments match this
1214
* subscriber's signature.
1216
contains: function(fn, obj) {
1218
return ((this.fn == fn) && this.obj == obj);
1220
return (this.fn == fn);
1227
toString: function() {
1228
return "Subscriber " + this.id;
1234
* Configures an object to be able to be targeted for events, and to publish events
1235
* @submodule event-target
1238
YUI.add("event-target", function(Y) {
1240
var SILENT = { 'yui:log': true };
1243
* Event.Target is designed to be used with Y.augment to wrap
1244
* Event.Custom in an interface that allows events to be subscribed to
1245
* and fired by name. This makes it possible for implementing code to
1246
* subscribe to an event that either has not been created yet, or will
1247
* not be created at all.
1249
* @Class Event.Target
1251
Y.EventTarget = function(opts) {
1253
// console.log('Event.Target constructor executed: ' + this._yuid);
1255
var o = (Y.Lang.isObject(opts)) ? opts : {};
1268
emitFacade: o.emitFacade || false,
1269
bubbles: ('bubbles' in o) ? o.bubbles : true
1276
var ET = Y.EventTarget;
1281
* Subscribe to a custom event hosted by this object
1283
* @param type {string} The type of the event
1284
* @param fn {Function} The callback
1285
* @param context The execution context
1286
* @param args* 1..n params to supply to the callback
1288
subscribe: function(type, fn, context) {
1290
var ce = this._yuievt.events[type] ||
1291
// this.publish(type, {
1292
// configured: false
1295
a = Y.Array(arguments, 1, true);
1297
return ce.subscribe.apply(ce, a);
1302
* Unsubscribes one or more listeners the from the specified event
1303
* @method unsubscribe
1304
* @param type {string|Object} Either the handle to the subscriber or the
1305
* type of event. If the type
1306
* is not specified, it will attempt to remove
1307
* the listener from all hosted events.
1308
* @param fn {Function} The subscribed function to unsubscribe, if not
1309
* supplied, all subscribers will be removed.
1310
* @param context {Object} The custom object passed to subscribe. This is
1311
* optional, but if supplied will be used to
1312
* disambiguate multiple listeners that are the same
1313
* (e.g., you subscribe many object using a function
1314
* that lives on the prototype)
1315
* @return {boolean} true if the subscriber was found and detached.
1317
unsubscribe: function(type, fn, context) {
1319
// If this is an event handle, use it to detach
1320
if (Y.Lang.isObject(type) && type.detach) {
1321
return type.detach();
1324
var evts = this._yuievt.events;
1327
var ce = evts[type];
1329
return ce.unsubscribe(fn, context);
1333
for (var i in evts) {
1334
if (Y.Object.owns(evts, i)) {
1335
ret = ret && evts[i].unsubscribe(fn, context);
1345
* Removes all listeners from the specified event. If the event type
1346
* is not specified, all listeners from all hosted custom events will
1348
* @method unsubscribeAll
1349
* @param type {string} The type, or name of the event
1351
unsubscribeAll: function(type) {
1352
return this.unsubscribe(type);
1356
* Creates a new custom event of the specified type. If a custom event
1357
* by that name already exists, it will not be re-created. In either
1358
* case the custom event is returned.
1362
* @param type {string} the type, or name of the event
1363
* @param opts {object} optional config params. Valid properties are:
1367
* 'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
1370
* 'bubbles': whether or not this event bubbles (true)
1373
* 'context': the default execution context for the listeners (this)
1376
* 'defaultFn': the default function to execute when this event fires if preventDefault was not called
1379
* 'emitFacade': whether or not this event emits a facade (false)
1382
* 'fireOnce': if an event is configured to fire once, new subscribers after
1383
* the fire will be notified immediately.
1386
* 'preventable': whether or not preventDefault() has an effect (true)
1389
* 'preventedFn': a function that is executed when preventDefault is called
1392
* 'queuable': whether or not this event can be queued during bubbling (false)
1395
* 'silent': if silent is true, debug messages are not provided for this event.
1398
* 'stoppedFn': a function that is executed when stopPropagation is called
1401
* 'type': the event type (valid option if not provided as the first parameter to publish)
1405
* @return {Event.Custom} the custom event
1408
publish: function(type, opts) {
1410
var events = this._yuievt.events, ce = events[type];
1412
//if (ce && !ce.configured) {
1415
// This event could have been published
1416
ce.applyConfig(opts, true);
1417
// ce.configured = true;
1423
Y.mix(o, this._yuievt.defaults);
1425
ce = new Y.CustomEvent(type, o);
1429
if (o.onSubscribeCallback) {
1430
ce.subscribeEvent.subscribe(o.onSubscribeCallback);
1435
return events[type];
1439
* Registers another Event.Target as a bubble target. Bubble order
1440
* is determined by the order registered. Multiple targets can
1443
* @param o {Event.Target} the target to add
1445
addTarget: function(o) {
1446
this._yuievt.targets[Y.stamp(o)] = o;
1447
this._yuievt.hasTargets = true;
1451
* Removes a bubble target
1452
* @method removeTarget
1453
* @param o {Event.Target} the target to remove
1455
removeTarget: function(o) {
1456
delete this._yuievt.targets[Y.stamp(o)];
1460
* Fire a custom event by name. The callback functions will be executed
1461
* from the context specified when the event was created, and with the
1462
* following parameters.
1464
* If the custom event object hasn't been created, then the event hasn't
1465
* been published and it has no subscribers. For performance sake, we
1466
* immediate exit in this case. This means the event won't bubble, so
1467
* if the intention is that a bubble target be notified, the event must
1468
* be published on this object first.
1471
* @param type {String|Object} The type of the event, or an object that contains
1472
* a 'type' property.
1473
* @param arguments {Object*} an arbitrary set of parameters to pass to
1475
* @return {boolean} the return value from Event.Custom.fire
1478
fire: function(type) {
1480
var typeIncluded = Y.Lang.isString(type),
1481
t = (typeIncluded) ? type : (type && type.type);
1483
var ce = this.getEvent(t);
1485
// this event has not been published or subscribed to
1488
// if this object has bubble targets, we need to publish the
1489
// event in order for it to bubble.
1490
if (this._yuievt.hasTargets) {
1491
// ce = this.publish(t, {
1492
// configured: false
1494
ce = this.publish(t);
1495
ce.details = Y.Array(arguments, (typeIncluded) ? 1 : 0, true);
1497
return this.bubble(ce);
1500
// otherwise there is nothing to be done
1504
// Provide this object's subscribers the object they are listening to.
1505
// ce.currentTarget = this;
1507
// This this the target unless target is current not null
1508
// (set in bubble()).
1509
// ce.target = ce.target || this;
1511
var a = Y.Array(arguments, (typeIncluded) ? 1 : 0, true);
1512
var ret = ce.fire.apply(ce, a);
1514
// clear target for next fire()
1521
* Returns the custom event of the provided type has been created, a
1522
* falsy value otherwise
1524
* @param type {string} the type, or name of the event
1525
* @return {Event.Custom} the custom event or null
1527
getEvent: function(type) {
1528
var e = this._yuievt.events;
1529
return (e && type in e) ? e[type] : null;
1533
* Propagate an event
1535
* @param evt {Event.Custom} the custom event to propagate
1536
* @return {boolean} the aggregated return value from Event.Custom.fire
1538
bubble: function(evt) {
1540
var targs = this._yuievt.targets, ret = true;
1542
if (!evt.stopped && targs) {
1545
for (var i in targs) {
1546
if (targs.hasOwnProperty(i)) {
1548
var t = targs[i], type = evt.type,
1549
ce = t.getEvent(type), targetProp = evt.target || this;
1551
// if this event was not published on the bubble target,
1552
// publish it with sensible default properties
1555
// publish the event on the bubble target using this event
1556
// for its configuration
1557
ce = t.publish(type, evt);
1558
// ce.configured = false;
1560
// set the host and context appropriately
1561
ce.context = (evt.host === evt.context) ? t : evt.context;
1564
// clear handlers if specified on this event
1565
ce.defaultFn = null;
1566
ce.preventedFn = null;
1567
ce.stoppedFn = null;
1570
ce.target = targetProp;
1571
ce.currentTarget = t;
1573
// ce.target = evt.target;
1575
ret = ret && ce.fire.apply(ce, evt.details);
1577
// stopPropagation() was called
1589
* Subscribe to a custom event hosted by this object. The
1590
* supplied callback will execute after any listeners add
1591
* via the subscribe method, and after the default function,
1592
* if configured for the event, has executed.
1594
* @param type {string} The type of the event
1595
* @param fn {Function} The callback
1596
* @param context The execution context
1597
* @param args* 1..n params to supply to the callback
1599
after: function(type, fn) {
1600
var ce = this._yuievt.events[type] ||
1601
// this.publish(type, {
1602
// configured: false
1605
a = Y.Array(arguments, 1, true);
1607
return ce.after.apply(ce, a);
1612
// make Y an event target
1613
Y.mix(Y, ET.prototype, false, false, {
1623
* @submodule event-ready
1632
POLL_INTERVAL = C.pollInterval || 20;
1636
Env.windowLoaded = false;
1638
Env._ready = function() {
1639
if (!Env.DOMReady) {
1642
// Remove the DOMContentLoaded (FF/Opera)
1643
if (D.removeEventListener) {
1644
D.removeEventListener("DOMContentLoaded", _ready, false);
1649
var _ready = function(e) {
1653
// create custom event
1655
/////////////////////////////////////////////////////////////
1657
// based on work by: Dean Edwards/John Resig/Matthias Miller
1659
// Internet Explorer: use the readyState of a defered script.
1660
// This isolates what appears to be a safe moment to manipulate
1661
// the DOM prior to when the document's readyState suggests
1662
// it is safe to do so.
1663
if (navigator.userAgent.match(/MSIE/)) {
1665
Env._dri = setInterval(function() {
1667
// throws an error if doc is not ready
1668
document.documentElement.doScroll('left');
1669
clearInterval(Env._dri);
1676
// FireFox and Opera: These browsers provide a event for this
1677
// moment. The latest WebKit releases now support this event.
1679
D.addEventListener("DOMContentLoaded", _ready, false);
1682
/////////////////////////////////////////////////////////////
1685
YUI.add("event-ready", function(Y) {
1691
Y.publish('event:ready', {
1695
var yready = function() {
1696
Y.fire('event:ready');
1702
Y.before(yready, Env, "_ready");
1709
* The YUI DOM event system
1710
* @submodule event-dom
1715
var add = function(el, type, fn, capture) {
1716
if (el.addEventListener) {
1717
el.addEventListener(type, fn, !!capture);
1718
} else if (el.attachEvent) {
1719
el.attachEvent("on" + type, fn);
1723
remove = function(el, type, fn, capture) {
1724
if (el.removeEventListener) {
1725
el.removeEventListener(type, fn, !!capture);
1726
} else if (el.detachEvent) {
1727
el.detachEvent("on" + type, fn);
1731
onLoad = function() {
1732
YUI.Env.windowLoaded = true;
1733
remove(window, "load", onLoad);
1736
add(window, "load", onLoad);
1738
YUI.add("event-dom", function(Y) {
1741
* The Event Utility provides utilities for managing DOM Events and tools
1742
* for building event systems
1745
* @title Event Utility
1749
* The event utility provides functions to add and remove event listeners,
1750
* event cleansing. It also tries to automatically remove listeners it
1751
* registers during the unload event.
1756
Y.Event = function() {
1759
* True after the onload event has fired
1760
* @property loadComplete
1765
var loadComplete = false;
1768
* The number of times to poll after window.onload. This number is
1769
* increased if additional late-bound handlers are requested after
1771
* @property _retryCount
1775
var _retryCount = 0;
1778
* onAvailable listeners
1786
* Custom event wrappers for DOM events. Key is
1787
* 'event:' + Element uid stamp + event type
1788
* @property _wrappers
1789
* @type Y.Event.Custom
1795
var _windowLoadKey = null;
1798
* Custom event wrapper map DOM events. Key is
1799
* Element uid stamp. Each item is a hash of custom event
1800
* wrappers as provided in the _wrappers collection. This
1801
* provides the infrastructure for getListeners.
1802
* @property _el_events
1806
var _el_events = {};
1811
* The number of times we should look for elements that are not
1812
* in the DOM at the time the event is requested after the document
1813
* has been loaded. The default is 2000@amp;20 ms, so it will poll
1814
* for 40 seconds or until all outstanding handlers are bound
1815
* (whichever comes first).
1816
* @property POLL_RETRYS
1824
* The poll interval in milliseconds
1825
* @property POLL_INTERVAL
1833
* addListener/removeListener can throw errors in unexpected scenarios.
1834
* These errors are suppressed, the method returns false, and this property
1836
* @property lastError
1845
* @property _interval
1852
* document readystate poll handle
1860
* True when the document is initially usable
1861
* @property DOMReady
1868
* @method startInterval
1872
startInterval: function() {
1873
if (!this._interval) {
1874
this._interval = setInterval(Y.bind(this._tryPreloadAttach, this), this.POLL_INTERVAL);
1879
* Executes the supplied callback when the item with the supplied
1880
* id is found. This is meant to be used to execute behavior as
1881
* soon as possible as the page loads. If you use this after the
1882
* initial page load it will poll for a fixed time for the element.
1883
* The number of times it will poll and the frequency are
1884
* configurable. By default it will poll for 10 seconds.
1886
* <p>The callback is executed with a single parameter:
1887
* the custom object parameter, if provided.</p>
1889
* @method onAvailable
1891
* @param {string||string[]} id the id of the element, or an array
1892
* of ids to look for.
1893
* @param {function} fn what to execute when the element is found.
1894
* @param {object} p_obj an optional object to be passed back as
1895
* a parameter to fn.
1896
* @param {boolean|object} p_override If set to true, fn will execute
1897
* in the context of p_obj, if set to an object it
1898
* will execute in the context of that object
1899
* @param checkContent {boolean} check child node readiness (onContentReady)
1901
* @deprecated This will be replaced with a special Y.on custom event
1903
// @TODO fix arguments
1904
onAvailable: function(id, fn, p_obj, p_override, checkContent) {
1906
// var a = (Y.Lang.isString(id)) ? [id] : id;
1907
var a = Y.Array(id);
1909
for (var i=0; i<a.length; i=i+1) {
1910
_avail.push({ id: a[i],
1913
override: p_override,
1914
checkReady: checkContent });
1916
_retryCount = this.POLL_RETRYS;
1917
// this.startInterval();
1918
// this._tryPreloadAttach();
1920
// We want the first test to be immediate, but async
1921
setTimeout(Y.bind(this._tryPreloadAttach, this), 0);
1925
* Works the same way as onAvailable, but additionally checks the
1926
* state of sibling elements to determine if the content of the
1927
* available element is safe to modify.
1929
* <p>The callback is executed with a single parameter:
1930
* the custom object parameter, if provided.</p>
1932
* @method onContentReady
1934
* @param {string} id the id of the element to look for.
1935
* @param {function} fn what to execute when the element is ready.
1936
* @param {object} p_obj an optional object to be passed back as
1937
* a parameter to fn.
1938
* @param {boolean|object} p_override If set to true, fn will execute
1939
* in the context of p_obj. If an object, fn will
1940
* exectute in the context of that object
1943
* @deprecated This will be replaced with a special Y.on custom event
1945
// @TODO fix arguments
1946
onContentReady: function(id, fn, p_obj, p_override) {
1947
this.onAvailable(id, fn, p_obj, p_override, true);
1951
* Executes the supplied callback when the DOM is first usable. This
1952
* will execute immediately if called after the DOMReady event has
1953
* fired. @todo the DOMContentReady event does not fire when the
1954
* script is dynamically injected into the page. This means the
1955
* DOMReady custom event will never fire in FireFox or Opera when the
1956
* library is injected. It _will_ fire in Safari, and the IE
1957
* implementation would allow for us to fire it if the defered script
1958
* is not available. We want this to behave the same in all browsers.
1959
* Is there a way to identify when the script has been injected
1960
* instead of included inline? Is there a way to know whether the
1961
* window onload event has fired without having had a listener attached
1962
* to it when it did so?
1964
* <p>The callback is a Event.Custom, so the signature is:</p>
1965
* <p>type <string>, args <array>, customobject <object></p>
1966
* <p>For DOMReady events, there are no fire argments, so the
1968
* <p>"DOMReady", [], obj</p>
1971
* @method onDOMReady
1973
* @param {function} fn what to execute when the element is found.
1974
* @optional context execution context
1975
* @optional args 1..n arguments to send to the listener
1978
* @deprecated Use Y.on('event:ready');
1980
onDOMReady: function(fn) {
1981
// var ev = Y.Event.DOMReadyEvent;
1982
// ev.subscribe.apply(ev, arguments);
1983
var a = Y.Array(arguments, 0, true);
1984
a.unshift('event:ready');
1989
* Appends an event handler
1991
* @method addListener
1993
* @param {String|HTMLElement|Array|NodeList} el An id, an element
1994
* reference, or a collection of ids and/or elements to assign the
1996
* @param {String} type The type of event to append
1997
* @param {Function} fn The method the event invokes
1998
* @param {Object} obj An arbitrary object that will be
1999
* passed as a parameter to the handler
2000
* @param {Boolean|object} args 1..n ar
2001
* @return {Boolean} True if the action was successful or defered,
2002
* false if one or more of the elements
2003
* could not have the listener attached,
2004
* or if the operation throws an exception.
2006
* @deprecated Use Y.on instead. This will be removed in PR2
2008
addListener: function(el, type, fn, obj) {
2011
var a=Y.Array(arguments, 1, true), override = a[3], E = Y.Event,
2012
aa=Y.Array(arguments, 0, true);
2014
if (!fn || !fn.call) {
2015
// throw new TypeError(type + " addListener call failed, callback undefined");
2019
// The el argument can be an array of elements or element ids.
2020
if (this._isValidCollection(el)) {
2023
var handles=[], h, i, l, proc = function(v, k) {
2024
// handles.push(this.addListener(el[i], type, fn, obj, override));
2025
// var node = el.item(k);
2029
h = E.addListener.apply(E, b);
2033
Y.each(el, proc, E);
2039
} else if (Y.Lang.isString(el)) {
2040
var oEl = Y.all(el);
2041
// If the el argument is a string, we assume it is
2042
// actually the id of the element. If the page is loaded
2043
// we convert el to the actual element, otherwise we
2044
// defer attaching the event until onload event fires
2046
// check to see if we need to delay hooking up the event
2047
// until after the page loads.
2048
var size = oEl.size();
2052
return E.addListener.apply(E, aa);
2058
// defer adding the event until the element is available
2059
this.onAvailable(el, function() {
2060
// Y.Event.addListener(el, type, fn, obj, override);
2061
Y.Event.addListener.apply(Y.Event, aa);
2068
// Element should be an html element or an array if we get
2074
// the custom event key is the uid for the element + type
2076
var ek = Y.stamp(el), key = 'event:' + ek + type,
2077
cewrapper = _wrappers[key];
2081
// create CE wrapper
2082
cewrapper = Y.publish(key, {
2088
// cache the dom event details in the custom event
2089
// for later removeListener calls
2091
cewrapper.type = type;
2092
cewrapper.fn = function(e) {
2093
cewrapper.fire(Y.Event.getEvent(e, el));
2096
if (el == Y.config.win && type == "load") {
2097
// window load happens once
2098
cewrapper.fireOnce = true;
2099
_windowLoadKey = key;
2101
// if the load is complete, fire immediately.
2102
// all subscribers, including the current one
2103
// will be notified.
2104
if (YUI.Env.windowLoaded) {
2109
_wrappers[key] = cewrapper;
2110
_el_events[ek] = _el_events[ek] || {};
2111
_el_events[ek][key] = cewrapper;
2113
// var capture = (Y.lang.isObject(obj) && obj.capture);
2114
// attach a listener that fires the custom event
2115
this.nativeAdd(el, type, cewrapper.fn, false);
2119
// from type, fn, etc to fn, obj, override
2120
a = Y.Array(arguments, 2, true);
2123
var context = obj || Y.get(el);
2125
// if (override === true) {
2128
// context = override;
2134
// set context to the Node if not specified
2135
return cewrapper.subscribe.apply(cewrapper, a);
2141
* Removes an event listener. Supports the signature the event was bound
2142
* with, but the preferred way to remove listeners is using the handle
2143
* that is returned when using Y.on
2145
* @method removeListener
2147
* @param {String|HTMLElement|Array|NodeList} el An id, an element
2148
* reference, or a collection of ids and/or elements to remove
2149
* the listener from.
2150
* @param {String} type the type of event to remove.
2151
* @param {Function} fn the method the event invokes. If fn is
2152
* undefined, then all event handlers for the type of event are * removed.
2153
* @return {boolean} true if the unbind was successful, false * otherwise.
2156
removeListener: function(el, type, fn) {
2158
if (el && el.detach) {
2163
// The el argument can be a string
2164
if (typeof el == "string") {
2166
// The el argument can be an array of elements or element ids.
2167
} else if ( this._isValidCollection(el)) {
2169
for (i=0,len=el.length; i<len; ++i) {
2170
ok = ( this.removeListener(el[i], type, fn) && ok );
2175
if (!fn || !fn.call) {
2177
return this.purgeElement(el, false, type);
2181
var id = 'event:' + Y.stamp(el) + type,
2184
return ce.unsubscribe(fn);
2192
* Finds the event in the window object, the caller's arguments, or
2193
* in the arguments of another method in the callstack. This is
2194
* executed automatically for events registered through the event
2195
* manager, so the implementer should not normally need to execute
2196
* this function at all.
2198
* @param {Event} e the event parameter from the handler
2199
* @param {HTMLElement} boundEl the element the listener is attached to
2200
* @return {Event} the event
2203
getEvent: function(e, boundEl) {
2204
var ev = e || window.event;
2207
var c = this.getEvent.caller;
2209
ev = c.arguments[0];
2210
if (ev && Event == ev.constructor) {
2218
return new Y.Event.Facade(ev, boundEl, _wrappers['event:' + Y.stamp(boundEl) + e.type]);
2223
* Generates an unique ID for the element if it does not already
2225
* @method generateId
2226
* @param el the element to create the id for
2227
* @return {string} the resulting id of the element
2230
generateId: function(el) {
2243
* We want to be able to use getElementsByTagName as a collection
2244
* to attach a group of events to. Unfortunately, different
2245
* browsers return different types of collections. This function
2246
* tests to determine if the object is array-like. It will also
2247
* fail if the object is an array, but is empty.
2248
* @method _isValidCollection
2249
* @param o the object to test
2250
* @return {boolean} true if the object is array-like and populated
2254
_isValidCollection: function(o) {
2256
return ( o && // o is something
2257
typeof o !== "string" && // o is not a string
2258
(o.each || o.length) && // o is indexed
2259
!o.tagName && // o is not an HTML element
2260
!o.alert && // o is not a window
2261
(o.item || typeof o[0] !== "undefined") );
2269
* Custom event the fires when the dom is initially usable
2270
* @event DOMReadyEvent
2272
// DOMReadyEvent: new Y.CustomEvent("event:ready", this),
2273
// DOMReadyEvent: Y.publish("event:ready", this, {
2278
* hook up any deferred listeners
2283
_load: function(e) {
2285
if (!loadComplete) {
2288
loadComplete = true;
2290
// Just in case DOMReady did not go off for some reason
2293
Y.fire('event:ready');
2296
// Available elements may not have been detected before the
2297
// window load event fires. Try to find them now so that the
2298
// the user is more likely to get the onAvailable notifications
2299
// before the window load notification
2300
Y.Event._tryPreloadAttach();
2306
* Polling function that runs before the onload event fires,
2307
* attempting to attach to DOM Nodes as soon as they are
2309
* @method _tryPreloadAttach
2313
_tryPreloadAttach: function() {
2319
if (Y.UA.ie && !YUI.Env.DOMReady) {
2320
// Hold off if DOMReady has not fired and check current
2321
// readyState to protect against the IE operation aborted
2323
this.startInterval();
2330
// keep trying until after the page is loaded. We need to
2331
// check the page load state prior to trying to bind the
2332
// elements so that we can be certain all elements have been
2333
// tested appropriately
2334
var tryAgain = !loadComplete;
2336
tryAgain = (_retryCount > 0);
2342
var executeItem = function (el, item) {
2344
if (item.override) {
2345
if (item.override === true) {
2348
context = item.override;
2351
context = Y.get(el);
2353
item.fn.call(context, item.obj);
2359
for (i=0,len=_avail.length; i<len; ++i) {
2361
if (item && !item.checkReady) {
2362
el = Y.get(item.id);
2364
executeItem(el, item);
2367
notAvail.push(item);
2373
for (i=0,len=_avail.length; i<len; ++i) {
2375
if (item && item.checkReady) {
2376
el = Y.get(item.id);
2379
// The element is available, but not necessarily ready
2380
// @todo should we test parentNode.nextSibling?
2381
if (loadComplete || el.get('nextSibling')) {
2382
executeItem(el, item);
2386
notAvail.push(item);
2391
_retryCount = (notAvail.length === 0) ? 0 : _retryCount - 1;
2394
// we may need to strip the nulled out items here
2395
this.startInterval();
2397
clearInterval(this._interval);
2398
this._interval = null;
2401
this.locked = false;
2408
* Removes all listeners attached to the given element via addListener.
2409
* Optionally, the node's children can also be purged.
2410
* Optionally, you can specify a specific type of event to remove.
2411
* @method purgeElement
2412
* @param {HTMLElement} el the element to purge
2413
* @param {boolean} recurse recursively purge this element's children
2414
* as well. Use with caution.
2415
* @param {string} type optional type of listener to purge. If
2416
* left out, all listeners will be removed
2419
purgeElement: function(el, recurse, type) {
2420
var oEl = (Y.Lang.isString(el)) ? Y.get(el) : el,
2422
var lis = this.getListeners(oEl, type), i, len;
2424
for (i=0,len=lis.length; i<len ; ++i) {
2425
lis[i].unsubscribeAll();
2429
if (recurse && oEl && oEl.childNodes) {
2430
for (i=0,len=oEl.childNodes.length; i<len ; ++i) {
2431
this.purgeElement(oEl.childNodes[i], recurse, type);
2437
* Returns all listeners attached to the given element via addListener.
2438
* Optionally, you can specify a specific type of event to return.
2439
* @method getListeners
2440
* @param el {HTMLElement|string} the element or element id to inspect
2441
* @param type {string} optional type of listener to return. If
2442
* left out, all listeners will be returned
2443
* @return {Y.Custom.Event} the custom event wrapper for the DOM event(s)
2446
getListeners: function(el, type) {
2447
var results=[], ek = Y.stamp(el), key = (type) ? 'event:' + type : null,
2448
evts = _el_events[ek];
2452
results.push(evts[key]);
2455
for (var i in evts) {
2456
results.push(evts[i]);
2460
return (results.length) ? results : null;
2464
* Removes all listeners registered by pe.event. Called
2465
* automatically during the unload event.
2470
_unload: function(e) {
2472
var E = Y.Event, i, w;
2474
for (i in _wrappers) {
2477
E.nativeRemove(w.el, w.type, w.fn);
2478
delete _wrappers[i];
2481
E.nativeRemove(window, "unload", E._unload);
2486
* Adds a DOM event directly without the caching, cleanup, context adj, etc
2489
* @param {HTMLElement} el the element to bind the handler to
2490
* @param {string} type the type of event handler
2491
* @param {function} fn the callback to invoke
2492
* @param {boolen} capture capture or bubble phase
2499
* Basic remove listener
2501
* @method nativeRemove
2502
* @param {HTMLElement} el the element to bind the handler to
2503
* @param {string} type the type of event handler
2504
* @param {function} fn the callback to invoke
2505
* @param {boolen} capture capture or bubble phase
2509
nativeRemove: remove
2516
// Process onAvailable/onContentReady items when when the DOM is ready in IE
2517
if (Y.UA.ie && Y.on) {
2518
Y.on('event:ready', E._tryPreloadAttach, E, true);
2521
E.Custom = Y.CustomEvent;
2522
E.Subscriber = Y.Subscriber;
2523
E.Target = Y.EventTarget;
2526
* Y.Event.on is an alias for addListener
2531
E.attach = function(type, fn, el, data, context) {
2532
var a = Y.Array(arguments, 0, true),
2533
oEl = a.splice(2, 1);
2535
return E.addListener.apply(E, a);
2538
E.detach = function(type, fn, el, data, context) {
2539
return E.removeListener(el, type, fn, data, context);
2542
E.attach("load", E._load, window, E);
2543
E.nativeAdd(window, "unload", E._unload);
2545
E._tryPreloadAttach();
2551
* A wrapper for DOM events and Custom Events
2552
* @submodule event-facade
2555
YUI.add("event-facade", function(Y) {
2560
// "button" : 1, // we supply
2561
// "bubbles" : 1, // needed?
2562
// "cancelable" : 1, // needed?
2563
// "charCode" : 1, // we supply
2565
// "currentTarget" : 1, // we supply
2567
"clientX" : 1, // needed?
2568
"clientY" : 1, // needed?
2569
"detail" : 1, // not fully implemented
2570
// "fromElement" : 1,
2572
// "height" : 1, // needed?
2573
// "initEvent" : 1, // need the init events?
2574
// "initMouseEvent" : 1,
2575
// "initUIEvent" : 1,
2576
// "layerX" : 1, // needed?
2577
// "layerY" : 1, // needed?
2579
// "modifiers" : 1, // needed?
2580
// "offsetX" : 1, // needed?
2581
// "offsetY" : 1, // needed?
2582
// "preventDefault" : 1, // we supply
2583
// "reason" : 1, // IE proprietary
2584
// "relatedTarget" : 1,
2585
// "returnValue" : 1, // needed?
2587
// "srcUrn" : 1, // IE proprietary
2588
// "srcElement" : 1,
2589
// "srcFilter" : 1, IE proprietary
2590
// "stopPropagation" : 1, // we supply
2592
// "timeStamp" : 1, // needed?
2596
// "which" : 1, // we supply
2597
// "width" : 1, // needed?
2605
* webkit key remapping required for Safari < 3.1
2606
* @property webkitKeymap
2614
63276: 33, // page up
2615
63277: 34, // page down
2616
25: 9 // SHIFT-TAB (Safari provides a different key code in
2617
// this case, even though the shiftKey modifier is set)
2621
* Returns a wrapped node. Intended to be used on event targets,
2622
* so it will return the node's parent if the target is a text
2627
resolve = function(n) {
2634
if (ua.webkit && 3 == n.nodeType) {
2639
return Y.Node.get(n);
2643
// provide a single event with browser abstractions resolved
2645
// include all properties for both browers?
2646
// include only DOM2 spec properties?
2647
// provide browser-specific facade?
2650
* Wraps a DOM event, properties requiring browser abstraction are
2651
* fixed here. Provids a security layer when required.
2652
* @class Event.Facade
2653
* @param ev {Event} the DOM event
2654
* @param currentTarget {HTMLElement} the element the listener was attached to
2655
* @param wrapper {Event.Custom} the custom event wrapper for this DOM event
2657
Y.Event.Facade = function(ev, currentTarget, wrapper, details) {
2659
// @TODO the document should be the target's owner document
2661
var e = ev, ot = currentTarget, d = Y.config.doc, b = d.body,
2662
x = e.pageX, y = e.pageY, isCE = (ev._YUI_EVENT);
2664
// copy all primitives ... this is slow in FF
2665
// for (var i in e) {
2666
for (var i in whitelist) {
2667
// if (!Y.Lang.isObject(e[i])) {
2668
if (whitelist.hasOwnProperty(i)) {
2673
//////////////////////////////////////////////////////
2675
if (!x && 0 !== x) {
2680
x += Math.max(d.documentElement.scrollLeft, b.scrollLeft);
2681
y += Math.max(d.documentElement.scrollTop, b.scrollTop);
2685
this._yuifacade = true;
2688
* The X location of the event on the page (including scroll)
2695
* The Y location of the event on the page (including scroll)
2701
//////////////////////////////////////////////////////
2704
* The keyCode for key events. Uses charCode if keyCode is not available
2708
var c = e.keyCode || e.charCode || 0;
2710
if (ua.webkit && (c in webkitKeymap)) {
2711
c = webkitKeymap[c];
2715
* The keyCode for key events. Uses charCode if keyCode is not available
2722
* The charCode for key events. Same as keyCode
2723
* @property charCode
2728
//////////////////////////////////////////////////////
2731
* The button that was pushed.
2735
this.button = e.which || e.button;
2738
* The button that was pushed. Same as button.
2742
this.which = this.button;
2745
* The event details. Currently supported for Custom
2746
* Events only, where it contains the arguments that
2747
* were passed to fire().
2751
this.details = details;
2753
//////////////////////////////////////////////////////
2756
* Timestamp for the event
2760
this.time = e.time || new Date().getTime();
2762
//////////////////////////////////////////////////////
2765
* Node reference for the targeted element
2769
this.target = (isCE) ? e.target : resolve(e.target || e.srcElement);
2772
* Node reference for the element that the listener was attached to.
2773
* @propery currentTarget
2776
this.currentTarget = (isCE) ? ot : resolve(ot);
2778
var t = e.relatedTarget;
2780
if (e.type == "mouseout") {
2782
} else if (e.type == "mouseover") {
2788
* Node reference to the relatedTarget
2789
* @propery relatedTarget
2792
this.relatedTarget = (isCE) ? t : resolve(t);
2794
//////////////////////////////////////////////////////
2798
* Stops the propagation to the next bubble target
2799
* @method stopPropagation
2801
this.stopPropagation = function() {
2802
if (e.stopPropagation) {
2803
e.stopPropagation();
2805
e.cancelBubble = true;
2808
wrapper.stopPropagation();
2813
* Stops the propagation to the next bubble target and
2814
* prevents any additional listeners from being exectued
2815
* on the current target.
2816
* @method stopImmediatePropagation
2818
this.stopImmediatePropagation = function() {
2820
if (e.stopImmediatePropagation) {
2821
e.stopImmediatePropagation();
2823
this.stopPropagation();
2827
wrapper.stopImmediatePropagation();
2833
* Prevents the event's default behavior
2834
* @method preventDefault
2836
this.preventDefault = function() {
2837
if (e.preventDefault) {
2840
e.returnValue = false;
2843
wrapper.preventDefault();
2848
* Stops the event propagation and prevents the default
2851
* @param immediate {boolean} if true additional listeners
2852
* on the current target will not be executed
2854
this.halt = function(immediate) {
2856
this.stopImmediatePropagation();
2858
this.stopPropagation();
2860
this.preventDefault();