File: event-custom/js/event-do.js
- /**
- * Custom event engine, DOM event listener abstraction layer, synthetic DOM
- * events.
- * @module event-custom
- * @submodule event-custom-base
- */
-
- /**
- * Allows for the insertion of methods that are executed before or after
- * a specified method
- * @class Do
- * @static
- */
-
- var DO_BEFORE = 0,
- DO_AFTER = 1,
-
- DO = {
-
- /**
- * Cache of objects touched by the utility
- * @property objs
- * @static
- * @deprecated Since 3.6.0. The `_yuiaop` property on the AOP'd object
- * replaces the role of this property, but is considered to be private, and
- * is only mentioned to provide a migration path.
- *
- * If you have a use case which warrants migration to the _yuiaop property,
- * please file a ticket to let us know what it's used for and we can see if
- * we need to expose hooks for that functionality more formally.
- */
- objs: null,
-
- /**
- * <p>Execute the supplied method before the specified function. Wrapping
- * function may optionally return an instance of the following classes to
- * further alter runtime behavior:</p>
- * <dl>
- * <dt></code>Y.Do.Halt(message, returnValue)</code></dt>
- * <dd>Immediatly stop execution and return
- * <code>returnValue</code>. No other wrapping functions will be
- * executed.</dd>
- * <dt></code>Y.Do.AlterArgs(message, newArgArray)</code></dt>
- * <dd>Replace the arguments that the original function will be
- * called with.</dd>
- * <dt></code>Y.Do.Prevent(message)</code></dt>
- * <dd>Don't execute the wrapped function. Other before phase
- * wrappers will be executed.</dd>
- * </dl>
- *
- * @method before
- * @param fn {Function} the function to execute
- * @param obj the object hosting the method to displace
- * @param sFn {string} the name of the method to displace
- * @param c The execution context for fn
- * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
- * when the event fires.
- * @return {EventHandle} handle for the subscription
- * @static
- */
- before: function(fn, obj, sFn, c) {
- // Y.log('Do before: ' + sFn, 'info', 'event');
- var f = fn, a;
- if (c) {
- a = [fn, c].concat(Y.Array(arguments, 4, true));
- f = Y.rbind.apply(Y, a);
- }
-
- return this._inject(DO_BEFORE, f, obj, sFn);
- },
-
- /**
- * <p>Execute the supplied method after the specified function. Wrapping
- * function may optionally return an instance of the following classes to
- * further alter runtime behavior:</p>
- * <dl>
- * <dt></code>Y.Do.Halt(message, returnValue)</code></dt>
- * <dd>Immediatly stop execution and return
- * <code>returnValue</code>. No other wrapping functions will be
- * executed.</dd>
- * <dt></code>Y.Do.AlterReturn(message, returnValue)</code></dt>
- * <dd>Return <code>returnValue</code> instead of the wrapped
- * method's original return value. This can be further altered by
- * other after phase wrappers.</dd>
- * </dl>
- *
- * <p>The static properties <code>Y.Do.originalRetVal</code> and
- * <code>Y.Do.currentRetVal</code> will be populated for reference.</p>
- *
- * @method after
- * @param fn {Function} the function to execute
- * @param obj the object hosting the method to displace
- * @param sFn {string} the name of the method to displace
- * @param c The execution context for fn
- * @param arg* {mixed} 0..n additional arguments to supply to the subscriber
- * @return {EventHandle} handle for the subscription
- * @static
- */
- after: function(fn, obj, sFn, c) {
- var f = fn, a;
- if (c) {
- a = [fn, c].concat(Y.Array(arguments, 4, true));
- f = Y.rbind.apply(Y, a);
- }
-
- return this._inject(DO_AFTER, f, obj, sFn);
- },
-
- /**
- * Execute the supplied method before or after the specified function.
- * Used by <code>before</code> and <code>after</code>.
- *
- * @method _inject
- * @param when {string} before or after
- * @param fn {Function} the function to execute
- * @param obj the object hosting the method to displace
- * @param sFn {string} the name of the method to displace
- * @param c The execution context for fn
- * @return {EventHandle} handle for the subscription
- * @private
- * @static
- */
- _inject: function(when, fn, obj, sFn) {
- // object id
- var id = Y.stamp(obj), o, sid;
-
- if (!obj._yuiaop) {
- // create a map entry for the obj if it doesn't exist, to hold overridden methods
- obj._yuiaop = {};
- }
-
- o = obj._yuiaop;
-
- if (!o[sFn]) {
- // create a map entry for the method if it doesn't exist
- o[sFn] = new Y.Do.Method(obj, sFn);
-
- // re-route the method to our wrapper
- obj[sFn] = function() {
- return o[sFn].exec.apply(o[sFn], arguments);
- };
- }
-
- // subscriber id
- sid = id + Y.stamp(fn) + sFn;
-
- // register the callback
- o[sFn].register(sid, fn, when);
-
- return new Y.EventHandle(o[sFn], sid);
- },
-
- /**
- * Detach a before or after subscription.
- *
- * @method detach
- * @param handle {EventHandle} the subscription handle
- * @static
- */
- detach: function(handle) {
- if (handle.detach) {
- handle.detach();
- }
- }
- };
-
- Y.Do = DO;
-
- //////////////////////////////////////////////////////////////////////////
-
- /**
- * Contains the return value from the wrapped method, accessible
- * by 'after' event listeners.
- *
- * @property originalRetVal
- * @static
- * @since 3.2.0
- */
-
- /**
- * Contains the current state of the return value, consumable by
- * 'after' event listeners, and updated if an after subscriber
- * changes the return value generated by the wrapped function.
- *
- * @property currentRetVal
- * @static
- * @since 3.2.0
- */
-
- //////////////////////////////////////////////////////////////////////////
-
- /**
- * Wrapper for a displaced method with aop enabled
- * @class Do.Method
- * @constructor
- * @param obj The object to operate on
- * @param sFn The name of the method to displace
- */
- DO.Method = function(obj, sFn) {
- this.obj = obj;
- this.methodName = sFn;
- this.method = obj[sFn];
- this.before = {};
- this.after = {};
- };
-
- /**
- * Register a aop subscriber
- * @method register
- * @param sid {string} the subscriber id
- * @param fn {Function} the function to execute
- * @param when {string} when to execute the function
- */
- DO.Method.prototype.register = function (sid, fn, when) {
- if (when) {
- this.after[sid] = fn;
- } else {
- this.before[sid] = fn;
- }
- };
-
- /**
- * Unregister a aop subscriber
- * @method delete
- * @param sid {string} the subscriber id
- * @param fn {Function} the function to execute
- * @param when {string} when to execute the function
- */
- DO.Method.prototype._delete = function (sid) {
- // Y.log('Y.Do._delete: ' + sid, 'info', 'Event');
- delete this.before[sid];
- delete this.after[sid];
- };
-
- /**
- * <p>Execute the wrapped method. All arguments are passed into the wrapping
- * functions. If any of the before wrappers return an instance of
- * <code>Y.Do.Halt</code> or <code>Y.Do.Prevent</code>, neither the wrapped
- * function nor any after phase subscribers will be executed.</p>
- *
- * <p>The return value will be the return value of the wrapped function or one
- * provided by a wrapper function via an instance of <code>Y.Do.Halt</code> or
- * <code>Y.Do.AlterReturn</code>.
- *
- * @method exec
- * @param arg* {any} Arguments are passed to the wrapping and wrapped functions
- * @return {any} Return value of wrapped function unless overwritten (see above)
- */
- DO.Method.prototype.exec = function () {
-
- var args = Y.Array(arguments, 0, true),
- i, ret, newRet,
- bf = this.before,
- af = this.after,
- prevented = false;
-
- // execute before
- for (i in bf) {
- if (bf.hasOwnProperty(i)) {
- ret = bf[i].apply(this.obj, args);
- if (ret) {
- switch (ret.constructor) {
- case DO.Halt:
- return ret.retVal;
- case DO.AlterArgs:
- args = ret.newArgs;
- break;
- case DO.Prevent:
- prevented = true;
- break;
- default:
- }
- }
- }
- }
-
- // execute method
- if (!prevented) {
- ret = this.method.apply(this.obj, args);
- }
-
- DO.originalRetVal = ret;
- DO.currentRetVal = ret;
-
- // execute after methods.
- for (i in af) {
- if (af.hasOwnProperty(i)) {
- newRet = af[i].apply(this.obj, args);
- // Stop processing if a Halt object is returned
- if (newRet && newRet.constructor === DO.Halt) {
- return newRet.retVal;
- // Check for a new return value
- } else if (newRet && newRet.constructor === DO.AlterReturn) {
- ret = newRet.newRetVal;
- // Update the static retval state
- DO.currentRetVal = ret;
- }
- }
- }
-
- return ret;
- };
-
- //////////////////////////////////////////////////////////////////////////
-
- /**
- * Return an AlterArgs object when you want to change the arguments that
- * were passed into the function. Useful for Do.before subscribers. An
- * example would be a service that scrubs out illegal characters prior to
- * executing the core business logic.
- * @class Do.AlterArgs
- * @constructor
- * @param msg {String} (optional) Explanation of the altered return value
- * @param newArgs {Array} Call parameters to be used for the original method
- * instead of the arguments originally passed in.
- */
- DO.AlterArgs = function(msg, newArgs) {
- this.msg = msg;
- this.newArgs = newArgs;
- };
-
- /**
- * Return an AlterReturn object when you want to change the result returned
- * from the core method to the caller. Useful for Do.after subscribers.
- * @class Do.AlterReturn
- * @constructor
- * @param msg {String} (optional) Explanation of the altered return value
- * @param newRetVal {any} Return value passed to code that invoked the wrapped
- * function.
- */
- DO.AlterReturn = function(msg, newRetVal) {
- this.msg = msg;
- this.newRetVal = newRetVal;
- };
-
- /**
- * Return a Halt object when you want to terminate the execution
- * of all subsequent subscribers as well as the wrapped method
- * if it has not exectued yet. Useful for Do.before subscribers.
- * @class Do.Halt
- * @constructor
- * @param msg {String} (optional) Explanation of why the termination was done
- * @param retVal {any} Return value passed to code that invoked the wrapped
- * function.
- */
- DO.Halt = function(msg, retVal) {
- this.msg = msg;
- this.retVal = retVal;
- };
-
- /**
- * Return a Prevent object when you want to prevent the wrapped function
- * from executing, but want the remaining listeners to execute. Useful
- * for Do.before subscribers.
- * @class Do.Prevent
- * @constructor
- * @param msg {String} (optional) Explanation of why the termination was done
- */
- DO.Prevent = function(msg) {
- this.msg = msg;
- };
-
- /**
- * Return an Error object when you want to terminate the execution
- * of all subsequent method calls.
- * @class Do.Error
- * @constructor
- * @param msg {String} (optional) Explanation of the altered return value
- * @param retVal {any} Return value passed to code that invoked the wrapped
- * function.
- * @deprecated use Y.Do.Halt or Y.Do.Prevent
- */
- DO.Error = DO.Halt;
-
-
- //////////////////////////////////////////////////////////////////////////
-
-