2
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
Code licensed under the BSD License:
4
http://developer.yahoo.com/yui/license.html
8
YUI.add('event-custom-base', function(Y) {
11
* Custom event engine, DOM event listener abstraction layer, synthetic DOM
13
* @module event-custom
23
* Custom event engine, DOM event listener abstraction layer, synthetic DOM
25
* @module event-custom
26
* @submodule event-custom-base
31
* Allows for the insertion of methods that are executed before or after
43
* Cache of objects touched by the utility
50
* Execute the supplied method before the specified function
52
* @param fn {Function} the function to execute
53
* @param obj the object hosting the method to displace
54
* @param sFn {string} the name of the method to displace
55
* @param c The execution context for fn
56
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
57
* when the event fires.
58
* @return {string} handle for the subscription
61
before: function(fn, obj, sFn, c) {
64
a = [fn, c].concat(Y.Array(arguments, 4, true));
65
f = Y.rbind.apply(Y, a);
68
return this._inject(BEFORE, f, obj, sFn);
72
* Execute the supplied method after the specified function
74
* @param fn {Function} the function to execute
75
* @param obj the object hosting the method to displace
76
* @param sFn {string} the name of the method to displace
77
* @param c The execution context for fn
78
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
79
* @return {string} handle for the subscription
82
after: function(fn, obj, sFn, c) {
85
a = [fn, c].concat(Y.Array(arguments, 4, true));
86
f = Y.rbind.apply(Y, a);
89
return this._inject(AFTER, f, obj, sFn);
93
* Execute the supplied method after the specified function
95
* @param when {string} before or after
96
* @param fn {Function} the function to execute
97
* @param obj the object hosting the method to displace
98
* @param sFn {string} the name of the method to displace
99
* @param c The execution context for fn
100
* @return {string} handle for the subscription
104
_inject: function(when, fn, obj, sFn) {
107
var id = Y.stamp(obj), o, sid;
109
if (! this.objs[id]) {
110
// create a map entry for the obj if it doesn't exist
117
// create a map entry for the method if it doesn't exist
118
o[sFn] = new Y.Do.Method(obj, sFn);
120
// re-route the method to our wrapper
123
return o[sFn].exec.apply(o[sFn], arguments);
128
sid = id + Y.stamp(fn) + sFn;
130
// register the callback
131
o[sFn].register(sid, fn, when);
133
return new Y.EventHandle(o[sFn], sid);
138
* Detach a before or after subscription
140
* @param handle {string} the subscription handle
142
detach: function(handle) {
150
_unload: function(e, me) {
155
//////////////////////////////////////////////////////////////////////////
158
* Wrapper for a displaced method with aop enabled
161
* @param obj The object to operate on
162
* @param sFn The name of the method to displace
164
Y.Do.Method = function(obj, sFn) {
166
this.methodName = sFn;
167
this.method = obj[sFn];
173
* Register a aop subscriber
175
* @param sid {string} the subscriber id
176
* @param fn {Function} the function to execute
177
* @param when {string} when to execute the function
179
Y.Do.Method.prototype.register = function (sid, fn, when) {
181
this.after[sid] = fn;
183
this.before[sid] = fn;
188
* Unregister a aop subscriber
190
* @param sid {string} the subscriber id
191
* @param fn {Function} the function to execute
192
* @param when {string} when to execute the function
194
Y.Do.Method.prototype._delete = function (sid) {
195
delete this.before[sid];
196
delete this.after[sid];
200
* Execute the wrapped method
203
Y.Do.Method.prototype.exec = function () {
205
var args = Y.Array(arguments, 0, true),
213
if (bf.hasOwnProperty(i)) {
214
ret = bf[i].apply(this.obj, args);
216
switch (ret.constructor) {
233
ret = this.method.apply(this.obj, args);
236
// execute after methods.
238
if (af.hasOwnProperty(i)) {
239
newRet = af[i].apply(this.obj, args);
240
// Stop processing if a Halt object is returned
241
if (newRet && newRet.constructor == Y.Do.Halt) {
242
return newRet.retVal;
243
// Check for a new return value
244
} else if (newRet && newRet.constructor == Y.Do.AlterReturn) {
245
ret = newRet.newRetVal;
253
//////////////////////////////////////////////////////////////////////////
257
* Return an AlterArgs object when you want to change the arguments that
258
* were passed into the function. An example would be a service that scrubs
259
* out illegal characters prior to executing the core business logic.
260
* @class Do.AlterArgs
262
Y.Do.AlterArgs = function(msg, newArgs) {
264
this.newArgs = newArgs;
268
* Return an AlterReturn object when you want to change the result returned
269
* from the core method to the caller
270
* @class Do.AlterReturn
272
Y.Do.AlterReturn = function(msg, newRetVal) {
274
this.newRetVal = newRetVal;
278
* Return a Halt object when you want to terminate the execution
279
* of all subsequent subscribers as well as the wrapped method
280
* if it has not exectued yet.
283
Y.Do.Halt = function(msg, retVal) {
285
this.retVal = retVal;
289
* Return a Prevent object when you want to prevent the wrapped function
290
* from executing, but want the remaining listeners to execute
293
Y.Do.Prevent = function(msg) {
298
* Return an Error object when you want to terminate the execution
299
* of all subsequent method calls.
301
* @deprecated use Y.Do.Halt or Y.Do.Prevent
303
Y.Do.Error = Y.Do.Halt;
305
//////////////////////////////////////////////////////////////////////////
307
// Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
312
* Custom event engine, DOM event listener abstraction layer, synthetic DOM
314
* @module event-custom
315
* @submodule event-custom-base
319
* Return value from all subscribe operations
322
* @param evt {CustomEvent} the custom event
323
* @param sub {Subscriber} the subscriber
326
// var onsubscribeType = "_event:onsub",
354
Y.EventHandle = function(evt, sub) {
363
* The subscriber object
369
Y.EventHandle.prototype = {
372
if (Y.Lang.isArray(this.evt)) {
373
Y.Array.each(this.evt, function(h) {
380
* Detaches this subscriber
384
var evt = this.evt, detached = 0, i;
386
if (Y.Lang.isArray(evt)) {
387
for (i=0; i<evt.length; i++) {
388
detached += evt[i].detach();
391
evt._delete(this.sub);
401
* Monitor the event state for the subscribed event. The first parameter
402
* is what should be monitored, the rest are the normal parameters when
403
* subscribing to an event.
405
* @param what {string} what to monitor ('attach', 'detach', 'publish')
406
* @return {EventHandle} return value from the monitor event subscription
408
monitor: function(what) {
409
return this.evt.monitor.apply(this.evt, arguments);
414
* The CustomEvent class lets you define events for your application
415
* that can be subscribed to by one or more independent component.
417
* @param {String} type The type of event, which is passed to the callback
418
* when the event fires
419
* @param o configuration object
423
Y.CustomEvent = function(type, o) {
425
// if (arguments.length > 2) {
426
// this.log('CustomEvent context and silent are now in the config', 'warn', 'Event');
431
this.id = Y.stamp(this);
434
* The type of event, returned to subscribers when the event fires
441
* The context the the event will fire from by default. Defaults to the YUI
449
* Monitor when an event is attached or detached.
451
* @property monitored
454
// this.monitored = false;
456
this.logSystem = (type == YUI_LOG);
459
* If 0, this event does not broadcast. If 1, the YUI instance is notified
460
* every time this event fires. If 2, the YUI instance and the YUI global
461
* (if event is enabled on the global) are notified every time this event
463
* @property broadcast
466
// this.broadcast = 0;
469
* By default all custom events are logged in the debug build, set silent
470
* to true to disable debug outpu for this event.
474
this.silent = this.logSystem;
477
* Specifies whether this event should be queued when the host is actively
478
* processing an event. This will effect exectution order of the callbacks
479
* for the various events.
484
// this.queuable = false;
487
* The subscribers to this event
488
* @property subscribers
491
this.subscribers = {};
494
* 'After' subscribers
501
* This event has fired if true
507
// this.fired = false;
510
* An array containing the arguments the custom event
511
* was last fired with.
512
* @property firedWith
518
* This event should only fire one time if true, and if
519
* it has fired, any new subscribers should be notified
526
// this.fireOnce = false;
529
* fireOnce listeners will fire syncronously unless async
535
//this.async = false;
538
* Flag for stopPropagation that is modified during fire()
539
* 1 means to stop propagation to bubble targets. 2 means
540
* to also stop additional subscribers on this target.
547
* Flag for preventDefault that is modified during fire().
548
* if it is not 0, the default behavior for this event
549
* @property prevented
552
// this.prevented = 0;
555
* Specifies the host for this custom event. This is used
556
* to enable event bubbling
563
* The default function to execute after event listeners
564
* have fire, but only if the default action was not
566
* @property defaultFn
569
// this.defaultFn = null;
572
* The function to execute if a subscriber calls
573
* stopPropagation or stopImmediatePropagation
574
* @property stoppedFn
577
// this.stoppedFn = null;
580
* The function to execute if a subscriber calls
582
* @property preventedFn
585
// this.preventedFn = null;
588
* Specifies whether or not this event's default function
589
* can be cancelled by a subscriber by executing preventDefault()
590
* on the event facade
591
* @property preventable
595
this.preventable = true;
598
* Specifies whether or not a subscriber can stop the event propagation
599
* via stopPropagation(), stopImmediatePropagation(), or halt()
601
* Events can only bubble if emitFacade is true.
610
* Supports multiple options for listener signatures in order to
612
* @property signature
616
this.signature = YUI3_SIGNATURE;
621
// this.hasSubscribers = false;
623
// this.hasAfters = false;
626
* If set to true, the custom event will deliver an EventFacade object
627
* that is similar to a DOM event object.
628
* @property emitFacade
632
// this.emitFacade = false;
634
this.applyConfig(o, true);
636
// this.log("Creating " + this.type);
640
Y.CustomEvent.prototype = {
642
hasSubs: function(when) {
643
var s = this.subCount, a = this.afterCount, sib = this.sibling;
651
return (when == 'after') ? a : s;
658
* Monitor the event state for the subscribed event. The first parameter
659
* is what should be monitored, the rest are the normal parameters when
660
* subscribing to an event.
662
* @param what {string} what to monitor ('detach', 'attach', 'publish')
663
* @return {EventHandle} return value from the monitor event subscription
665
monitor: function(what) {
666
this.monitored = true;
667
var type = this.id + '|' + this.type + '_' + what,
668
args = Y.Array(arguments, 0, true);
670
return this.host.on.apply(this.host, args);
674
* Get all of the subscribers to this event and any sibling event
675
* @return {Array} first item is the on subscribers, second the after
677
getSubs: function() {
678
var s = Y.merge(this.subscribers), a = Y.merge(this.afters), sib = this.sibling;
681
Y.mix(s, sib.subscribers);
682
Y.mix(a, sib.afters);
689
* Apply configuration properties. Only applies the CONFIG whitelist
690
* @method applyConfig
691
* @param o hash of properties to apply
692
* @param force {boolean} if true, properties that exist on the event
693
* will be overwritten.
695
applyConfig: function(o, force) {
697
Y.mix(this, o, force, CONFIGS);
701
_on: function(fn, context, args, when) {
704
this.log("Invalid callback for CE: " + this.type);
707
var s = new Y.Subscriber(fn, context, args, when);
709
if (this.fireOnce && this.fired) {
711
setTimeout(Y.bind(this._notify, this, s, this.firedWith), 0);
713
this._notify(s, this.firedWith);
718
this.afters[s.id] = s;
721
this.subscribers[s.id] = s;
725
return new Y.EventHandle(this, s);
730
* Listen for this event
732
* @param {Function} fn The function to execute
733
* @return {EventHandle} Unsubscribe handle
736
subscribe: function(fn, context) {
737
var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
738
return this._on(fn, context, a, true);
742
* Listen for this event
744
* @param {Function} fn The function to execute
745
* @param context {object} optional execution context.
746
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
747
* when the event fires.
748
* @return {EventHandle} An object with a detach method to detch the handler(s)
750
on: function(fn, context) {
751
var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
753
this.host._monitor('attach', this.type, {
757
return this._on(fn, context, a, true);
761
* Listen for this event after the normal subscribers have been notified and
762
* the default behavior has been applied. If a normal subscriber prevents the
763
* default behavior, it also prevents after listeners from firing.
765
* @param {Function} fn The function to execute
766
* @param context {object} optional execution context.
767
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
768
* when the event fires.
769
* @return {EventHandle} handle Unsubscribe handle
771
after: function(fn, context) {
772
var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
773
return this._on(fn, context, a, AFTER);
779
* @param {Function} fn The subscribed function to remove, if not supplied
780
* all will be removed
781
* @param {Object} context The context object passed to subscribe.
782
* @return {int} returns the number of subscribers unsubscribed
784
detach: function(fn, context) {
785
// unsubscribe handle
786
if (fn && fn.detach) {
792
subs = Y.merge(this.subscribers, this.afters);
795
if (subs.hasOwnProperty(i)) {
797
if (s && (!fn || fn === s.fn)) {
809
* @method unsubscribe
810
* @param {Function} fn The subscribed function to remove, if not supplied
811
* all will be removed
812
* @param {Object} context The context object passed to subscribe.
813
* @return {int|undefined} returns the number of subscribers unsubscribed
814
* @deprecated use detach
816
unsubscribe: function() {
817
return this.detach.apply(this, arguments);
821
* Notify a single subscriber
823
* @param s {Subscriber} the subscriber
824
* @param args {Array} the arguments array to apply to the listener
827
_notify: function(s, args, ef) {
829
this.log(this.type + "->" + "sub: " + s.id);
833
ret = s.notify(args, this);
835
if (false === ret || this.stopped > 1) {
836
this.log(this.type + " cancelled by subscriber");
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) {
855
* Notifies the subscribers. The callback functions will be executed
856
* from the context specified when the event was created, and with the
857
* following parameters:
859
* <li>The type of event</li>
860
* <li>All of the arguments fire() was executed with as an array</li>
861
* <li>The custom object (if any) that was passed into the subscribe()
865
* @param {Object*} arguments an arbitrary set of parameters to pass to
867
* @return {boolean} false if one of the subscribers returned false,
872
if (this.fireOnce && this.fired) {
873
this.log('fireOnce event: ' + this.type + ' already fired');
877
var args = Y.Array(arguments, 0, true);
879
// this doesn't happen if the event isn't published
880
// this.host._monitor('fire', this.type, args);
883
this.firedWith = args;
885
if (this.emitFacade) {
886
return this.fireComplex(args);
888
return this.fireSimple(args);
893
fireSimple: function(args) {
896
if (this.hasSubs()) {
897
// this._procSubs(Y.merge(this.subscribers, this.afters), args);
898
var subs = this.getSubs();
899
this._procSubs(subs[0], args);
900
this._procSubs(subs[1], args);
902
this._broadcast(args);
903
return this.stopped ? false : true;
906
// Requires the event-custom-complex module for full funcitonality.
907
fireComplex: function(args) {
908
args[0] = args[0] || {};
909
return this.fireSimple(args);
912
_procSubs: function(subs, args, ef) {
915
if (subs.hasOwnProperty(i)) {
918
if (false === this._notify(s, args, ef)) {
921
if (this.stopped == 2) {
931
_broadcast: function(args) {
932
if (!this.stopped && this.broadcast) {
934
var a = Y.Array(args);
935
a.unshift(this.type);
937
if (this.host !== Y) {
941
if (this.broadcast == 2) {
942
Y.Global.fire.apply(Y.Global, a);
948
* Removes all listeners
949
* @method unsubscribeAll
950
* @return {int} The number of listeners unsubscribed
951
* @deprecated use detachAll
953
unsubscribeAll: function() {
954
return this.detachAll.apply(this, arguments);
958
* Removes all listeners
960
* @return {int} The number of listeners unsubscribed
962
detachAll: function() {
963
return this.detach();
968
* @param subscriber object
971
_delete: function(s) {
973
if (this.subscribers[s.id]) {
974
delete this.subscribers[s.id];
977
if (this.afters[s.id]) {
978
delete this.afters[s.id];
984
this.host._monitor('detach', this.type, {
997
/////////////////////////////////////////////////////////////////////
1000
* Stores the subscriber information to be used when the event fires.
1001
* @param {Function} fn The wrapped function to execute
1002
* @param {Object} context The value of the keyword 'this' in the listener
1003
* @param {Array} args* 0..n additional arguments to supply the listener
1008
Y.Subscriber = function(fn, context, args) {
1011
* The callback that will be execute when the event fires
1012
* This is wrapped by Y.rbind if obj was supplied.
1019
* Optional 'this' keyword for the listener
1023
this.context = context;
1026
* Unique subscriber id
1030
this.id = Y.stamp(this);
1033
* Additional arguments to propagate to the subscriber
1040
* Custom events for a given fire transaction.
1042
* @type {EventTarget}
1044
// this.events = null;
1047
* This listener only reacts to the event once
1050
// this.once = false;
1054
Y.Subscriber.prototype = {
1056
_notify: function(c, args, ce) {
1057
var a = this.args, ret;
1058
switch (ce.signature) {
1060
ret = this.fn.call(c, ce.type, args, c);
1063
ret = this.fn.call(c, args[0] || null, c);
1068
a = (a) ? args.concat(a) : args;
1069
ret = this.fn.apply(c, a);
1071
ret = this.fn.call(c);
1083
* Executes the subscriber.
1085
* @param args {Array} Arguments array for the subscriber
1086
* @param ce {CustomEvent} The custom event that sent the notification
1088
notify: function(args, ce) {
1089
var c = this.context,
1093
c = (ce.contextFn) ? ce.contextFn() : ce.context;
1096
// only catch errors if we will not re-throw them.
1097
if (Y.config.throwFail) {
1098
ret = this._notify(c, args, ce);
1101
ret = this._notify(c, args, ce);
1103
Y.error(this + ' failed: ' + e.message, e);
1111
* Returns true if the fn and obj match this objects properties.
1112
* Used by the unsubscribe method to match the right subscriber.
1115
* @param {Function} fn the function to execute
1116
* @param {Object} context optional 'this' keyword for the listener
1117
* @return {boolean} true if the supplied arguments match this
1118
* subscriber's signature.
1120
contains: function(fn, context) {
1122
return ((this.fn == fn) && this.context == context);
1124
return (this.fn == fn);
1131
* Custom event engine, DOM event listener abstraction layer, synthetic DOM
1133
* @module event-custom
1134
* @submodule event-custom-base
1139
* EventTarget provides the implementation for any object to
1140
* publish, subscribe and fire to custom events, and also
1141
* alows other EventTargets to target the object with events
1142
* sourced from the other object.
1143
* EventTarget is designed to be used with Y.augment to wrap
1144
* EventCustom in an interface that allows events to be listened to
1145
* and fired by name. This makes it possible for implementing code to
1146
* subscribe to an event that either has not been created yet, or will
1147
* not be created at all.
1148
* @class EventTarget
1149
* @param opts a configuration object
1150
* @config emitFacade {boolean} if true, all events will emit event
1151
* facade payloads by default (default false)
1152
* @config prefix {string} the prefix to apply to non-prefixed event names
1153
* @config chain {boolean} if true, on/after/detach return the host to allow
1154
* chaining, otherwise they return an EventHandle (default false)
1158
PREFIX_DELIMITER = ':',
1159
CATEGORY_DELIMITER = '|',
1160
AFTER_PREFIX = '~AFTER~',
1163
_wildType = Y.cached(function(type) {
1164
return type.replace(/(.*)(:)(.*)/, "*$2$3");
1168
* If the instance has a prefix attribute and the
1169
* event type is not prefixed, the instance prefix is
1170
* applied to the supplied type.
1174
_getType = Y.cached(function(type, pre) {
1176
if (!pre || !L.isString(type) || type.indexOf(PREFIX_DELIMITER) > -1) {
1180
return pre + PREFIX_DELIMITER + type;
1184
* Returns an array with the detach key (if provided),
1185
* and the prefixed event name from _getType
1186
* Y.on('detachcategory| menu:click', fn)
1187
* @method _parseType
1190
_parseType = Y.cached(function(type, pre) {
1192
var t = type, detachcategory, after, i;
1194
if (!L.isString(t)) {
1198
i = t.indexOf(AFTER_PREFIX);
1202
t = t.substr(AFTER_PREFIX.length);
1205
i = t.indexOf(CATEGORY_DELIMITER);
1208
detachcategory = t.substr(0, (i));
1215
// detach category, full type with instance prefix, is this an after listener, short type
1216
return [detachcategory, (pre) ? _getType(t, pre) : t, after, t];
1219
ET = function(opts) {
1222
var o = (L.isObject(opts)) ? opts : {};
1224
this._yuievt = this._yuievt || {
1234
chain: ('chain' in o) ? o.chain : Y.config.chain,
1239
context: o.context || this,
1241
emitFacade: o.emitFacade,
1242
fireOnce: o.fireOnce,
1243
queuable: o.queuable,
1244
monitored: o.monitored,
1245
broadcast: o.broadcast,
1246
defaultTargetOnly: o.defaultTargetOnly,
1247
bubbles: ('bubbles' in o) ? o.bubbles : true
1257
* Listen to a custom event hosted by this object one time.
1258
* This is the equivalent to <code>on</code> except the
1259
* listener is immediatelly detached when it is executed.
1261
* @param type {string} The type of the event
1262
* @param fn {Function} The callback
1263
* @param context {object} optional execution context.
1264
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
1265
* @return the event target or a detach handle per 'chain' config
1268
var handle = this.on.apply(this, arguments);
1269
handle.each(function(hand) {
1271
hand.sub.once = true;
1278
* Subscribe to a custom event hosted by this object
1280
* @param type {string} The type of the event
1281
* @param fn {Function} The callback
1282
* @param context {object} optional execution context.
1283
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
1284
* @return the event target or a detach handle per 'chain' config
1286
on: function(type, fn, context) {
1288
var parts = _parseType(type, this._yuievt.config.prefix), f, c, args, ret, ce,
1289
detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
1290
Node = Y.Node, n, domevent, isArr;
1292
// full name, args, detachcategory, after
1293
this._monitor('attach', parts[1], {
1299
if (L.isObject(type)) {
1301
if (L.isFunction(type)) {
1302
return Y.Do.before.apply(Y.Do, arguments);
1307
args = YArray(arguments, 0, true);
1310
if (L.isArray(type)) {
1314
after = type._after;
1317
Y.each(type, function(v, k) {
1319
if (L.isObject(v)) {
1320
f = v.fn || ((L.isFunction(v)) ? v : f);
1324
var nv = (after) ? AFTER_PREFIX : '';
1326
args[0] = nv + ((isArr) ? v : k);
1330
ret.push(this.on.apply(this, args));
1334
return (this._yuievt.chain) ? this : new Y.EventHandle(ret);
1338
detachcategory = parts[0];
1340
shorttype = parts[3];
1342
// extra redirection so we catch adaptor events too. take a look at this.
1343
if (Node && (this instanceof Node) && (shorttype in Node.DOM_EVENTS)) {
1344
args = YArray(arguments, 0, true);
1345
args.splice(2, 0, Node.getDOMNode(this));
1346
return Y.on.apply(Y, args);
1351
if (this instanceof YUI) {
1353
adapt = Y.Env.evt.plugins[type];
1354
args = YArray(arguments, 0, true);
1355
args[0] = shorttype;
1360
if (n instanceof Y.NodeList) {
1361
n = Y.NodeList.getDOMNodes(n);
1362
} else if (n instanceof Node) {
1363
n = Node.getDOMNode(n);
1366
domevent = (shorttype in Node.DOM_EVENTS);
1368
// Captures both DOM events and event plugins.
1374
// check for the existance of an event adaptor
1376
handle = adapt.on.apply(Y, args);
1377
} else if ((!type) || domevent) {
1378
handle = Y.Event._attach(args);
1384
ce = this._yuievt.events[type] || this.publish(type);
1385
handle = ce._on(fn, context, (arguments.length > 3) ? YArray(arguments, 3, true) : null, (after) ? 'after' : true);
1388
if (detachcategory) {
1389
store[detachcategory] = store[detachcategory] || {};
1390
store[detachcategory][type] = store[detachcategory][type] || [];
1391
store[detachcategory][type].push(handle);
1394
return (this._yuievt.chain) ? this : handle;
1399
* subscribe to an event
1401
* @deprecated use on
1403
subscribe: function() {
1404
return this.on.apply(this, arguments);
1408
* Detach one or more listeners the from the specified event
1410
* @param type {string|Object} Either the handle to the subscriber or the
1411
* type of event. If the type
1412
* is not specified, it will attempt to remove
1413
* the listener from all hosted events.
1414
* @param fn {Function} The subscribed function to unsubscribe, if not
1415
* supplied, all subscribers will be removed.
1416
* @param context {Object} The custom object passed to subscribe. This is
1417
* optional, but if supplied will be used to
1418
* disambiguate multiple listeners that are the same
1419
* (e.g., you subscribe many object using a function
1420
* that lives on the prototype)
1421
* @return {EventTarget} the host
1423
detach: function(type, fn, context) {
1424
var evts = this._yuievt.events, i,
1425
Node = Y.Node, isNode = Node && (this instanceof Node);
1427
// detachAll disabled on the Y instance.
1428
if (!type && (this !== Y)) {
1430
if (evts.hasOwnProperty(i)) {
1431
evts[i].detach(fn, context);
1435
Y.Event.purgeElement(Node.getDOMNode(this));
1441
var parts = _parseType(type, this._yuievt.config.prefix),
1442
detachcategory = L.isArray(parts) ? parts[0] : null,
1443
shorttype = (parts) ? parts[3] : null,
1444
adapt, store = Y.Env.evt.handles, detachhost, cat, args,
1447
keyDetacher = function(lcat, ltype, host) {
1448
var handles = lcat[ltype], ce, i;
1450
for (i = handles.length - 1; i >= 0; --i) {
1451
ce = handles[i].evt;
1452
if (ce.host === host || ce.el === host) {
1453
handles[i].detach();
1459
if (detachcategory) {
1461
cat = store[detachcategory];
1463
detachhost = (isNode) ? Y.Node.getDOMNode(this) : this;
1467
keyDetacher(cat, type, detachhost);
1470
if (cat.hasOwnProperty(i)) {
1471
keyDetacher(cat, i, detachhost);
1479
// If this is an event handle, use it to detach
1480
} else if (L.isObject(type) && type.detach) {
1483
// extra redirection so we catch adaptor events too. take a look at this.
1484
} else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
1485
args = YArray(arguments, 0, true);
1486
args[2] = Node.getDOMNode(this);
1487
Y.detach.apply(Y, args);
1491
adapt = Y.Env.evt.plugins[shorttype];
1493
// The YUI instance handles DOM events and adaptors
1494
if (this instanceof YUI) {
1495
args = YArray(arguments, 0, true);
1496
// use the adaptor specific detach code if
1497
if (adapt && adapt.detach) {
1498
adapt.detach.apply(Y, args);
1501
} else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
1503
Y.Event.detach.apply(Y.Event, args);
1509
ce = evts[parts[1]];
1511
ce.detach(fn, context);
1519
* @method unsubscribe
1520
* @deprecated use detach
1522
unsubscribe: function() {
1523
return this.detach.apply(this, arguments);
1527
* Removes all listeners from the specified event. If the event type
1528
* is not specified, all listeners from all hosted custom events will
1531
* @param type {string} The type, or name of the event
1533
detachAll: function(type) {
1534
return this.detach(type);
1538
* Removes all listeners from the specified event. If the event type
1539
* is not specified, all listeners from all hosted custom events will
1541
* @method unsubscribeAll
1542
* @param type {string} The type, or name of the event
1543
* @deprecated use detachAll
1545
unsubscribeAll: function() {
1546
return this.detachAll.apply(this, arguments);
1550
* Creates a new custom event of the specified type. If a custom event
1551
* by that name already exists, it will not be re-created. In either
1552
* case the custom event is returned.
1556
* @param type {string} the type, or name of the event
1557
* @param opts {object} optional config params. Valid properties are:
1561
* 'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
1564
* 'bubbles': whether or not this event bubbles (true)
1565
* Events can only bubble if emitFacade is true.
1568
* 'context': the default execution context for the listeners (this)
1571
* 'defaultFn': the default function to execute when this event fires if preventDefault was not called
1574
* 'emitFacade': whether or not this event emits a facade (false)
1577
* 'prefix': the prefix for this targets events, e.g., 'menu' in 'menu:click'
1580
* 'fireOnce': if an event is configured to fire once, new subscribers after
1581
* the fire will be notified immediately.
1584
* 'async': fireOnce event listeners will fire synchronously if the event has already
1585
* fired unless async is true.
1588
* 'preventable': whether or not preventDefault() has an effect (true)
1591
* 'preventedFn': a function that is executed when preventDefault is called
1594
* 'queuable': whether or not this event can be queued during bubbling (false)
1597
* 'silent': if silent is true, debug messages are not provided for this event.
1600
* 'stoppedFn': a function that is executed when stopPropagation is called
1604
* 'monitored': specifies whether or not this event should send notifications about
1605
* when the event has been attached, detached, or published.
1608
* 'type': the event type (valid option if not provided as the first parameter to publish)
1612
* @return {CustomEvent} the custom event
1615
publish: function(type, opts) {
1616
var events, ce, ret, defaults,
1617
edata = this._yuievt,
1618
pre = edata.config.prefix;
1620
type = (pre) ? _getType(type, pre) : type;
1622
this._monitor('publish', type, {
1626
if (L.isObject(type)) {
1628
Y.each(type, function(v, k) {
1629
ret[k] = this.publish(k, v || opts);
1635
events = edata.events;
1639
// ce.log("publish applying new config to published event: '"+type+"' exists", 'info', 'event');
1641
ce.applyConfig(opts, true);
1645
defaults = edata.defaults;
1648
ce = new Y.CustomEvent(type,
1649
(opts) ? Y.merge(defaults, opts) : defaults);
1653
// make sure we turn the broadcast flag off if this
1654
// event was published as a result of bubbling
1655
// if (opts instanceof Y.CustomEvent) {
1656
// events[type].broadcast = false;
1659
return events[type];
1663
* This is the entry point for the event monitoring system.
1664
* You can monitor 'attach', 'detach', 'fire', and 'publish'.
1665
* When configured, these events generate an event. click ->
1666
* click_attach, click_detach, click_publish -- these can
1667
* be subscribed to like other events to monitor the event
1668
* system. Inividual published events can have monitoring
1669
* turned on or off (publish can't be turned off before it
1670
* it published) by setting the events 'monitor' config.
1674
_monitor: function(what, type, o) {
1675
var monitorevt, ce = this.getEvent(type);
1676
if ((this._yuievt.config.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) {
1677
monitorevt = type + '_' + what;
1679
this.fire.call(this, monitorevt, o);
1684
* Fire a custom event by name. The callback functions will be executed
1685
* from the context specified when the event was created, and with the
1686
* following parameters.
1688
* If the custom event object hasn't been created, then the event hasn't
1689
* been published and it has no subscribers. For performance sake, we
1690
* immediate exit in this case. This means the event won't bubble, so
1691
* if the intention is that a bubble target be notified, the event must
1692
* be published on this object first.
1694
* The first argument is the event type, and any additional arguments are
1695
* passed to the listeners as parameters. If the first of these is an
1696
* object literal, and the event is configured to emit an event facade,
1697
* that object is mixed into the event facade and the facade is provided
1698
* in place of the original object.
1701
* @param type {String|Object} The type of the event, or an object that contains
1702
* a 'type' property.
1703
* @param arguments {Object*} an arbitrary set of parameters to pass to
1704
* the handler. If the first of these is an object literal and the event is
1705
* configured to emit an event facade, the event facade will replace that
1706
* parameter after the properties the object literal contains are copied to
1708
* @return {EventTarget} the event host
1711
fire: function(type) {
1713
var typeIncluded = L.isString(type),
1714
t = (typeIncluded) ? type : (type && type.type),
1715
ce, ret, pre = this._yuievt.config.prefix, ce2,
1716
args = (typeIncluded) ? YArray(arguments, 1, true) : arguments;
1718
t = (pre) ? _getType(t, pre) : t;
1720
this._monitor('fire', t, {
1724
ce = this.getEvent(t, true);
1725
ce2 = this.getSibling(t, ce);
1728
ce = this.publish(t);
1731
// this event has not been published or subscribed to
1733
if (this._yuievt.hasTargets) {
1734
return this.bubble({ type: t }, args, this);
1737
// otherwise there is nothing to be done
1741
ret = ce.fire.apply(ce, args);
1744
return (this._yuievt.chain) ? this : ret;
1747
getSibling: function(type, ce) {
1749
// delegate to *:type events if there are subscribers
1750
if (type.indexOf(PREFIX_DELIMITER) > -1) {
1751
type = _wildType(type);
1752
// console.log(type);
1753
ce2 = this.getEvent(type, true);
1755
// console.log("GOT ONE: " + type);
1756
ce2.applyConfig(ce);
1757
ce2.bubbles = false;
1759
// ret = ce2.fire.apply(ce2, a);
1767
* Returns the custom event of the provided type has been created, a
1768
* falsy value otherwise
1770
* @param type {string} the type, or name of the event
1771
* @param prefixed {string} if true, the type is prefixed already
1772
* @return {CustomEvent} the custom event or null
1774
getEvent: function(type, prefixed) {
1777
pre = this._yuievt.config.prefix;
1778
type = (pre) ? _getType(type, pre) : type;
1780
e = this._yuievt.events;
1781
return e[type] || null;
1785
* Subscribe to a custom event hosted by this object. The
1786
* supplied callback will execute after any listeners add
1787
* via the subscribe method, and after the default function,
1788
* if configured for the event, has executed.
1790
* @param type {string} The type of the event
1791
* @param fn {Function} The callback
1792
* @param context {object} optional execution context.
1793
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
1794
* @return the event target or a detach handle per 'chain' config
1796
after: function(type, fn) {
1798
var a = YArray(arguments, 0, true);
1800
switch (L.type(type)) {
1802
return Y.Do.after.apply(Y.Do, arguments);
1804
// YArray.each(a[0], function(v) {
1805
// v = AFTER_PREFIX + v;
1812
a[0] = AFTER_PREFIX + type;
1815
return this.on.apply(this, a);
1820
* Executes the callback before a DOM event, custom event
1821
* or method. If the first argument is a function, it
1822
* is assumed the target is a method. For DOM and custom
1823
* events, this is an alias for Y.on.
1825
* For DOM and custom events:
1826
* type, callback, context, 0-n arguments
1829
* callback, object (method host), methodName, context, 0-n arguments
1832
* @return detach handle
1834
before: function() {
1835
return this.on.apply(this, arguments);
1842
// make Y an event target
1843
Y.mix(Y, ET.prototype, false, false, {
1849
YUI.Env.globalEvents = YUI.Env.globalEvents || new ET();
1852
* Hosts YUI page level events. This is where events bubble to
1853
* when the broadcast config is set to 2. This property is
1854
* only available if the custom event module is loaded.
1859
Y.Global = YUI.Env.globalEvents;
1861
// @TODO implement a global namespace function on Y.Global?
1866
* <code>YUI</code>'s <code>on</code> method is a unified interface for subscribing to
1867
* most events exposed by YUI. This includes custom events, DOM events, and
1868
* function events. <code>detach</code> is also provided to remove listeners
1869
* serviced by this function.
1871
* The signature that <code>on</code> accepts varies depending on the type
1872
* of event being consumed. Refer to the specific methods that will
1873
* service a specific request for additional information about subscribing
1874
* to that type of event.
1877
* <li>Custom events. These events are defined by various
1878
* modules in the library. This type of event is delegated to
1879
* <code>EventTarget</code>'s <code>on</code> method.
1881
* <li>The type of the event</li>
1882
* <li>The callback to execute</li>
1883
* <li>An optional context object</li>
1884
* <li>0..n additional arguments to supply the callback.</li>
1887
* <code>Y.on('drag:drophit', function() { // start work });</code>
1889
* <li>DOM events. These are moments reported by the browser related
1890
* to browser functionality and user interaction.
1891
* This type of event is delegated to <code>Event</code>'s
1892
* <code>attach</code> method.
1894
* <li>The type of the event</li>
1895
* <li>The callback to execute</li>
1896
* <li>The specification for the Node(s) to attach the listener
1897
* to. This can be a selector, collections, or Node/Element
1899
* <li>An optional context object</li>
1900
* <li>0..n additional arguments to supply the callback.</li>
1903
* <code>Y.on('click', function(e) { // something was clicked }, '#someelement');</code>
1905
* <li>Function events. These events can be used to react before or after a
1906
* function is executed. This type of event is delegated to <code>Event.Do</code>'s
1907
* <code>before</code> method.
1909
* <li>The callback to execute</li>
1910
* <li>The object that has the function that will be listened for.</li>
1911
* <li>The name of the function to listen for.</li>
1912
* <li>An optional context object</li>
1913
* <li>0..n additional arguments to supply the callback.</li>
1915
* Example <code>Y.on(function(arg1, arg2, etc) { // obj.methodname was executed }, obj 'methodname');</code>
1919
* <code>on</code> corresponds to the moment before any default behavior of
1920
* the event. <code>after</code> works the same way, but these listeners
1921
* execute after the event's default behavior. <code>before</code> is an
1922
* alias for <code>on</code>.
1925
* @param type event type (this parameter does not apply for function events)
1926
* @param fn the callback
1927
* @param context optionally change the value of 'this' in the callback
1928
* @param args* 0..n additional arguments to pass to the callback.
1929
* @return the event target or a detach handle per 'chain' config
1934
* Listen for an event one time. Equivalent to <code>on</code>, except that
1935
* the listener is immediately detached when executed.
1938
* @param type event type (this parameter does not apply for function events)
1939
* @param fn the callback
1940
* @param context optionally change the value of 'this' in the callback
1941
* @param args* 0..n additional arguments to pass to the callback.
1942
* @return the event target or a detach handle per 'chain' config
1947
* after() is a unified interface for subscribing to
1948
* most events exposed by YUI. This includes custom events,
1949
* DOM events, and AOP events. This works the same way as
1950
* the on() function, only it operates after any default
1951
* behavior for the event has executed. @see <code>on</code> for more
1954
* @param type event type (this parameter does not apply for function events)
1955
* @param fn the callback
1956
* @param context optionally change the value of 'this' in the callback
1957
* @param args* 0..n additional arguments to pass to the callback.
1958
* @return the event target or a detach handle per 'chain' config
1963
}, '3.2.0' ,{requires:['oop']});