| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //var DEBUG = DEBUG != null ? DEBUG : true
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | define(function(require){ var module = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | // Actions
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Actions are an extension to the JavaScript object model tailored for
 | 
					
						
							|  |  |  | // a set of specific tasks.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The action system consists of these parts:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 1) documentation generation and introspection
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | // 	XXX not all helpers are defined at this point...
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | // 	
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 2) event-like callbacks for actions
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		MyActions.on('action', function(){ ... })
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | // 		MyActions.on('action.post', function(){ ... })
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		MyActions.on('action.pre', function(){ ... })
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 3) a mechanism to extend already defined actions
 | 
					
						
							|  |  |  | // 	This replaces / complements the standard JavaScript overloading 
 | 
					
						
							|  |  |  | // 	mechanisms, here is a direct comparison:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// Native...
 | 
					
						
							|  |  |  | // 		var X = {
 | 
					
						
							|  |  |  | // 			m: function(){ console.log('m') }
 | 
					
						
							|  |  |  | // 		}
 | 
					
						
							|  |  |  | // 		var O = {
 | 
					
						
							|  |  |  | // 			m: function(){
 | 
					
						
							|  |  |  | // 				console.log('pre')
 | 
					
						
							|  |  |  | // 				B.__proto__.m.call(this)
 | 
					
						
							|  |  |  | // 				console.log('post')
 | 
					
						
							|  |  |  | // 			}
 | 
					
						
							|  |  |  | // 		}
 | 
					
						
							|  |  |  | // 		O.__proto__ = X
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// Actions...
 | 
					
						
							|  |  |  | // 		var X = Actions({
 | 
					
						
							|  |  |  | // 			m: [function(){ console.log('m') }]
 | 
					
						
							|  |  |  | // 		})
 | 
					
						
							|  |  |  | // 		var O = Actions(X, {
 | 
					
						
							|  |  |  | // 			m: [function(){
 | 
					
						
							|  |  |  | // 				console.log('pre')
 | 
					
						
							|  |  |  | // 				return function(){
 | 
					
						
							|  |  |  | // 					console.log('post')
 | 
					
						
							|  |  |  | // 				}
 | 
					
						
							|  |  |  | // 			}]
 | 
					
						
							|  |  |  | // 		})
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Comparing to the native system:
 | 
					
						
							|  |  |  | // 	+ no need to chain overloaded calls by hand (automatic)
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | // 	+/- more restrictive -- no way to prevent original actions from 
 | 
					
						
							|  |  |  | // 	  running, i.e. no way to shadow.
 | 
					
						
							|  |  |  | // 	+/- hidden the internals (.__proto__ assignment)
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | // 	- more structural code (returning a callback vs. B.__proto__.m.call)
 | 
					
						
							|  |  |  | // 		NOTE: that the Actions(..) call and lists containing functions
 | 
					
						
							|  |  |  | // 			is not added complexity as they are mainly used for docs.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | // helpers...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX
 | 
					
						
							|  |  |  | function args2array(args){ | 
					
						
							|  |  |  | 	return Array.apply(null, args) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Construct an action object...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | // Action function format:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// pre event code...
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | // 		function(){
 | 
					
						
							|  |  |  | //			... // pre code
 | 
					
						
							|  |  |  | // 		}
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | // 		// pre/post event code...
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | // 		function(){
 | 
					
						
							|  |  |  | //			... // pre code
 | 
					
						
							|  |  |  | //			return function(){
 | 
					
						
							|  |  |  | //				... // post code
 | 
					
						
							|  |  |  | //			}
 | 
					
						
							|  |  |  | // 		}
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | // 		// same as above but using a deferred instead of a callback...
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | // 		function(){
 | 
					
						
							|  |  |  | //			... // pre code
 | 
					
						
							|  |  |  | //			return $.Deferred()
 | 
					
						
							|  |  |  | //				.done(function(){
 | 
					
						
							|  |  |  | //					... // post code
 | 
					
						
							|  |  |  | //				})
 | 
					
						
							|  |  |  | // 		}
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2014-10-06 06:18:39 +04:00
										 |  |  | // An action is essentially a method with several additional features:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	- actions are split into two stages:
 | 
					
						
							|  |  |  | // 		pre: 	the code of the method is executed before the action 
 | 
					
						
							|  |  |  | // 				event is fired
 | 
					
						
							|  |  |  | // 		post:	if the action returns a callback function or a deferred
 | 
					
						
							|  |  |  | // 				object it will be executed after the event is fired
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	- actions automatically call the shadowed action, the pre stage is
 | 
					
						
							|  |  |  | // 	  executed down-up while the post stage is run in reverse order, 
 | 
					
						
							|  |  |  | // 	  i.e. the pre is going down and the post is going up.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	- actions provide an event-like mechanism to register handlers or 
 | 
					
						
							|  |  |  | // 	  callbacks. These callbacks are local to a specific object and will
 | 
					
						
							|  |  |  | // 	  be fired on action event/call starting from the current action 
 | 
					
						
							|  |  |  | // 	  caller and down the inheritance chain, i.e. all event handlers 
 | 
					
						
							|  |  |  | // 	  registered from the current object and up to the base action set
 | 
					
						
							|  |  |  | // 	  will be fired.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: actions once defined do not depend on the inheritance hierarchy,
 | 
					
						
							|  |  |  | // 		but they do on the other hand depend on methods defined in the
 | 
					
						
							|  |  |  | // 		MetaActions object.
 | 
					
						
							|  |  |  | // 		XXX should this be the case???
 | 
					
						
							|  |  |  | // NOTE: by default an action will return 'this', i.e. the action set
 | 
					
						
							|  |  |  | // 		object the action was called from.
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | var Action = | 
					
						
							|  |  |  | module.Action = | 
					
						
							|  |  |  | function Action(name, doc, ldoc, func){ | 
					
						
							|  |  |  | 	// we got called without a 'new'...
 | 
					
						
							|  |  |  | 	if(this == null || this.constructor !== Action){ | 
					
						
							|  |  |  | 		// XXX using something like .apply(.., arguemnts) would be more
 | 
					
						
							|  |  |  | 		// 		generel but have no time to figure out how to pass it 
 | 
					
						
							|  |  |  | 		// 		to new without the later complaining...
 | 
					
						
							|  |  |  | 		return new Action(name, doc, ldoc, func) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// prevent action overloading...
 | 
					
						
							|  |  |  | 	if(this[name] != null){ | 
					
						
							|  |  |  | 		throw 'action "'+name+'" already exists.' | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// create the actual instance we will be returning...
 | 
					
						
							|  |  |  | 	var meth = function(){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		var args = args2array(arguments) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 		// get and call handlers -- pre phase...
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: using CLASS.__proto__[name].call(this, ...) here is not
 | 
					
						
							|  |  |  | 		// 		possible as there is no reliable way to get the "class" 
 | 
					
						
							|  |  |  | 		// 		the current method is referenced from.
 | 
					
						
							|  |  |  | 		// 		...searching the inheritance chain is not reliable as a
 | 
					
						
							|  |  |  | 		// 		method can be referenced more than once, both with the 
 | 
					
						
							|  |  |  | 		// 		same as well as under different names...
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:52:20 +04:00
										 |  |  | 		var handlers = this.getHandlers(name) | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 			.map(function(h){ return h.apply(that, args) }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 		// NOTE: this action will get included and called by the code 
 | 
					
						
							|  |  |  | 		// 		above and below...
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 		// call handlers -- post phase...
 | 
					
						
							|  |  |  | 		// NOTE: post handlers need to get called last run pre first run post...
 | 
					
						
							|  |  |  | 		handlers.reverse().forEach(function(h){  | 
					
						
							|  |  |  | 			// function...
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 			if(h instanceof Function){ | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 				//h.call(that, res)
 | 
					
						
							|  |  |  | 				h.call(that) | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 			// deferred...
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 			} else if(h != null && h.resolve instanceof Function){ | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 				//h.resolve(res)
 | 
					
						
							|  |  |  | 				h.resolve() | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 			}  | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 		//return res
 | 
					
						
							|  |  |  | 		return this | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	meth.__proto__ = this.__proto__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// populate the action attributes...
 | 
					
						
							|  |  |  | 	meth.name = name | 
					
						
							|  |  |  | 	meth.doc = doc | 
					
						
							|  |  |  | 	meth.long_doc = ldoc | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 	meth.func = func | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 	return meth | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 06:18:39 +04:00
										 |  |  | // A base action-set object...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This will define a set of action-set specific methods and helpers.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | // XXX .off(...) needs more work...
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | var MetaActions = | 
					
						
							|  |  |  | module.MetaActions = { | 
					
						
							|  |  |  | 	// List actions...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this will only list all actions except the ones defined in 
 | 
					
						
							|  |  |  | 	// 		MetaActions, unless 'all' is set...
 | 
					
						
							|  |  |  | 	actions: function(all){ | 
					
						
							|  |  |  | 		var res = [] | 
					
						
							|  |  |  | 		for(var k in this){ | 
					
						
							|  |  |  | 			// get only actions...
 | 
					
						
							|  |  |  | 			if(this[k] instanceof Action  | 
					
						
							|  |  |  | 					// if all is true, get all actions...
 | 
					
						
							|  |  |  | 					&& !all  | 
					
						
							|  |  |  | 					// if all is false, skip actions defined in MetaActions...
 | 
					
						
							|  |  |  | 					|| MetaActions.hasOwnProperty(k)){ | 
					
						
							|  |  |  | 				res.push(k) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Number of defined actions...
 | 
					
						
							|  |  |  | 	get length(){ | 
					
						
							|  |  |  | 		return this.actions.length | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:52:20 +04:00
										 |  |  | 	// get action documentation...
 | 
					
						
							|  |  |  | 	getDoc: function(actions){ | 
					
						
							|  |  |  | 		var res = {} | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		actions = actions == null ? this.actions()  | 
					
						
							|  |  |  | 			: typeof(actions) == typeof('str') ? [actions] | 
					
						
							|  |  |  | 			: actions | 
					
						
							|  |  |  | 		// get the first defined set of docs in the inheritance chain...
 | 
					
						
							|  |  |  | 		actions.forEach(function(n){ | 
					
						
							|  |  |  | 			var cur = that | 
					
						
							|  |  |  | 			while(cur.__proto__ != null){ | 
					
						
							|  |  |  | 				if(cur[n].doc != null){ | 
					
						
							|  |  |  | 					res[n] = [ cur[n].doc, cur[n].long_doc ] | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				cur = cur.__proto__ | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// collect all the handlers from the inheritance chain and arrange
 | 
					
						
							|  |  |  | 	// them up-down, first defined to last...
 | 
					
						
							|  |  |  | 	getHandlers: function(name){ | 
					
						
							|  |  |  | 		var handlers = [] | 
					
						
							|  |  |  | 		var cur = this | 
					
						
							|  |  |  | 		while(cur.__proto__ != null){ | 
					
						
							|  |  |  | 			// get action "event" handlers...
 | 
					
						
							|  |  |  | 			if(cur.hasOwnProperty('_action_handlers')  | 
					
						
							|  |  |  | 					&& name in cur._action_handlers){ | 
					
						
							|  |  |  | 				handlers.splice.apply(handlers, | 
					
						
							|  |  |  | 						[handlers.length, 0].concat(cur._action_handlers[name])) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// get the overloading action...
 | 
					
						
							|  |  |  | 			// NOTE: this will get all the handlers including the root 
 | 
					
						
							|  |  |  | 			// 		and the current handlers...
 | 
					
						
							|  |  |  | 			// NOTE: this will ignore "shadows" that are not actions...
 | 
					
						
							|  |  |  | 			if(cur.hasOwnProperty(name) && cur[name] instanceof Action){ | 
					
						
							|  |  |  | 				handlers.push(cur[name].func) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			cur = cur.__proto__ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return handlers | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 	// Register an action callback...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Register a post action callback
 | 
					
						
							|  |  |  | 	// 	.on('action', <function>)
 | 
					
						
							|  |  |  | 	// 	.on('action.post', <function>)
 | 
					
						
							|  |  |  | 	// 		-> <action-set>
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Register a pre action callback
 | 
					
						
							|  |  |  | 	// 	.on('action.pre', <function>)
 | 
					
						
							|  |  |  | 	// 		-> <action-set>
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Modes:
 | 
					
						
							|  |  |  | 	// 	'pre'		- the handler is fired before the action is triggered,
 | 
					
						
							|  |  |  | 	// 					and if the handler returns a deferred or a function
 | 
					
						
							|  |  |  | 	// 					then that will get resolved, called resp. after
 | 
					
						
							|  |  |  | 	// 					the action is done.
 | 
					
						
							|  |  |  | 	// 	'post'		- the handler is fired after the action is finished.
 | 
					
						
							|  |  |  | 	// 					this is the default.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | 	// NOTE: 'post' mode is the default.
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 	on: function(action, handler){ | 
					
						
							|  |  |  | 		// prepare the handler...
 | 
					
						
							|  |  |  | 		var mode = action.split('.') | 
					
						
							|  |  |  | 		action = mode[0] | 
					
						
							|  |  |  | 		mode = mode[1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// a post handler (default)...
 | 
					
						
							|  |  |  | 		if(mode == null || mode == 'post'){ | 
					
						
							|  |  |  | 			var old_handler = handler | 
					
						
							|  |  |  | 			handler = function(){ return old_handler } | 
					
						
							|  |  |  | 			// NOTE: this is set so as to identify the handler for removal
 | 
					
						
							|  |  |  | 			// 		via. .off(..)
 | 
					
						
							|  |  |  | 			handler.orig_handler = old_handler | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// mot pre mode...
 | 
					
						
							|  |  |  | 		} else if(mode != 'pre') { | 
					
						
							|  |  |  | 			throw 'Unknown action mode: '+action+'.'+mode | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// register handlers locally only...
 | 
					
						
							|  |  |  | 		if(!this.hasOwnProperty('_action_handlers')){ | 
					
						
							|  |  |  | 			this._action_handlers = {} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(!(action in this._action_handlers)){ | 
					
						
							|  |  |  | 			this._action_handlers[action] = [] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// register a handler only once...
 | 
					
						
							|  |  |  | 		if(this._action_handlers[action].indexOf(handler) < 0){ | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 			// NOTE: last registered is first...
 | 
					
						
							|  |  |  | 			this._action_handlers[action].splice(0, 0, handler) | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Remove an action callback...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX this will not work for explicit <action>.post...
 | 
					
						
							|  |  |  | 	off: function(action, handler){ | 
					
						
							|  |  |  | 		if(this.hasOwnProperty('_action_handlers')){ | 
					
						
							|  |  |  | 			var mode = action.split('.') | 
					
						
							|  |  |  | 			action = mode[0] | 
					
						
							|  |  |  | 			mode = mode[1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// get the handlers...
 | 
					
						
							|  |  |  | 			var h = this._action_handlers[action] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var i = -1 | 
					
						
							|  |  |  | 			if(mode == null || mode == 'post'){ | 
					
						
							|  |  |  | 				// XXX find via e.orig_handler == handler && e.mode == 'post'
 | 
					
						
							|  |  |  | 				h.forEach(function(e, j){ | 
					
						
							|  |  |  | 					// NOTE: we will only get the first match...
 | 
					
						
							|  |  |  | 					if(e.orig_handler == handler && i == -1){ | 
					
						
							|  |  |  | 						i = j | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} else if(mode == 'pre'){ | 
					
						
							|  |  |  | 				i = h.indexOf(handler) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// NOTE: unknown modes are skipped...
 | 
					
						
							|  |  |  | 			if(i >= 0){ | 
					
						
							|  |  |  | 				h.splice(i, 1) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 06:18:39 +04:00
										 |  |  | // An action set...
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | //
 | 
					
						
							|  |  |  | //	Actions(<object>)
 | 
					
						
							|  |  |  | //	Actions(<prototype>, <object>)
 | 
					
						
							|  |  |  | //		-> actions
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This will pre-process an object to setup the action mechanics.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The action format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							|  |  |  | // 		// full format...
 | 
					
						
							|  |  |  | // 		<name> : [
 | 
					
						
							|  |  |  | // 			<doc>,
 | 
					
						
							|  |  |  | // 			<long-doc>,
 | 
					
						
							|  |  |  | // 			<function>
 | 
					
						
							|  |  |  | // 		],
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// short doc only...
 | 
					
						
							|  |  |  | // 		<name> : [
 | 
					
						
							|  |  |  | // 			<doc>,
 | 
					
						
							|  |  |  | // 			<function>
 | 
					
						
							|  |  |  | // 		],
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// only the code...
 | 
					
						
							|  |  |  | // 		<name> : [
 | 
					
						
							|  |  |  | // 			<function>
 | 
					
						
							|  |  |  | // 		],
 | 
					
						
							|  |  |  | // 		...
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2014-10-06 06:18:39 +04:00
										 |  |  | // NOTE: if <prototype> is not given, MetaActions will be used as default.
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2014-10-06 06:18:39 +04:00
										 |  |  | // For more documentation see: Action(..).
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | var Actions = | 
					
						
							|  |  |  | module.Actions = | 
					
						
							|  |  |  | function Actions(a, b){ | 
					
						
							|  |  |  | 	var obj = b == null ? a : b | 
					
						
							|  |  |  | 	var proto = b == null ? MetaActions : a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// NOTE: this is intentionally done only for own attributes...
 | 
					
						
							|  |  |  | 	Object.keys(obj).forEach(function(k){ | 
					
						
							|  |  |  | 		var args = obj[k] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// skip non-arrays...
 | 
					
						
							|  |  |  | 		if(args.constructor !== Array  | 
					
						
							|  |  |  | 				// and arrays the last element of which is not a function...
 | 
					
						
							|  |  |  | 				|| !(args[args.length-1] instanceof Function)){ | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var func = args.pop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// create a new action...
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 		obj[k] = new Action(k, args[0], args[1], func) | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(proto != null){ | 
					
						
							|  |  |  | 		obj.__proto__ = proto | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return obj | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var test = | 
					
						
							|  |  |  | module.test = | 
					
						
							|  |  |  | function test(){ | 
					
						
							|  |  |  | 	var TestActions =  | 
					
						
							|  |  |  | 	module.TestActions =  | 
					
						
							|  |  |  | 	Actions({ | 
					
						
							|  |  |  | 		testActionGen1: ['baisc test action...', | 
					
						
							|  |  |  | 			'some extra info', | 
					
						
							|  |  |  | 			function(){ | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 				console.log('  test 1!') | 
					
						
							|  |  |  | 				return function(){ | 
					
						
							|  |  |  | 					console.log('  test 2!') | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 			}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		testActionGen2: ['baisc 2\'nd gen test action...', | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 			// no extra info...
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 			function(){ | 
					
						
							|  |  |  | 				console.log('  test gen 2!') | 
					
						
							|  |  |  | 				this.testActionGen1() | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var TestActions2 =  | 
					
						
							|  |  |  | 	module.TestActions2 =  | 
					
						
							|  |  |  | 	Actions(TestActions, { | 
					
						
							|  |  |  | 		// NOTE: this looks like an action and feels like an action but 
 | 
					
						
							|  |  |  | 		// 		actually this is a callback as an action with this name 
 | 
					
						
							|  |  |  | 		// 		already exists...
 | 
					
						
							|  |  |  | 		testActionGen1: [function(){ | 
					
						
							|  |  |  | 			console.log('  pre callback!') | 
					
						
							|  |  |  | 			return function(){ | 
					
						
							|  |  |  | 				console.log('  post callback!') | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-06 02:25:57 +04:00
										 |  |  | 	// XXX the main question here is that there is no way to know if a 
 | 
					
						
							|  |  |  | 	// 		particular action is going to be a root action or an action
 | 
					
						
							|  |  |  | 	// 		callback because we do not know if the action in the parent 
 | 
					
						
							|  |  |  | 	// 		will be available at mix time or not, and the two models 
 | 
					
						
							|  |  |  | 	// 		are different...
 | 
					
						
							|  |  |  | 	// 		XXX one way to do this is to make all code a callback and 
 | 
					
						
							|  |  |  | 	// 			just use the root as an event trigger...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 			...but this effectively means we are implementing 
 | 
					
						
							|  |  |  | 	// 			inheritance ourselves as the traditional name resolution
 | 
					
						
							|  |  |  | 	// 			will no longer be used, and as in the case we implement
 | 
					
						
							|  |  |  | 	// 			MRO why not go the whole way and implement multiple 
 | 
					
						
							|  |  |  | 	// 			inheritance in the first place...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 			...let's try and avoid this...
 | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	var TestActionMixin = | 
					
						
							|  |  |  | 	module.TestActionMixin =  | 
					
						
							|  |  |  | 	ActionMixin({ | 
					
						
							|  |  |  | 		// XXX
 | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	console.log('TestActions.testActionGen1()') | 
					
						
							|  |  |  | 	TestActions.testActionGen1() | 
					
						
							|  |  |  | 	console.log('TestActions.testActionGen2()') | 
					
						
							|  |  |  | 	TestActions.testActionGen2() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 	// both of these should cet a callback...
 | 
					
						
							|  |  |  | 	console.log('TestActions2.testActionGen1()') | 
					
						
							|  |  |  | 	TestActions2.testActionGen1() | 
					
						
							|  |  |  | 	console.log('TestActions2.testActionGen2()') | 
					
						
							|  |  |  | 	TestActions2.testActionGen2() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// and an event-like handler...
 | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | 	TestActions2.on('testActionGen1.post',  | 
					
						
							|  |  |  | 			function(){ console.log('  post handler! (first defined)') }) | 
					
						
							|  |  |  | 	TestActions2.on('testActionGen1',  | 
					
						
							|  |  |  | 			function(){ console.log('  post handler! (last defined)') }) | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	console.log('TestActions2.testActionGen1()') | 
					
						
							|  |  |  | 	TestActions2.testActionGen1() | 
					
						
							| 
									
										
										
										
											2014-10-06 03:14:11 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	TestActions2.on('testActionGen2.pre',  | 
					
						
							|  |  |  | 			function(){ console.log('  pre handler! (first defined)') }) | 
					
						
							|  |  |  | 	TestActions2.on('testActionGen2.pre',  | 
					
						
							|  |  |  | 			function(){ console.log('  pre handler! (last defined)') }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	console.log('TestActions2.testActionGen2()') | 
					
						
							|  |  |  | 	TestActions2.testActionGen2() | 
					
						
							| 
									
										
										
										
											2014-10-04 01:39:05 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                                                */ | 
					
						
							|  |  |  | return module }) |