event-custom-base.js revision e806a570fd5dbd8a6ef84c8e580763818b165618
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinYUI.add('event-custom-base', function(Y) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Custom event engine, DOM event listener abstraction layer, synthetic DOM
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * events.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @module event-custom
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.Env.evt = {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin handles: {},
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin plugins: {}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Custom event engine, DOM event listener abstraction layer, synthetic DOM
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * events.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @module event-custom
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @submodule event-custom-base
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin(function() {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Allows for the insertion of methods that are executed before or after
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * a specified method
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @class Do
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @static
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvar BEFORE = 0,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin AFTER = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.Do = {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Cache of objects touched by the utility
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @property objs
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @static
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin objs: {},
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Execute the supplied method before the specified function
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @method before
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param fn {Function} the function to execute
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param obj the object hosting the method to displace
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param sFn {string} the name of the method to displace
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param c The execution context for fn
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * when the event fires.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @return {string} handle for the subscription
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @static
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin before: function(fn, obj, sFn, c) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin var f = fn, a;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (c) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin a = [fn, c].concat(Y.Array(arguments, 4, true));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin f = Y.rbind.apply(Y, a);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return this._inject(BEFORE, f, obj, sFn);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin },
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Execute the supplied method after the specified function
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @method after
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param fn {Function} the function to execute
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param obj the object hosting the method to displace
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param sFn {string} the name of the method to displace
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param c The execution context for fn
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @return {string} handle for the subscription
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @static
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin after: function(fn, obj, sFn, c) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin var f = fn, a;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (c) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin a = [fn, c].concat(Y.Array(arguments, 4, true));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin f = Y.rbind.apply(Y, a);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return this._inject(AFTER, f, obj, sFn);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin },
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Execute the supplied method after the specified function
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @method _inject
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param when {string} before or after
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param fn {Function} the function to execute
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param obj the object hosting the method to displace
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param sFn {string} the name of the method to displace
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param c The execution context for fn
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @return {string} handle for the subscription
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @private
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @static
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin _inject: function(when, fn, obj, sFn) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // object id
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin var id = Y.stamp(obj), o, sid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (! this.objs[id]) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // create a map entry for the obj if it doesn't exist
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.objs[id] = {};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin o = this.objs[id];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (! o[sFn]) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // create a map entry for the method if it doesn't exist
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin o[sFn] = new Y.Do.Method(obj, sFn);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // re-route the method to our wrapper
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin obj[sFn] =
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin function() {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return o[sFn].exec.apply(o[sFn], arguments);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin };
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // subscriber id
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sid = id + Y.stamp(fn) + sFn;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // register the callback
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin o[sFn].register(sid, fn, when);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return new Y.EventHandle(o[sFn], sid);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin },
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Detach a before or after subscription
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @method detach
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param handle {string} the subscription handle
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin detach: function(handle) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (handle.detach) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin handle.detach();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin },
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin _unload: function(e, me) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin//////////////////////////////////////////////////////////////////////////
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Wrapper for a displaced method with aop enabled
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @class Do.Method
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @constructor
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param obj The object to operate on
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param sFn The name of the method to displace
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.Do.Method = function(obj, sFn) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.obj = obj;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.methodName = sFn;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.method = obj[sFn];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.before = {};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.after = {};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Register a aop subscriber
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @method register
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param sid {string} the subscriber id
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param fn {Function} the function to execute
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param when {string} when to execute the function
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.Do.Method.prototype.register = function (sid, fn, when) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (when) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.after[sid] = fn;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.before[sid] = fn;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Unregister a aop subscriber
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @method delete
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param sid {string} the subscriber id
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param fn {Function} the function to execute
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param when {string} when to execute the function
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.Do.Method.prototype._delete = function (sid) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin delete this.before[sid];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin delete this.after[sid];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Execute the wrapped method
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @method exec
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.Do.Method.prototype.exec = function () {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin var args = Y.Array(arguments, 0, true),
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin i, ret, newRet,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bf = this.before,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin af = this.after,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin prevented = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // execute before
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (i in bf) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (bf.hasOwnProperty(i)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = bf[i].apply(this.obj, args);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (ret) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (ret.constructor) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case Y.Do.Halt:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return ret.retVal;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case Y.Do.AlterArgs:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin args = ret.newArgs;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case Y.Do.Prevent:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin prevented = true;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin default:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // execute method
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!prevented) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = this.method.apply(this.obj, args);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // execute after methods.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (i in af) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (af.hasOwnProperty(i)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin newRet = af[i].apply(this.obj, args);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // Stop processing if a Halt object is returned
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (newRet && newRet.constructor == Y.Do.Halt) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return newRet.retVal;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // Check for a new return value
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else if (newRet && newRet.constructor == Y.Do.AlterReturn) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = newRet.newRetVal;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return ret;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin//////////////////////////////////////////////////////////////////////////
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Return an AlterArgs object when you want to change the arguments that
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * were passed into the function. An example would be a service that scrubs
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * out illegal characters prior to executing the core business logic.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @class Do.AlterArgs
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.Do.AlterArgs = function(msg, newArgs) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.msg = msg;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.newArgs = newArgs;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Return an AlterReturn object when you want to change the result returned
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * from the core method to the caller
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @class Do.AlterReturn
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.Do.AlterReturn = function(msg, newRetVal) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.msg = msg;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.newRetVal = newRetVal;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Return a Halt object when you want to terminate the execution
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * of all subsequent subscribers as well as the wrapped method
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * if it has not exectued yet.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @class Do.Halt
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.Do.Halt = function(msg, retVal) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.msg = msg;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.retVal = retVal;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Return a Prevent object when you want to prevent the wrapped function
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * from executing, but want the remaining listeners to execute
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @class Do.Prevent
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.Do.Prevent = function(msg) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.msg = msg;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Return an Error object when you want to terminate the execution
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * of all subsequent method calls.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @class Do.Error
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @deprecated use Y.Do.Halt or Y.Do.Prevent
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.Do.Error = Y.Do.Halt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin//////////////////////////////////////////////////////////////////////////
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin// Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin})();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Custom event engine, DOM event listener abstraction layer, synthetic DOM
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * events.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @module event-custom
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @submodule event-custom-base
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Return value from all subscribe operations
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @class EventHandle
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @constructor
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param evt {CustomEvent} the custom event
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param sub {Subscriber} the subscriber
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin// var onsubscribeType = "_event:onsub",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvar AFTER = 'after',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin CONFIGS = [
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'broadcast',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'monitored',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'bubbles',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'context',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'contextFn',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'currentTarget',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'defaultFn',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'defaultTargetOnly',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'details',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'emitFacade',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'fireOnce',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'async',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'host',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'preventable',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'preventedFn',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'queuable',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'silent',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'stoppedFn',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'target',
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 'type'
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ],
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin YUI3_SIGNATURE = 9,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin YUI_LOG = 'yui:log';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.EventHandle = function(evt, sub) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The custom event
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @type CustomEvent
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.evt = evt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The subscriber object
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @type Subscriber
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.sub = sub;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.EventHandle.prototype = {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Detaches this subscriber
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @method detach
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin detach: function() {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin var evt = this.evt, detached = 0, i;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (evt) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (Y.Lang.isArray(evt)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (i=0; i<evt.length; i++) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin detached += evt[i].detach();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin evt._delete(this.sub);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin detached = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return detached;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin },
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Monitor the event state for the subscribed event. The first parameter
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * is what should be monitored, the rest are the normal parameters when
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * subscribing to an event.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @method monitor
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param what {string} what to monitor ('attach', 'detach', 'publish')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @return {EventHandle} return value from the monitor event subscription
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin monitor: function(what) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return this.evt.monitor.apply(this.evt, arguments);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The CustomEvent class lets you define events for your application
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * that can be subscribed to by one or more independent component.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param {String} type The type of event, which is passed to the callback
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * when the event fires
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @param o configuration object
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @class CustomEvent
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @constructor
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinY.CustomEvent = function(type, o) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // if (arguments.length > 2) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin// this.log('CustomEvent context and silent are now in the config', 'warn', 'Event');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin o = o || {};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.id = Y.stamp(this);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The type of event, returned to subscribers when the event fires
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @property type
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @type string
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.type = type;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The context the the event will fire from by default. Defaults to the YUI
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * instance.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @property context
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @type object
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.context = Y;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Monitor when an event is attached or detached.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @property monitored
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @type boolean
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // this.monitored = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin this.logSystem = (type == YUI_LOG);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If 0, this event does not broadcast. If 1, the YUI instance is notified
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * every time this event fires. If 2, the YUI instance and the YUI global
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * (if event is enabled on the global) are notified every time this event
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * fires.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @property broadcast
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @type int
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin // this.broadcast = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * By default all custom events are logged in the debug build, set silent
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * to true to disable debug outpu for this event.
* @property silent
* @type boolean
*/
this.silent = this.logSystem;
/**
* Specifies whether this event should be queued when the host is actively
* processing an event. This will effect exectution order of the callbacks
* for the various events.
* @property queuable
* @type boolean
* @default false
*/
// this.queuable = false;
/**
* The subscribers to this event
* @property subscribers
* @type Subscriber{}
*/
this.subscribers = {};
/**
* 'After' subscribers
* @property afters
* @type Subscriber{}
*/
this.afters = {};
/**
* This event has fired if true
*
* @property fired
* @type boolean
* @default false;
*/
// this.fired = false;
/**
* An array containing the arguments the custom event
* was last fired with.
* @property firedWith
* @type Array
*/
// this.firedWith;
/**
* This event should only fire one time if true, and if
* it has fired, any new subscribers should be notified
* immediately.
*
* @property fireOnce
* @type boolean
* @default false;
*/
// this.fireOnce = false;
/**
* fireOnce listeners will fire syncronously unless async
* is set to true
* @property async
* @type boolean
* @default false
*/
//this.async = false;
/**
* Flag for stopPropagation that is modified during fire()
* 1 means to stop propagation to bubble targets. 2 means
* to also stop additional subscribers on this target.
* @property stopped
* @type int
*/
// this.stopped = 0;
/**
* Flag for preventDefault that is modified during fire().
* if it is not 0, the default behavior for this event
* @property prevented
* @type int
*/
// this.prevented = 0;
/**
* Specifies the host for this custom event. This is used
* to enable event bubbling
* @property host
* @type EventTarget
*/
// this.host = null;
/**
* The default function to execute after event listeners
* have fire, but only if the default action was not
* prevented.
* @property defaultFn
* @type Function
*/
// this.defaultFn = null;
/**
* The function to execute if a subscriber calls
* stopPropagation or stopImmediatePropagation
* @property stoppedFn
* @type Function
*/
// this.stoppedFn = null;
/**
* The function to execute if a subscriber calls
* preventDefault
* @property preventedFn
* @type Function
*/
// this.preventedFn = null;
/**
* Specifies whether or not this event's default function
* can be cancelled by a subscriber by executing preventDefault()
* on the event facade
* @property preventable
* @type boolean
* @default true
*/
this.preventable = true;
/**
* Specifies whether or not a subscriber can stop the event propagation
* via stopPropagation(), stopImmediatePropagation(), or halt()
*
* Events can only bubble if emitFacade is true.
*
* @property bubbles
* @type boolean
* @default true
*/
this.bubbles = true;
/**
* Supports multiple options for listener signatures in order to
* port YUI 2 apps.
* @property signature
* @type int
* @default 9
*/
this.signature = YUI3_SIGNATURE;
this.subCount = 0;
this.afterCount = 0;
// this.hasSubscribers = false;
// this.hasAfters = false;
/**
* If set to true, the custom event will deliver an EventFacade object
* that is similar to a DOM event object.
* @property emitFacade
* @type boolean
* @default false
*/
// this.emitFacade = false;
this.applyConfig(o, true);
// this.log("Creating " + this.type);
};
Y.CustomEvent.prototype = {
hasSubs: function(when) {
var s = this.subCount, a = this.afterCount, sib = this.sibling;
if (sib) {
s += sib.subCount;
a += sib.afterCount;
}
if (when) {
return (when == 'after') ? a : s;
}
return (s + a);
},
/**
* Monitor the event state for the subscribed event. The first parameter
* is what should be monitored, the rest are the normal parameters when
* subscribing to an event.
* @method monitor
* @param what {string} what to monitor ('detach', 'attach', 'publish')
* @return {EventHandle} return value from the monitor event subscription
*/
monitor: function(what) {
this.monitored = true;
var type = this.id + '|' + this.type + '_' + what,
args = Y.Array(arguments, 0, true);
args[0] = type;
return this.host.on.apply(this.host, args);
},
/**
* Get all of the subscribers to this event and any sibling event
* @return {Array} first item is the on subscribers, second the after
*/
getSubs: function() {
var s = Y.merge(this.subscribers), a = Y.merge(this.afters), sib = this.sibling;
if (sib) {
Y.mix(s, sib.subscribers);
Y.mix(a, sib.afters);
}
return [s, a];
},
/**
* Apply configuration properties. Only applies the CONFIG whitelist
* @method applyConfig
* @param o hash of properties to apply
* @param force {boolean} if true, properties that exist on the event
* will be overwritten.
*/
applyConfig: function(o, force) {
if (o) {
Y.mix(this, o, force, CONFIGS);
}
},
_on: function(fn, context, args, when) {
if (!fn) {
this.log("Invalid callback for CE: " + this.type);
}
var s = new Y.Subscriber(fn, context, args, when);
if (this.fireOnce && this.fired) {
if (this.async) {
setTimeout(Y.bind(this._notify, this, s, this.firedWith), 0);
} else {
this._notify(s, this.firedWith);
}
}
if (when == AFTER) {
this.afters[s.id] = s;
this.afterCount++;
} else {
this.subscribers[s.id] = s;
this.subCount++;
}
return new Y.EventHandle(this, s);
},
/**
* Listen for this event
* @method subscribe
* @param {Function} fn The function to execute
* @return {EventHandle} Unsubscribe handle
* @deprecated use on
*/
subscribe: function(fn, context) {
var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
return this._on(fn, context, a, true);
},
/**
* Listen for this event
* @method on
* @param {Function} fn The function to execute
* @param context {object} optional execution context.
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
* when the event fires.
* @return {EventHandle} An object with a detach method to detch the handler(s)
*/
on: function(fn, context) {
var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
if (this.host) {
this.host._monitor('attach', this.type, {
args: arguments
});
}
return this._on(fn, context, a, true);
},
/**
* Listen for this event after the normal subscribers have been notified and
* the default behavior has been applied. If a normal subscriber prevents the
* default behavior, it also prevents after listeners from firing.
* @method after
* @param {Function} fn The function to execute
* @param context {object} optional execution context.
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
* when the event fires.
* @return {EventHandle} handle Unsubscribe handle
*/
after: function(fn, context) {
var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
return this._on(fn, context, a, AFTER);
},
/**
* Detach listeners.
* @method detach
* @param {Function} fn The subscribed function to remove, if not supplied
* all will be removed
* @param {Object} context The context object passed to subscribe.
* @return {int} returns the number of subscribers unsubscribed
*/
detach: function(fn, context) {
// unsubscribe handle
if (fn && fn.detach) {
return fn.detach();
}
var found = 0, subs = this.subscribers, i, s;
for (i in subs) {
if (subs.hasOwnProperty(i)) {
s = subs[i];
if (s && (!fn || fn === s.fn)) {
this._delete(s);
found++;
}
}
}
return found;
},
/**
* Detach listeners.
* @method unsubscribe
* @param {Function} fn The subscribed function to remove, if not supplied
* all will be removed
* @param {Object} context The context object passed to subscribe.
* @return {int|undefined} returns the number of subscribers unsubscribed
* @deprecated use detach
*/
unsubscribe: function() {
return this.detach.apply(this, arguments);
},
/**
* Notify a single subscriber
* @method _notify
* @param s {Subscriber} the subscriber
* @param args {Array} the arguments array to apply to the listener
* @private
*/
_notify: function(s, args, ef) {
this.log(this.type + "->" + "sub: " + s.id);
var ret;
ret = s.notify(args, this);
if (false === ret || this.stopped > 1) {
this.log(this.type + " cancelled by subscriber");
return false;
}
return true;
},
/**
* Logger abstraction to centralize the application of the silent flag
* @method log
* @param msg {string} message to log
* @param cat {string} log category
*/
log: function(msg, cat) {
if (!this.silent) {
}
},
/**
* Notifies the subscribers. The callback functions will be executed
* from the context specified when the event was created, and with the
* following parameters:
* <ul>
* <li>The type of event</li>
* <li>All of the arguments fire() was executed with as an array</li>
* <li>The custom object (if any) that was passed into the subscribe()
* method</li>
* </ul>
* @method fire
* @param {Object*} arguments an arbitrary set of parameters to pass to
* the handler.
* @return {boolean} false if one of the subscribers returned false,
* true otherwise
*
*/
fire: function() {
if (this.fireOnce && this.fired) {
this.log('fireOnce event: ' + this.type + ' already fired');
return true;
} else {
var args = Y.Array(arguments, 0, true);
// this doesn't happen if the event isn't published
// this.host._monitor('fire', this.type, args);
this.fired = true;
this.firedWith = args;
if (this.emitFacade) {
return this.fireComplex(args);
} else {
return this.fireSimple(args);
}
}
},
fireSimple: function(args) {
this.stopped = 0;
this.prevented = 0;
if (this.hasSubs()) {
// this._procSubs(Y.merge(this.subscribers, this.afters), args);
var subs = this.getSubs();
this._procSubs(subs[0], args);
this._procSubs(subs[1], args);
}
this._broadcast(args);
return this.stopped ? false : true;
},
// Requires the event-custom-complex module for full funcitonality.
fireComplex: function(args) {
args[0] = args[0] || {};
return this.fireSimple(args);
},
_procSubs: function(subs, args, ef) {
var s, i;
for (i in subs) {
if (subs.hasOwnProperty(i)) {
s = subs[i];
if (s && s.fn) {
if (false === this._notify(s, args, ef)) {
this.stopped = 2;
}
if (this.stopped == 2) {
return false;
}
}
}
}
return true;
},
_broadcast: function(args) {
if (!this.stopped && this.broadcast) {
var a = Y.Array(args);
a.unshift(this.type);
if (this.host !== Y) {
Y.fire.apply(Y, a);
}
if (this.broadcast == 2) {
Y.Global.fire.apply(Y.Global, a);
}
}
},
/**
* Removes all listeners
* @method unsubscribeAll
* @return {int} The number of listeners unsubscribed
* @deprecated use detachAll
*/
unsubscribeAll: function() {
return this.detachAll.apply(this, arguments);
},
/**
* Removes all listeners
* @method detachAll
* @return {int} The number of listeners unsubscribed
*/
detachAll: function() {
return this.detach();
},
/**
* @method _delete
* @param subscriber object
* @private
*/
_delete: function(s) {
if (s) {
if (this.subscribers[s.id]) {
delete this.subscribers[s.id];
this.subCount--;
}
if (this.afters[s.id]) {
delete this.afters[s.id];
this.afterCount--;
}
}
if (this.host) {
this.host._monitor('detach', this.type, {
ce: this,
sub: s
});
}
if (s) {
delete s.fn;
delete s.context;
}
}
};
/////////////////////////////////////////////////////////////////////
/**
* Stores the subscriber information to be used when the event fires.
* @param {Function} fn The wrapped function to execute
* @param {Object} context The value of the keyword 'this' in the listener
* @param {Array} args* 0..n additional arguments to supply the listener
*
* @class Subscriber
* @constructor
*/
Y.Subscriber = function(fn, context, args) {
/**
* The callback that will be execute when the event fires
* This is wrapped by Y.rbind if obj was supplied.
* @property fn
* @type Function
*/
this.fn = fn;
/**
* Optional 'this' keyword for the listener
* @property context
* @type Object
*/
this.context = context;
/**
* Unique subscriber id
* @property id
* @type String
*/
this.id = Y.stamp(this);
/**
* Additional arguments to propagate to the subscriber
* @property args
* @type Array
*/
this.args = args;
/**
* Custom events for a given fire transaction.
* @property events
* @type {EventTarget}
*/
// this.events = null;
/**
* This listener only reacts to the event once
* @property once
*/
// this.once = false;
};
Y.Subscriber.prototype = {
_notify: function(c, args, ce) {
var a = this.args, ret;
switch (ce.signature) {
case 0:
ret = this.fn.call(c, ce.type, args, c);
break;
case 1:
ret = this.fn.call(c, args[0] || null, c);
break;
default:
if (a || args) {
args = args || [];
a = (a) ? args.concat(a) : args;
ret = this.fn.apply(c, a);
} else {
ret = this.fn.call(c);
}
}
if (this.once) {
ce._delete(this);
}
return ret;
},
/**
* Executes the subscriber.
* @method notify
* @param args {Array} Arguments array for the subscriber
* @param ce {CustomEvent} The custom event that sent the notification
*/
notify: function(args, ce) {
var c = this.context,
ret = true;
if (!c) {
c = (ce.contextFn) ? ce.contextFn() : ce.context;
}
// only catch errors if we will not re-throw them.
if (Y.config.throwFail) {
ret = this._notify(c, args, ce);
} else {
try {
ret = this._notify(c, args, ce);
} catch(e) {
Y.error(this + ' failed: ' + e.message, e);
}
}
return ret;
},
/**
* Returns true if the fn and obj match this objects properties.
* Used by the unsubscribe method to match the right subscriber.
*
* @method contains
* @param {Function} fn the function to execute
* @param {Object} context optional 'this' keyword for the listener
* @return {boolean} true if the supplied arguments match this
* subscriber's signature.
*/
contains: function(fn, context) {
if (context) {
return ((this.fn == fn) && this.context == context);
} else {
return (this.fn == fn);
}
}
};
/**
* Custom event engine, DOM event listener abstraction layer, synthetic DOM
* events.
* @module event-custom
* @submodule event-custom-base
*/
(function() {
/**
* EventTarget provides the implementation for any object to
* publish, subscribe and fire to custom events, and also
* alows other EventTargets to target the object with events
* sourced from the other object.
* EventTarget is designed to be used with Y.augment to wrap
* EventCustom in an interface that allows events to be listened to
* and fired by name. This makes it possible for implementing code to
* subscribe to an event that either has not been created yet, or will
* not be created at all.
* @class EventTarget
* @param opts a configuration object
* @config emitFacade {boolean} if true, all events will emit event
* facade payloads by default (default false)
* @config prefix {string} the prefix to apply to non-prefixed event names
* @config chain {boolean} if true, on/after/detach return the host to allow
* chaining, otherwise they return an EventHandle (default false)
*/
var L = Y.Lang,
PREFIX_DELIMITER = ':',
CATEGORY_DELIMITER = '|',
AFTER_PREFIX = '~AFTER~',
YArray = Y.Array,
_wildType = Y.cached(function(type) {
return type.replace(/(.*)(:)(.*)/, "*$2$3");
}),
/**
* If the instance has a prefix attribute and the
* event type is not prefixed, the instance prefix is
* applied to the supplied type.
* @method _getType
* @private
*/
_getType = Y.cached(function(type, pre) {
if (!pre || !L.isString(type) || type.indexOf(PREFIX_DELIMITER) > -1) {
return type;
}
return pre + PREFIX_DELIMITER + type;
}),
/**
* Returns an array with the detach key (if provided),
* and the prefixed event name from _getType
* Y.on('detachcategory| menu:click', fn)
* @method _parseType
* @private
*/
_parseType = Y.cached(function(type, pre) {
var t = type, detachcategory, after, i;
if (!L.isString(t)) {
return t;
}
i = t.indexOf(AFTER_PREFIX);
if (i > -1) {
after = true;
t = t.substr(AFTER_PREFIX.length);
}
i = t.indexOf(CATEGORY_DELIMITER);
if (i > -1) {
detachcategory = t.substr(0, (i));
t = t.substr(i+1);
if (t == '*') {
t = null;
}
}
// detach category, full type with instance prefix, is this an after listener, short type
return [detachcategory, (pre) ? _getType(t, pre) : t, after, t];
}),
ET = function(opts) {
var o = (L.isObject(opts)) ? opts : {};
this._yuievt = this._yuievt || {
id: Y.guid(),
events: {},
targets: {},
config: o,
chain: ('chain' in o) ? o.chain : Y.config.chain,
bubbling: false,
defaults: {
context: o.context || this,
host: this,
emitFacade: o.emitFacade,
fireOnce: o.fireOnce,
queuable: o.queuable,
monitored: o.monitored,
broadcast: o.broadcast,
defaultTargetOnly: o.defaultTargetOnly,
bubbles: ('bubbles' in o) ? o.bubbles : true
}
};
};
ET.prototype = {
/**
* Listen to a custom event hosted by this object one time.
* This is the equivalent to <code>on</code> except the
* listener is immediatelly detached when it is executed.
* @method once
* @param type {string} The type of the event
* @param fn {Function} The callback
* @param context {object} optional execution context.
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
* @return the event target or a detach handle per 'chain' config
*/
once: function() {
var handle = this.on.apply(this, arguments);
handle.sub.once = true;
return handle;
},
/**
* Subscribe to a custom event hosted by this object
* @method on
* @param type {string} The type of the event
* @param fn {Function} The callback
* @param context {object} optional execution context.
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
* @return the event target or a detach handle per 'chain' config
*/
on: function(type, fn, context) {
var parts = _parseType(type, this._yuievt.config.prefix), f, c, args, ret, ce,
detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
Node = Y.Node, n, domevent, isArr;
// full name, args, detachcategory, after
this._monitor('attach', parts[1], {
args: arguments,
category: parts[0],
after: parts[2]
});
if (L.isObject(type)) {
if (L.isFunction(type)) {
return Y.Do.before.apply(Y.Do, arguments);
}
f = fn;
c = context;
args = YArray(arguments, 0, true);
ret = {};
if (L.isArray(type)) {
isArr = true;
}
after = type._after;
delete type._after;
Y.each(type, function(v, k) {
if (L.isObject(v)) {
f = v.fn || ((L.isFunction(v)) ? v : f);
c = v.context || c;
}
var nv = (after) ? AFTER_PREFIX : '';
args[0] = nv + ((isArr) ? v : k);
args[1] = f;
args[2] = c;
ret[k] = this.on.apply(this, args);
}, this);
return (this._yuievt.chain) ? this : new Y.EventHandle(ret);
}
detachcategory = parts[0];
after = parts[2];
shorttype = parts[3];
// extra redirection so we catch adaptor events too. take a look at this.
if (Node && (this instanceof Node) && (shorttype in Node.DOM_EVENTS)) {
args = YArray(arguments, 0, true);
args.splice(2, 0, Node.getDOMNode(this));
return Y.on.apply(Y, args);
}
type = parts[1];
if (this instanceof YUI) {
adapt = Y.Env.evt.plugins[type];
args = YArray(arguments, 0, true);
args[0] = shorttype;
if (Node) {
n = args[2];
if (n instanceof Y.NodeList) {
n = Y.NodeList.getDOMNodes(n);
} else if (n instanceof Node) {
n = Node.getDOMNode(n);
}
domevent = (shorttype in Node.DOM_EVENTS);
// Captures both DOM events and event plugins.
if (domevent) {
args[2] = n;
}
}
// check for the existance of an event adaptor
if (adapt) {
handle = adapt.on.apply(Y, args);
} else if ((!type) || domevent) {
handle = Y.Event._attach(args);
}
}
if (!handle) {
ce = this._yuievt.events[type] || this.publish(type);
handle = ce._on(fn, context, (arguments.length > 3) ? YArray(arguments, 3, true) : null, (after) ? 'after' : true);
}
if (detachcategory) {
store[detachcategory] = store[detachcategory] || {};
store[detachcategory][type] = store[detachcategory][type] || [];
store[detachcategory][type].push(handle);
}
return (this._yuievt.chain) ? this : handle;
},
/**
* subscribe to an event
* @method subscribe
* @deprecated use on
*/
subscribe: function() {
return this.on.apply(this, arguments);
},
/**
* Detach one or more listeners the from the specified event
* @method detach
* @param type {string|Object} Either the handle to the subscriber or the
* type of event. If the type
* is not specified, it will attempt to remove
* the listener from all hosted events.
* @param fn {Function} The subscribed function to unsubscribe, if not
* supplied, all subscribers will be removed.
* @param context {Object} The custom object passed to subscribe. This is
* optional, but if supplied will be used to
* disambiguate multiple listeners that are the same
* (e.g., you subscribe many object using a function
* that lives on the prototype)
* @return {EventTarget} the host
*/
detach: function(type, fn, context) {
var evts = this._yuievt.events, i,
Node = Y.Node, isNode = Node && (this instanceof Node);
// detachAll disabled on the Y instance.
if (!type && (this !== Y)) {
for (i in evts) {
if (evts.hasOwnProperty(i)) {
evts[i].detach(fn, context);
}
}
if (isNode) {
Y.Event.purgeElement(Node.getDOMNode(this));
}
return this;
}
var parts = _parseType(type, this._yuievt.config.prefix),
detachcategory = L.isArray(parts) ? parts[0] : null,
shorttype = (parts) ? parts[3] : null,
adapt, store = Y.Env.evt.handles, detachhost, cat, args,
ce,
keyDetacher = function(lcat, ltype, host) {
var handles = lcat[ltype], ce, i;
if (handles) {
for (i = handles.length - 1; i >= 0; --i) {
ce = handles[i].evt;
if (ce.host === host || ce.el === host) {
handles[i].detach();
}
}
}
};
if (detachcategory) {
cat = store[detachcategory];
type = parts[1];
detachhost = (isNode) ? Y.Node.getDOMNode(this) : this;
if (cat) {
if (type) {
keyDetacher(cat, type, detachhost);
} else {
for (i in cat) {
if (cat.hasOwnProperty(i)) {
keyDetacher(cat, i, detachhost);
}
}
}
return this;
}
// If this is an event handle, use it to detach
} else if (L.isObject(type) && type.detach) {
type.detach();
return this;
// extra redirection so we catch adaptor events too. take a look at this.
} else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
args = YArray(arguments, 0, true);
args[2] = Node.getDOMNode(this);
Y.detach.apply(Y, args);
return this;
}
adapt = Y.Env.evt.plugins[shorttype];
// The YUI instance handles DOM events and adaptors
if (this instanceof YUI) {
args = YArray(arguments, 0, true);
// use the adaptor specific detach code if
if (adapt && adapt.detach) {
adapt.detach.apply(Y, args);
return this;
// DOM event fork
} else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
args[0] = type;
Y.Event.detach.apply(Y.Event, args);
return this;
}
}
// ce = evts[type];
ce = evts[parts[1]];
if (ce) {
ce.detach(fn, context);
}
return this;
},
/**
* detach a listener
* @method unsubscribe
* @deprecated use detach
*/
unsubscribe: function() {
return this.detach.apply(this, arguments);
},
/**
* Removes all listeners from the specified event. If the event type
* is not specified, all listeners from all hosted custom events will
* be removed.
* @method detachAll
* @param type {string} The type, or name of the event
*/
detachAll: function(type) {
return this.detach(type);
},
/**
* Removes all listeners from the specified event. If the event type
* is not specified, all listeners from all hosted custom events will
* be removed.
* @method unsubscribeAll
* @param type {string} The type, or name of the event
* @deprecated use detachAll
*/
unsubscribeAll: function() {
return this.detachAll.apply(this, arguments);
},
/**
* Creates a new custom event of the specified type. If a custom event
* by that name already exists, it will not be re-created. In either
* case the custom event is returned.
*
* @method publish
*
* @param type {string} the type, or name of the event
* @param opts {object} optional config params. Valid properties are:
*
* <ul>
* <li>
* 'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
* </li>
* <li>
* 'bubbles': whether or not this event bubbles (true)
* Events can only bubble if emitFacade is true.
* </li>
* <li>
* 'context': the default execution context for the listeners (this)
* </li>
* <li>
* 'defaultFn': the default function to execute when this event fires if preventDefault was not called
* </li>
* <li>
* 'emitFacade': whether or not this event emits a facade (false)
* </li>
* <li>
* 'prefix': the prefix for this targets events, e.g., 'menu' in 'menu:click'
* </li>
* <li>
* 'fireOnce': if an event is configured to fire once, new subscribers after
* the fire will be notified immediately.
* </li>
* <li>
* 'async': fireOnce event listeners will fire synchronously if the event has already
* fired unless async is true.
* </li>
* <li>
* 'preventable': whether or not preventDefault() has an effect (true)
* </li>
* <li>
* 'preventedFn': a function that is executed when preventDefault is called
* </li>
* <li>
* 'queuable': whether or not this event can be queued during bubbling (false)
* </li>
* <li>
* 'silent': if silent is true, debug messages are not provided for this event.
* </li>
* <li>
* 'stoppedFn': a function that is executed when stopPropagation is called
* </li>
*
* <li>
* 'monitored': specifies whether or not this event should send notifications about
* when the event has been attached, detached, or published.
* </li>
* <li>
* 'type': the event type (valid option if not provided as the first parameter to publish)
* </li>
* </ul>
*
* @return {CustomEvent} the custom event
*
*/
publish: function(type, opts) {
var events, ce, ret, defaults,
edata = this._yuievt,
pre = edata.config.prefix;
type = (pre) ? _getType(type, pre) : type;
this._monitor('publish', type, {
args: arguments
});
if (L.isObject(type)) {
ret = {};
Y.each(type, function(v, k) {
ret[k] = this.publish(k, v || opts);
}, this);
return ret;
}
events = edata.events;
ce = events[type];
if (ce) {
// ce.log("publish applying new config to published event: '"+type+"' exists", 'info', 'event');
if (opts) {
ce.applyConfig(opts, true);
}
} else {
defaults = edata.defaults;
// apply defaults
ce = new Y.CustomEvent(type,
(opts) ? Y.merge(defaults, opts) : defaults);
events[type] = ce;
}
// make sure we turn the broadcast flag off if this
// event was published as a result of bubbling
// if (opts instanceof Y.CustomEvent) {
// events[type].broadcast = false;
// }
return events[type];
},
/**
* This is the entry point for the event monitoring system.
* You can monitor 'attach', 'detach', 'fire', and 'publish'.
* When configured, these events generate an event. click ->
* click_attach, click_detach, click_publish -- these can
* be subscribed to like other events to monitor the event
* system. Inividual published events can have monitoring
* turned on or off (publish can't be turned off before it
* it published) by setting the events 'monitor' config.
*
* @private
*/
_monitor: function(what, type, o) {
var monitorevt, ce = this.getEvent(type);
if ((this._yuievt.config.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) {
monitorevt = type + '_' + what;
o.monitored = what;
this.fire.call(this, monitorevt, o);
}
},
/**
* Fire a custom event by name. The callback functions will be executed
* from the context specified when the event was created, and with the
* following parameters.
*
* If the custom event object hasn't been created, then the event hasn't
* been published and it has no subscribers. For performance sake, we
* immediate exit in this case. This means the event won't bubble, so
* if the intention is that a bubble target be notified, the event must
* be published on this object first.
*
* The first argument is the event type, and any additional arguments are
* passed to the listeners as parameters. If the first of these is an
* object literal, and the event is configured to emit an event facade,
* that object is mixed into the event facade and the facade is provided
* in place of the original object.
*
* @method fire
* @param type {String|Object} The type of the event, or an object that contains
* a 'type' property.
* @param arguments {Object*} an arbitrary set of parameters to pass to
* the handler. If the first of these is an object literal and the event is
* configured to emit an event facade, the event facade will replace that
* parameter after the properties the object literal contains are copied to
* the event facade.
* @return {EventTarget} the event host
*
*/
fire: function(type) {
var typeIncluded = L.isString(type),
t = (typeIncluded) ? type : (type && type.type),
ce, ret, pre = this._yuievt.config.prefix, ce2,
args = (typeIncluded) ? YArray(arguments, 1, true) : arguments;
t = (pre) ? _getType(t, pre) : t;
this._monitor('fire', t, {
args: args
});
ce = this.getEvent(t, true);
ce2 = this.getSibling(t, ce);
if (ce2 && !ce) {
ce = this.publish(t);
}
// this event has not been published or subscribed to
if (!ce) {
if (this._yuievt.hasTargets) {
return this.bubble({ type: t }, args, this);
}
// otherwise there is nothing to be done
ret = true;
} else {
ce.sibling = ce2;
ret = ce.fire.apply(ce, args);
}
return (this._yuievt.chain) ? this : ret;
},
getSibling: function(type, ce) {
var ce2;
// delegate to *:type events if there are subscribers
if (type.indexOf(PREFIX_DELIMITER) > -1) {
type = _wildType(type);
// console.log(type);
ce2 = this.getEvent(type, true);
if (ce2) {
// console.log("GOT ONE: " + type);
ce2.applyConfig(ce);
ce2.bubbles = false;
ce2.broadcast = 0;
// ret = ce2.fire.apply(ce2, a);
}
}
return ce2;
},
/**
* Returns the custom event of the provided type has been created, a
* falsy value otherwise
* @method getEvent
* @param type {string} the type, or name of the event
* @param prefixed {string} if true, the type is prefixed already
* @return {CustomEvent} the custom event or null
*/
getEvent: function(type, prefixed) {
var pre, e;
if (!prefixed) {
pre = this._yuievt.config.prefix;
type = (pre) ? _getType(type, pre) : type;
}
e = this._yuievt.events;
return e[type] || null;
},
/**
* Subscribe to a custom event hosted by this object. The
* supplied callback will execute after any listeners add
* via the subscribe method, and after the default function,
* if configured for the event, has executed.
* @method after
* @param type {string} The type of the event
* @param fn {Function} The callback
* @param context {object} optional execution context.
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
* @return the event target or a detach handle per 'chain' config
*/
after: function(type, fn) {
var a = YArray(arguments, 0, true);
switch (L.type(type)) {
case 'function':
return Y.Do.after.apply(Y.Do, arguments);
case 'array':
// YArray.each(a[0], function(v) {
// v = AFTER_PREFIX + v;
// });
// break;
case 'object':
a[0]._after = true;
break;
default:
a[0] = AFTER_PREFIX + type;
}
return this.on.apply(this, a);
},
/**
* Executes the callback before a DOM event, custom event
* or method. If the first argument is a function, it
* is assumed the target is a method. For DOM and custom
* events, this is an alias for Y.on.
*
* For DOM and custom events:
* type, callback, context, 0-n arguments
*
* For methods:
* callback, object (method host), methodName, context, 0-n arguments
*
* @method before
* @return detach handle
*/
before: function() {
return this.on.apply(this, arguments);
}
};
Y.EventTarget = ET;
// make Y an event target
Y.mix(Y, ET.prototype, false, false, {
bubbles: false
});
ET.call(Y);
YUI.Env.globalEvents = YUI.Env.globalEvents || new ET();
/**
* Hosts YUI page level events. This is where events bubble to
* when the broadcast config is set to 2. This property is
* only available if the custom event module is loaded.
* @property Global
* @type EventTarget
* @for YUI
*/
Y.Global = YUI.Env.globalEvents;
// @TODO implement a global namespace function on Y.Global?
})();
/**
* <code>YUI</code>'s <code>on</code> method is a unified interface for subscribing to
* most events exposed by YUI. This includes custom events, DOM events, and
* function events. <code>detach</code> is also provided to remove listeners
* serviced by this function.
*
* The signature that <code>on</code> accepts varies depending on the type
* of event being consumed. Refer to the specific methods that will
* service a specific request for additional information about subscribing
* to that type of event.
*
* <ul>
* <li>Custom events. These events are defined by various
* modules in the library. This type of event is delegated to
* <code>EventTarget</code>'s <code>on</code> method.
* <ul>
* <li>The type of the event</li>
* <li>The callback to execute</li>
* <li>An optional context object</li>
* <li>0..n additional arguments to supply the callback.</li>
* </ul>
* Example:
* <code>Y.on('drag:drophit', function() { // start work });</code>
* </li>
* <li>DOM events. These are moments reported by the browser related
* to browser functionality and user interaction.
* This type of event is delegated to <code>Event</code>'s
* <code>attach</code> method.
* <ul>
* <li>The type of the event</li>
* <li>The callback to execute</li>
* <li>The specification for the Node(s) to attach the listener
* to. This can be a selector, collections, or Node/Element
* refereces.</li>
* <li>An optional context object</li>
* <li>0..n additional arguments to supply the callback.</li>
* </ul>
* Example:
* <code>Y.on('click', function(e) { // something was clicked }, '#someelement');</code>
* </li>
* <li>Function events. These events can be used to react before or after a
* function is executed. This type of event is delegated to <code>Event.Do</code>'s
* <code>before</code> method.
* <ul>
* <li>The callback to execute</li>
* <li>The object that has the function that will be listened for.</li>
* <li>The name of the function to listen for.</li>
* <li>An optional context object</li>
* <li>0..n additional arguments to supply the callback.</li>
* </ul>
* Example <code>Y.on(function(arg1, arg2, etc) { // obj.methodname was executed }, obj 'methodname');</code>
* </li>
* </ul>
*
* <code>on</code> corresponds to the moment before any default behavior of
* the event. <code>after</code> works the same way, but these listeners
* execute after the event's default behavior. <code>before</code> is an
* alias for <code>on</code>.
*
* @method on
* @param type** event type (this parameter does not apply for function events)
* @param fn the callback
* @param target** a descriptor for the target (applies to custom events only).
* For function events, this is the object that contains the function to
* execute.
* @param extra** 0..n Extra information a particular event may need. These
* will be documented with the event. In the case of function events, this
* is the name of the function to execute on the host. In the case of
* delegate listeners, this is the event delegation specification.
* @param context optionally change the value of 'this' in the callback
* @param args* 0..n additional arguments to pass to the callback.
* @return the event target or a detach handle per 'chain' config
* @for YUI
*/
/**
* Listen for an event one time. Equivalent to <code>on</code>, except that
* the listener is immediately detached when executed.
* @see on
* @method once
* @param type** event type (this parameter does not apply for function events)
* @param fn the callback
* @param target** a descriptor for the target (applies to custom events only).
* For function events, this is the object that contains the function to
* execute.
* @param extra** 0..n Extra information a particular event may need. These
* will be documented with the event. In the case of function events, this
* is the name of the function to execute on the host. In the case of
* delegate listeners, this is the event delegation specification.
* @param context optionally change the value of 'this' in the callback
* @param args* 0..n additional arguments to pass to the callback.
* @return the event target or a detach handle per 'chain' config
* @for YUI
*/
/**
* after() is a unified interface for subscribing to
* most events exposed by YUI. This includes custom events,
* DOM events, and AOP events. This works the same way as
* the on() function, only it operates after any default
* behavior for the event has executed. @see <code>on</code> for more
* information.
* @method after
* @param type event type (this parameter does not apply for function events)
* @param fn the callback
* @param target a descriptor for the target (applies to custom events only).
* For function events, this is the object that contains the function to
* execute.
* @param extra 0..n Extra information a particular event may need. These
* will be documented with the event. In the case of function events, this
* is the name of the function to execute on the host. In the case of
* delegate listeners, this is the event delegation specification.
* @param context optionally change the value of 'this' in the callback
* @param args* 0..n additional arguments to pass to the callback.
* @return the event target or a detach handle per 'chain' config
* @for YUI
*/
}, '@VERSION@' ,{requires:['oop']});