| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							| 
									
										
										
										
											2016-08-21 01:52:45 +03:00
										 |  |  | ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)( | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | function(require){ var module={} // makes module AMD/node compatible...
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 01:44:50 +03:00
										 |  |  | var object = require('ig-object') | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 01:27:20 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var args2array = function(a){ return [].slice.call(a) }  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-26 23:45:26 +03:00
										 |  |  | var UNDEFINED = | 
					
						
							|  |  |  | module.UNDEFINED = ['undefined placeholder'] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 01:27:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 01:44:50 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | // Actions
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Actions are an extension to the JavaScript object model tailored for
 | 
					
						
							|  |  |  | // a set of specific tasks.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Goals:
 | 
					
						
							|  |  |  | // 	- provide a unified mechanism to define and manage user API's for 
 | 
					
						
							|  |  |  | // 	  use in UI-hooks, keyboard mappings, scripting, ... etc.
 | 
					
						
							|  |  |  | // 	- a means to generate configuration UI's
 | 
					
						
							|  |  |  | // 	- a means to generate documentation
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The main entities:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	Action set
 | 
					
						
							|  |  |  | // 		- an object containing a number of actions,
 | 
					
						
							|  |  |  | // 		- optionally, directly or indirectly inherited from MetaActions
 | 
					
						
							|  |  |  | // 		  and/or other action sets,
 | 
					
						
							|  |  |  | // 		- the action handlers are bound relative to it (._action_handlers)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	Action
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //								+  pre	+  pre	+		+  post	+  post	+
 | 
					
						
							|  |  |  | //		Action event handler:	o-------x						o-------x
 | 
					
						
							|  |  |  | //										v						^
 | 
					
						
							|  |  |  | //		Actions							o-------x		o-------x
 | 
					
						
							|  |  |  | //												v		^
 | 
					
						
							|  |  |  | //		Root Action								o---|---x
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		- a method, created by Action(..),
 | 
					
						
							|  |  |  | // 		- calls all the shadowed/overloaded actions in the inheritance 
 | 
					
						
							|  |  |  | // 		  chain in sequence implicitly,
 | 
					
						
							|  |  |  | // 		  NOTE: there is no way to prevent an action in the chain from
 | 
					
						
							|  |  |  | // 		  		running, this is by design, i.e. no way to fully shadow.
 | 
					
						
							|  |  |  | // 		- actions that do not shadow anything are called root actions.
 | 
					
						
							|  |  |  | // 		- returns the action set by default (for call chaining),
 | 
					
						
							|  |  |  | // 		- the base/root action can return any value.
 | 
					
						
							|  |  |  | // 		  NOTE: if undefined is returned, it will be replaced by the 
 | 
					
						
							|  |  |  | // 		  		action context/action set.
 | 
					
						
							|  |  |  | // 		  NOTE: there is no distinction between root and other actions
 | 
					
						
							|  |  |  | // 		  		other than that root action's return values are not 
 | 
					
						
							|  |  |  | // 		  		ignored.
 | 
					
						
							|  |  |  | // 		- can consist of two parts: the first is called before the 
 | 
					
						
							|  |  |  | // 		  shadowed action (pre-callback) and the second after (post-callback).
 | 
					
						
							|  |  |  | // 		- post-callback has access to the return value and can modify it
 | 
					
						
							|  |  |  | // 		  but not replace it.
 | 
					
						
							|  |  |  | // 		- can be bound to, a-la an event, calling the handlers when it is 
 | 
					
						
							|  |  |  | // 		  called, 
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	Action (event) handler
 | 
					
						
							|  |  |  | //  	- a function,
 | 
					
						
							|  |  |  | // 		- can be bound to run before and/or after the action itself,
 | 
					
						
							|  |  |  | // 		- is local to an action set it was bound via,
 | 
					
						
							|  |  |  | // 		- when an action is triggered from an action set, all the pre 
 | 
					
						
							|  |  |  | // 		  handlers in its inheritance chain will be called before the 
 | 
					
						
							|  |  |  | // 		  respective actions they are bound to and all the post handlers
 | 
					
						
							|  |  |  | // 		  are called directly after.
 | 
					
						
							|  |  |  | // 		- pre handlers are passed the same arguments the original actions
 | 
					
						
							|  |  |  | // 		  got when it was called.
 | 
					
						
							|  |  |  | // 		- post action handlers will get the root action result as first 
 | 
					
						
							|  |  |  | // 		  argument succeeded by the action arguments.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The action system main protocols:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 1) Documentation generation and introspection (MetaActions)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		<action>.toString()
 | 
					
						
							|  |  |  | // 				-> code of original action function
 | 
					
						
							|  |  |  | // 	
 | 
					
						
							|  |  |  | // 		<action-set>.getDoc()
 | 
					
						
							|  |  |  | // 		<action-set>.getDoc(<action-name>[, ..])
 | 
					
						
							|  |  |  | // 				-> dict of action-name, doc
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		<action-set>.a.getHandlerDocStr(<action-name>)
 | 
					
						
							|  |  |  | // 				-> formated string of action handlers
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		<action-set>.actions
 | 
					
						
							|  |  |  | // 				-> list of action names
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		<action-set>.length
 | 
					
						
							|  |  |  | // 				-> number of actions
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 2) Event-like callbacks for actions (MetaActions, Action)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		<action-set>.on('action', function(){ ... })
 | 
					
						
							|  |  |  | // 		<action-set>.on('action.post', function(){ ... })
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		<action-set>.on('action.pre', function(){ ... })
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 3) A mechanism to define and extend already defined actions
 | 
					
						
							|  |  |  | // 	This replaces / complements the standard JavaScript overloading 
 | 
					
						
							|  |  |  | // 	mechanisms (Action, Actions)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// Actions...
 | 
					
						
							|  |  |  | // 		var X = Actions({
 | 
					
						
							|  |  |  | // 			m: [function(){ console.log('m') }]
 | 
					
						
							|  |  |  | // 		})
 | 
					
						
							|  |  |  | // 		var O = Actions(X, {
 | 
					
						
							|  |  |  | // 			m: [function(){
 | 
					
						
							|  |  |  | // 				console.log('pre')
 | 
					
						
							|  |  |  | // 				return function(res){
 | 
					
						
							|  |  |  | // 					console.log('post')
 | 
					
						
							|  |  |  | // 				}
 | 
					
						
							|  |  |  | // 			}]
 | 
					
						
							|  |  |  | // 		})
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	NOTE: what is done here is similar to calling O.__proto__.m.call(..)
 | 
					
						
							|  |  |  | //		but is implicit, and not dependant on the original containing 
 | 
					
						
							|  |  |  | //		object name/reference ('O'), thus enabling an action to be 
 | 
					
						
							|  |  |  | //		referenced and called from any object and still chain correctly.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Secondary action protocols:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 1) A mechanism to manually call the pre/post stages of an action
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // 		Pre phase...
 | 
					
						
							|  |  |  | // 		 <action>.pre(<context>)
 | 
					
						
							|  |  |  | // 		 <action>.pre(<context>, [<arg>, ..])
 | 
					
						
							|  |  |  | // 			-> <call-data>
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		Post phase...
 | 
					
						
							|  |  |  | // 		 <action>.post(<context>, <call-data>)
 | 
					
						
							|  |  |  | // 			-> <result>
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	This is internally used to implement the action call as well as the
 | 
					
						
							|  |  |  | // 	chaining callbacks (see below).
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	All action protocol details apply.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	NOTE: there is not reliable way to call the post phase without first
 | 
					
						
							|  |  |  | // 		calling the pre phase due to how the pre phase is defined (i.e.
 | 
					
						
							|  |  |  | // 		pre phase functions can return post phase functions).
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 2) A mechanism to chain/wrap actions or an action and a function.
 | 
					
						
							|  |  |  | // 	This enables us to call a callback or another action (inner) between 
 | 
					
						
							|  |  |  | // 	the root action's (outer) pre and post stages.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		Outer action				o-------x		o-------x
 | 
					
						
							|  |  |  | //											v		^
 | 
					
						
							|  |  |  | //		Inner action/callback				o---|---x
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	A trivial example:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		actionSet.someAction.chainApply(actionsSet, 
 | 
					
						
							|  |  |  | //			function(){
 | 
					
						
							|  |  |  | //				// this gets run between someAction's pre and post 
 | 
					
						
							|  |  |  | //				// stages...
 | 
					
						
							|  |  |  | //			}, 
 | 
					
						
							|  |  |  | //			args)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	This is intended to implement protocols where a single action is
 | 
					
						
							|  |  |  | //	intended to act as a hook point (outer) and multiple different 
 | 
					
						
							|  |  |  | //	implementations (inner) within a single action set can be used as
 | 
					
						
							|  |  |  | //	entry points.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		// Protocol root action (outer) definition...
 | 
					
						
							|  |  |  | //		protocolAction: [function(){}],
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		// Implementation actions (inner)...
 | 
					
						
							|  |  |  | //		implementationAction1: [function(){
 | 
					
						
							|  |  |  | //			return this.protocolAction.chainApply(this, function(){
 | 
					
						
							|  |  |  | //				// ...
 | 
					
						
							|  |  |  | //			}, ..)
 | 
					
						
							|  |  |  | //		}]
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		implementationAction2: [function(){
 | 
					
						
							|  |  |  | //			return this.protocolAction.chainApply(this, function(){
 | 
					
						
							|  |  |  | //				// ...
 | 
					
						
							|  |  |  | //			}, ..)
 | 
					
						
							|  |  |  | //		}]
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	Now calling any of the 'implementation' actions will execute code
 | 
					
						
							|  |  |  | //	in the following order:
 | 
					
						
							|  |  |  | //		1) pre phase of protocol action (outer)
 | 
					
						
							|  |  |  | //		2) implementation action (inner)
 | 
					
						
							|  |  |  | //		3) post phase of protocol action (outer)
 | 
					
						
							| 
									
										
										
										
											2016-11-07 18:15:53 +03:00
										 |  |  | //	
 | 
					
						
							|  |  |  | //	Differences form the base action protocol:
 | 
					
						
							|  |  |  | //		- returning undefined from inner will keep the outer return value.
 | 
					
						
							|  |  |  | //		  ...this is different from the base action protocol where returning
 | 
					
						
							|  |  |  | //		  undefined will get replaces by the context (this), here to 
 | 
					
						
							|  |  |  | //		  guarantee returning the context, it should be returned explicitly,
 | 
					
						
							|  |  |  | //		  otherwise the responsibility is shifted to the outer action.
 | 
					
						
							|  |  |  | //		- returning anything else will override the outer return
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | //	NOTE: this will not affect to protocol/signature of the outer action
 | 
					
						
							| 
									
										
										
										
											2016-11-07 18:15:53 +03:00
										 |  |  | //		in any way other than the ability to override the return value.
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | //	NOTE: both the inner and outer actions will get passed the same 
 | 
					
						
							|  |  |  | //		arguments.
 | 
					
						
							|  |  |  | //	NOTE: another use-case is testing/debugging actions.
 | 
					
						
							|  |  |  | //	NOTE: this is effectively the inside-out of normal action overloading.
 | 
					
						
							|  |  |  | //	NOTE: there is intentionally no shorthand for this feature, to avoid 
 | 
					
						
							|  |  |  | //		confusion and to discourage the use of this feature unless
 | 
					
						
							|  |  |  | //		really necessary.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 3) .__call__ action / handler
 | 
					
						
							|  |  |  | // 	This action if defined is called for every action called. It behaves
 | 
					
						
							|  |  |  | // 	like any other action but with a fixed signature, it always receives 
 | 
					
						
							|  |  |  | // 	the action name as first argument and a list of action arguments as
 | 
					
						
							|  |  |  | // 	the second arguments, and as normal a result on the post phase.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	NOTE: it is not necessary to define the actual action, binding to a
 | 
					
						
							|  |  |  | // 		handler will also work.
 | 
					
						
							|  |  |  | // 	NOTE: one should not call actions directly from within a __call__ 
 | 
					
						
							|  |  |  | // 		handler as that will result in infinite recursion.
 | 
					
						
							|  |  |  | // 		XXX need a way to prevent this...
 | 
					
						
							|  |  |  | // 	NOTE: one should use this with extreme care as this will introduce 
 | 
					
						
							|  |  |  | // 		an overhead on all the actions if not done carefully.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | // helpers...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var normalizeTabs = function(str){ | 
					
						
							|  |  |  | 	str = str.split(/\n/g) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// get min number of leading tabs...
 | 
					
						
							|  |  |  | 	var i = str.length == 2 && /^\t/.test(str[1]) ? | 
					
						
							|  |  |  | 		str[1].split(/^(\t+)/)[1].length - 1 | 
					
						
							|  |  |  | 		: Math.min.apply(null, str | 
					
						
							|  |  |  | 			// skip first line...
 | 
					
						
							|  |  |  | 			.slice(1) | 
					
						
							|  |  |  | 			// skip empty strings...
 | 
					
						
							|  |  |  | 			.filter(function(l){ return l.trim() != '' }) | 
					
						
							|  |  |  | 			// count leading tabs...
 | 
					
						
							|  |  |  | 			.map(function(l){  | 
					
						
							|  |  |  | 				return /^\t+/.test(l) ?  | 
					
						
							|  |  |  | 					l.split(/^(\t+)/)[1].length | 
					
						
							|  |  |  | 					: 0})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return (str[0] +'\n'  | 
					
						
							|  |  |  | 		+ str | 
					
						
							|  |  |  | 			.slice(1) | 
					
						
							|  |  |  | 			// trim leading tabs...
 | 
					
						
							|  |  |  | 			.map(function(l){ return l.slice(i) }).join('\n') | 
					
						
							|  |  |  | 			// replace tabs...
 | 
					
						
							|  |  |  | 			.replace(/\t/g, '    ')) | 
					
						
							|  |  |  | 		// remove leading and trailing whitespace...
 | 
					
						
							|  |  |  | 		.trim() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var doWithRootAction =  | 
					
						
							|  |  |  | module.doWithRootAction =  | 
					
						
							|  |  |  | function(func){ | 
					
						
							| 
									
										
										
										
											2016-08-21 01:27:20 +03:00
										 |  |  | 	return function(){ | 
					
						
							|  |  |  | 		var args = args2array(arguments) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 		var handlers = (this.getHandlerList  | 
					
						
							|  |  |  | 				|| MetaActions.getHandlerList) | 
					
						
							| 
									
										
										
										
											2016-08-21 01:27:20 +03:00
										 |  |  | 			.apply(this, args) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 01:27:20 +03:00
										 |  |  | 		return func.apply(this, [handlers.pop()].concat(args)) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Construct an action object...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:54:20 +03:00
										 |  |  | // 	Action(<name>, <function>)
 | 
					
						
							|  |  |  | // 	Action(<name>[, <doc>[, <long-doc>]][, <attrs>,] <function>)
 | 
					
						
							|  |  |  | // 	Action(<name>, [ [<doc>[, <long-doc>]][, <attrs>,] <function> ])
 | 
					
						
							|  |  |  | // 		-> <action>
 | 
					
						
							|  |  |  | // 	
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | // Action function format:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// pre event code...
 | 
					
						
							|  |  |  | // 		function(..){
 | 
					
						
							|  |  |  | //			... // pre code
 | 
					
						
							|  |  |  | // 		}
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// pre/post event code...
 | 
					
						
							|  |  |  | // 		function(..){
 | 
					
						
							|  |  |  | //			... // pre code
 | 
					
						
							|  |  |  | //			return function(<return>, ..){
 | 
					
						
							|  |  |  | //				... // post code
 | 
					
						
							|  |  |  | //			}
 | 
					
						
							|  |  |  | // 		}
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 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
 | 
					
						
							| 
									
										
										
										
											2016-09-15 21:46:57 +03:00
										 |  |  | // 		post:	if the action returns a callback function it will be 
 | 
					
						
							|  |  |  | // 				executed after the event is fired
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | // 				NOTE: the signature if the post stage is the same as the
 | 
					
						
							|  |  |  | // 					action's with the added return value as first argument
 | 
					
						
							|  |  |  | // 					(the rest og the arguments are shifted by 1).
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	- 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.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	- an action will return the deepest (root) action's return, if that 
 | 
					
						
							|  |  |  | // 	  return is undefined, then the action set is returned instead.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	- action arguments are "threaded" through the action chain down and 
 | 
					
						
							|  |  |  | // 	  root action return value and arguments are threaded back up the 
 | 
					
						
							|  |  |  | // 	  action chain.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: actions once defined do not depend on the inheritance hierarchy, 
 | 
					
						
							|  |  |  | // 		other than the .getHandlerList(..) method. If this method is not 
 | 
					
						
							|  |  |  | // 		found in the inheritance chain (i.e. the link to MetaActions)
 | 
					
						
							|  |  |  | // 		was severed, then the default will be used: 
 | 
					
						
							|  |  |  | // 			MetaActions.getHandlerList(..)
 | 
					
						
							|  |  |  | // 		This makes it possible to redefine the method if needed but 
 | 
					
						
							|  |  |  | // 		prevents the system from breaking when an action set gets 
 | 
					
						
							|  |  |  | // 		disconnected from MetaActions. This can be useful, for example,
 | 
					
						
							|  |  |  | // 		to remove .on(..) / .off(..) handler functionality.
 | 
					
						
							|  |  |  | // 		XXX is this correct??
 | 
					
						
							|  |  |  | // NOTE: by default an action will return 'this', i.e. the action set
 | 
					
						
							|  |  |  | // 		object the action was called from.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // XXX add more metadata/docs:
 | 
					
						
							|  |  |  | // 		.section
 | 
					
						
							|  |  |  | // 		.category
 | 
					
						
							|  |  |  | // 		...
 | 
					
						
							|  |  |  | // XXX might be a good idea to add an option to return the full results...
 | 
					
						
							|  |  |  | var Action = | 
					
						
							|  |  |  | module.Action = | 
					
						
							| 
									
										
										
										
											2017-02-18 06:54:20 +03:00
										 |  |  | function Action(name, doc, ldoc, attrs, func){ | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// 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...
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:54:20 +03:00
										 |  |  | 		return new Action(name, doc, ldoc, attrs, func) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// prevent action overloading...
 | 
					
						
							|  |  |  | 	if(this[name] != null){ | 
					
						
							|  |  |  | 		throw 'action "'+name+'" already exists.' | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// create the actual instance we will be returning...
 | 
					
						
							|  |  |  | 	var meth = function(){ | 
					
						
							|  |  |  | 		return meth.chainApply(this, null, arguments) } | 
					
						
							|  |  |  | 	meth.__proto__ = this.__proto__ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:54:20 +03:00
										 |  |  | 	// precess args...
 | 
					
						
							|  |  |  | 	var args = doc instanceof Array ?  | 
					
						
							|  |  |  | 		doc  | 
					
						
							|  |  |  | 		: [].slice.call(arguments) | 
					
						
							|  |  |  | 			.filter(function(e){ return e !== undefined }) | 
					
						
							|  |  |  | 			.slice(1) | 
					
						
							|  |  |  | 	func = args.pop() | 
					
						
							|  |  |  | 	last = args[args.length-1] | 
					
						
							|  |  |  | 	attrs = last != null && typeof(last) != typeof('str') ? args.pop() : {} | 
					
						
							|  |  |  | 	doc = typeof(args[0]) == typeof('str') ? args.shift() : null | 
					
						
							|  |  |  | 	ldoc = typeof(args[0]) == typeof('str') ? args.shift() : null | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// populate the action attributes...
 | 
					
						
							|  |  |  | 	//meth.name = name
 | 
					
						
							|  |  |  | 	Object.defineProperty(meth, 'name', { | 
					
						
							|  |  |  | 		value: name, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	meth.doc = doc | 
					
						
							|  |  |  | 	meth.long_doc = ldoc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	meth.func = func | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// make introspection be a bit better...
 | 
					
						
							|  |  |  | 	meth.toString = func.toString.bind(func) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:54:20 +03:00
										 |  |  | 	// setup attrs...
 | 
					
						
							|  |  |  | 	Object.keys(attrs) | 
					
						
							|  |  |  | 		.forEach(function(k){ meth[k] = attrs[k] }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	return meth | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | // this will make action instances behave like real functions...
 | 
					
						
							|  |  |  | Action.prototype.__proto__ = Function | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // The pre/post stage runners...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	.pre(context, args)	
 | 
					
						
							|  |  |  | // 		-> data
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	.post(context, data)
 | 
					
						
							|  |  |  | // 		-> result
 | 
					
						
							| 
									
										
										
										
											2017-01-18 23:05:48 +03:00
										 |  |  | // 		
 | 
					
						
							|  |  |  | // 		
 | 
					
						
							|  |  |  | // Call data format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							|  |  |  | //		arguments: args,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		wrapper: call_wrapper,
 | 
					
						
							|  |  |  | //		handlers: handlers,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		result: res,
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: All the defaults should be handled by the pre stage, post will 
 | 
					
						
							|  |  |  | // 		process data assuming that it is correct.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // XXX revise the structure....
 | 
					
						
							|  |  |  | // 		...is it a better idea to define action methods in an object 
 | 
					
						
							|  |  |  | // 		and assign that???
 | 
					
						
							|  |  |  | Action.prototype.pre = function(context, args){ | 
					
						
							|  |  |  | 	args = args || [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var res = context | 
					
						
							|  |  |  | 	var outer = this.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// get the handler list...
 | 
					
						
							| 
									
										
										
										
											2016-08-21 01:27:20 +03:00
										 |  |  | 	var getHandlers = context.getHandlers || MetaActions.getHandlers | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	var handlers = getHandlers.call(context, outer) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 01:27:20 +03:00
										 |  |  | 	// special case: see if we need to handle the call without handlers...
 | 
					
						
							|  |  |  | 	var preActionHandler = context.preActionHandler || MetaActions.preActionHandler | 
					
						
							|  |  |  | 	if(preActionHandler){ | 
					
						
							|  |  |  | 		// XXX signature needs work...
 | 
					
						
							|  |  |  | 		var res = preActionHandler.call(context, outer, handlers, args) | 
					
						
							|  |  |  | 		if(res !== undefined){ | 
					
						
							|  |  |  | 			return res | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var call_wrapper = outer != '__call__' ?  | 
					
						
							|  |  |  | 		getHandlers.call(context, '__call__')  | 
					
						
							|  |  |  | 		: [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// wrapper handlers: pre phase...
 | 
					
						
							|  |  |  | 	call_wrapper = call_wrapper | 
					
						
							|  |  |  | 		.map(function(a){ | 
					
						
							|  |  |  | 			if(a.pre){ | 
					
						
							|  |  |  | 				res = a.pre.call(context, outer, args) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-15 21:55:21 +03:00
										 |  |  | 				// if a handler returns a function register is as a post
 | 
					
						
							|  |  |  | 				// handler...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 				if(res  | 
					
						
							|  |  |  | 						&& res !== context  | 
					
						
							| 
									
										
										
										
											2016-09-15 21:46:57 +03:00
										 |  |  | 						&& res instanceof Function){ | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 					a.post = res | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return a | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// handlers: pre phase...
 | 
					
						
							|  |  |  | 	handlers | 
					
						
							|  |  |  | 		// NOTE: current action will get included and called by the code 
 | 
					
						
							|  |  |  | 		// 		above and below, so no need to explicitly call func...
 | 
					
						
							|  |  |  | 		// NOTE: pre handlers are called FIFO, i.e. the last defined first... 
 | 
					
						
							|  |  |  | 		.map(function(a){ | 
					
						
							|  |  |  | 			if(a.pre){ | 
					
						
							|  |  |  | 				res = a.pre.apply(context, args) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-15 21:55:21 +03:00
										 |  |  | 				// if a handler returns a function register is as a post
 | 
					
						
							|  |  |  | 				// handler...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 				if(res  | 
					
						
							|  |  |  | 						&& res !== context  | 
					
						
							| 
									
										
										
										
											2016-09-15 21:46:57 +03:00
										 |  |  | 						&& res instanceof Function){ | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 					a.post = res | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// reset the result...
 | 
					
						
							| 
									
										
										
										
											2016-09-26 23:45:26 +03:00
										 |  |  | 					// NOTE: this is the only difference between this 
 | 
					
						
							|  |  |  | 					// 		and wrapper stages...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 					res = context | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return a | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// return context if nothing specific is returned...
 | 
					
						
							| 
									
										
										
										
											2016-09-26 23:55:59 +03:00
										 |  |  | 	res = res === undefined ? context  | 
					
						
							|  |  |  | 		: res === UNDEFINED ? undefined  | 
					
						
							|  |  |  | 		: res | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return { | 
					
						
							|  |  |  | 		arguments: args, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		wrapper: call_wrapper, | 
					
						
							|  |  |  | 		handlers: handlers, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		result: res, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | Action.prototype.post = function(context, data){ | 
					
						
							|  |  |  | 	var res = data.result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var args = data.arguments || [] | 
					
						
							|  |  |  | 	// the post handlers get the result as the first argument...
 | 
					
						
							|  |  |  | 	args.splice(0, 0, res) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var outer = this.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// handlers: post phase...
 | 
					
						
							|  |  |  | 	data.handlers && data.handlers | 
					
						
							|  |  |  | 		// NOTE: post handlers are called LIFO -- last defined last...
 | 
					
						
							|  |  |  | 		.reverse() | 
					
						
							|  |  |  | 		.forEach(function(a){ | 
					
						
							|  |  |  | 			a.post | 
					
						
							| 
									
										
										
										
											2016-09-15 21:46:57 +03:00
										 |  |  | 				&& a.post.apply(context, args) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// wrapper handlers: post phase...
 | 
					
						
							|  |  |  | 	data.wrapper && data.wrapper | 
					
						
							|  |  |  | 		// NOTE: post handlers are called LIFO -- last defined last...
 | 
					
						
							|  |  |  | 		.reverse() | 
					
						
							|  |  |  | 		.forEach(function(a){ | 
					
						
							|  |  |  | 			a.post | 
					
						
							| 
									
										
										
										
											2016-09-15 21:46:57 +03:00
										 |  |  | 				&& a.post.call(context, res, outer, args.slice(1)) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Chaining...
 | 
					
						
							| 
									
										
										
										
											2016-11-07 18:15:53 +03:00
										 |  |  | // 
 | 
					
						
							|  |  |  | // For docs see: MetaActions.chainApply(..) and the base module doc.
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | Action.prototype.chainApply = function(context, inner, args){ | 
					
						
							|  |  |  | 	args = [].slice.call(args || []) | 
					
						
							|  |  |  | 	var outer = this.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var data = this.pre(context, args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// call the inner action/function if preset....
 | 
					
						
							| 
									
										
										
										
											2016-11-08 06:30:23 +03:00
										 |  |  | 	// NOTE: this is slightly different (see docs) to what happens in 
 | 
					
						
							|  |  |  | 	// 		.pre(..)/.post(..), thus we are doing this separately and 
 | 
					
						
							|  |  |  | 	// 		not reusing existing code...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	if(inner){ | 
					
						
							| 
									
										
										
										
											2016-11-07 18:15:53 +03:00
										 |  |  | 		var res = inner instanceof Function ?  | 
					
						
							|  |  |  | 				inner.apply(context, args) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 			: inner instanceof Array && inner.length > 0 ?  | 
					
						
							| 
									
										
										
										
											2016-11-07 18:15:53 +03:00
										 |  |  | 				context[inner.pop()].chainApply(context, inner, args) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 			: typeof(inner) == typeof('str') ? | 
					
						
							| 
									
										
										
										
											2016-11-07 18:15:53 +03:00
										 |  |  | 				context[inner].chainApply(context, null, args) | 
					
						
							|  |  |  | 			: undefined | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-08 05:11:02 +03:00
										 |  |  | 		// call the resulting function...
 | 
					
						
							|  |  |  | 		if(res instanceof Function){ | 
					
						
							|  |  |  | 			res.apply(context, [context].concat(args)) | 
					
						
							|  |  |  | 			data.result = context | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 18:15:53 +03:00
										 |  |  | 		// push the inner result into the chian...
 | 
					
						
							| 
									
										
										
										
											2016-11-08 05:11:02 +03:00
										 |  |  | 		} else if(res !== undefined){ | 
					
						
							| 
									
										
										
										
											2016-11-07 18:15:53 +03:00
										 |  |  | 			data.result = res | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return this.post(context, data) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | Action.prototype.chainCall = function(context, inner){ | 
					
						
							|  |  |  | 	return this.chainApply(context, inner, args2array(arguments).slice(2)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A base action-set object...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This will define a set of action-set specific methods and helpers.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // XXX .off(...) needs more work...
 | 
					
						
							|  |  |  | // XXX need a mechanism to publish specific attrs...
 | 
					
						
							|  |  |  | var MetaActions = | 
					
						
							|  |  |  | module.MetaActions = { | 
					
						
							|  |  |  | 	// List actions...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	get actions(){ | 
					
						
							|  |  |  | 		var res = [] | 
					
						
							|  |  |  | 		for(var k in this){ | 
					
						
							|  |  |  | 			// avoid recursion, skip props...
 | 
					
						
							|  |  |  | 			var cur = this | 
					
						
							|  |  |  | 			var prop = Object.getOwnPropertyDescriptor(cur, k) | 
					
						
							|  |  |  | 			while(!prop && cur.__proto__ != null){ | 
					
						
							|  |  |  | 				var cur = cur.__proto__ | 
					
						
							|  |  |  | 				var prop = Object.getOwnPropertyDescriptor(cur, k) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if(prop.get != null){ | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			//if(k == 'actions' || k == 'length'){
 | 
					
						
							|  |  |  | 			//	continue
 | 
					
						
							|  |  |  | 			//}
 | 
					
						
							|  |  |  | 			// get only actions...
 | 
					
						
							|  |  |  | 			if(this[k] instanceof Action){ | 
					
						
							|  |  |  | 				res.push(k) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-30 03:19:12 +03:00
										 |  |  | 	// Get action attribute...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-02-19 05:18:29 +03:00
										 |  |  | 	// NOTE: this will get attribute set both on the action object and 
 | 
					
						
							|  |  |  | 	// 		the action function, this covers two usecases:
 | 
					
						
							|  |  |  | 	// 		1) action constructor attributes...
 | 
					
						
							|  |  |  | 	// 			someAction: ['...',
 | 
					
						
							|  |  |  | 	// 				// action attribute...
 | 
					
						
							|  |  |  | 	// 				{attr: 'value'},
 | 
					
						
							|  |  |  | 	// 				function(){ ... }],
 | 
					
						
							|  |  |  | 	// 		2) action modifiers... 
 | 
					
						
							|  |  |  | 	// 			var modifyAction = function(func){
 | 
					
						
							|  |  |  | 	// 				// function attribute...
 | 
					
						
							|  |  |  | 	// 				func.attr = 'value'
 | 
					
						
							|  |  |  | 	// 				return func
 | 
					
						
							|  |  |  | 	// 			}
 | 
					
						
							|  |  |  | 	//			...
 | 
					
						
							|  |  |  | 	// 			someAction: ['...',
 | 
					
						
							|  |  |  | 	// 				modifyAction(function(){ ... })],
 | 
					
						
							| 
									
										
										
										
											2017-01-02 19:42:56 +03:00
										 |  |  | 	getActionAttr: function(action, attr){ | 
					
						
							| 
									
										
										
										
											2016-12-30 03:19:12 +03:00
										 |  |  | 		var cur = this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// go up the proto chain...
 | 
					
						
							|  |  |  | 		while(cur.__proto__ != null){ | 
					
						
							| 
									
										
										
										
											2017-02-19 05:18:29 +03:00
										 |  |  | 			if(cur[action] != null){ | 
					
						
							|  |  |  | 				// attribute of action...
 | 
					
						
							|  |  |  | 				if(cur[action][attr] !== undefined){ | 
					
						
							|  |  |  | 					return cur[action][attr] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// attribute of action function...
 | 
					
						
							|  |  |  | 				} else if(cur[action].func && cur[action].func[attr] !== undefined){ | 
					
						
							|  |  |  | 					return cur[action].func[attr] | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-12-30 03:19:12 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			cur = cur.__proto__ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// Get action documentation...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	getDoc: function(actions){ | 
					
						
							|  |  |  | 		var res = {} | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		actions = actions == null ? this.actions | 
					
						
							|  |  |  | 			: arguments.length > 1 ? args2array(arguments) | 
					
						
							|  |  |  | 			: typeof(actions) == typeof('str') ? [actions] | 
					
						
							|  |  |  | 			: actions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// get the first defined set of docs in the inheritance chain...
 | 
					
						
							|  |  |  | 		actions.forEach(function(n){ | 
					
						
							|  |  |  | 			var cur = that | 
					
						
							|  |  |  | 			res[n] = [] | 
					
						
							|  |  |  | 			// go up the proto chain...
 | 
					
						
							|  |  |  | 			while(cur.__proto__ != null){ | 
					
						
							|  |  |  | 				if(cur[n] != null && cur[n].doc != null){ | 
					
						
							|  |  |  | 					res[n] = [ cur[n].doc, cur[n].long_doc, cur[n].name ] | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				cur = cur.__proto__ | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	getPath: function(actions){ | 
					
						
							|  |  |  | 		var res = {} | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		actions = actions == null ? this.actions | 
					
						
							|  |  |  | 			: arguments.length > 1 ? args2array(arguments) | 
					
						
							|  |  |  | 			: typeof(actions) == typeof('str') ? [actions] | 
					
						
							|  |  |  | 			: actions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// get the first defined set of docs in the inheritance chain...
 | 
					
						
							|  |  |  | 		actions.forEach(function(n){ | 
					
						
							|  |  |  | 			var cur = that | 
					
						
							|  |  |  | 			// go up the proto chain...
 | 
					
						
							|  |  |  | 			while(cur.__proto__ != null){ | 
					
						
							|  |  |  | 				if(cur[n] != null && cur[n].doc != null){ | 
					
						
							|  |  |  | 					var doc = cur[n].doc | 
					
						
							|  |  |  | 					var long_doc = cur[n].long_doc | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				cur = cur.__proto__ | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			res[(doc && doc.replace(/[\\\/]$/, '/'+n)) || n] = [n, doc, long_doc] | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 	// Toggle handler cache...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Toggle cache...
 | 
					
						
							|  |  |  | 	//	.toggleHandlerCache()
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Set caching on...
 | 
					
						
							|  |  |  | 	//	.toggleHandlerCache('on')
 | 
					
						
							|  |  |  | 	//	.toggleHandlerCache(true)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Set caching off...
 | 
					
						
							|  |  |  | 	//	.toggleHandlerCache('off')
 | 
					
						
							|  |  |  | 	//	.toggleHandlerCache(false)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Reset caching...
 | 
					
						
							|  |  |  | 	//	.toggleHandlerCache('!')
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Get current caching state...
 | 
					
						
							|  |  |  | 	//	.toggleHandlerCache('?')
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Get supported states...
 | 
					
						
							|  |  |  | 	//	.toggleHandlerCache('??')
 | 
					
						
							|  |  |  | 	//		-> ['on', 'off']
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: setting the cache on may prevent calling of actions event
 | 
					
						
							|  |  |  | 	// 		handlers of parent action-sets if they are added (via .on(..)
 | 
					
						
							|  |  |  | 	// 		or .one(..), ...) AFTER the current object cloned it's cache.
 | 
					
						
							|  |  |  | 	// 		to avoid this, care must be taken to reset the cache of 
 | 
					
						
							|  |  |  | 	// 		children objects, or not use caching for cases where action
 | 
					
						
							|  |  |  | 	// 		event handlers can be added on the tree in runtime.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX EXPERIMENTAL...
 | 
					
						
							|  |  |  | 	// XXX should we use the toggler object here???
 | 
					
						
							|  |  |  | 	toggleHandlerCache: function(to){ | 
					
						
							|  |  |  | 		if(to == '?'){ | 
					
						
							|  |  |  | 			return this.__handler_cache ? 'on' : 'off' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else if(to == '??'){ | 
					
						
							|  |  |  | 			return ['on', 'off'] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		to = (to === true || to == 'on') ? true | 
					
						
							|  |  |  | 			: (to === false || to == 'off') ? false | 
					
						
							|  |  |  | 			: to == '!' ? !!this.__handler_cache | 
					
						
							|  |  |  | 			: !this.__handler_cache  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(to){ | 
					
						
							|  |  |  | 			// no local cache -> copy from parent...
 | 
					
						
							|  |  |  | 			if(this.__handler_cache  | 
					
						
							|  |  |  | 					&& !Object.hasOwnProperty(this, '__handler_cache')){ | 
					
						
							|  |  |  | 				var parent = this.__handler_cache | 
					
						
							|  |  |  | 				var cache = this.__handler_cache = {} | 
					
						
							|  |  |  | 				for(var a in parent){ | 
					
						
							|  |  |  | 					cache[a] = parent[a] | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// local cache only...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				this.__handler_cache = this.__handler_cache || {} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// NOTE: we do not delete here so as to shadow the parent's 
 | 
					
						
							|  |  |  | 			// 		cache...
 | 
					
						
							|  |  |  | 			this.__handler_cache = false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-11 05:13:50 +03:00
										 |  |  | 		// XXX this is not the handler protocol...
 | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Rest handler cache...
 | 
					
						
							|  |  |  | 	// 	
 | 
					
						
							|  |  |  | 	// 	Reset the full cache...
 | 
					
						
							|  |  |  | 	// 	.resetHandlerCache()
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Reset handler cache for action...
 | 
					
						
							|  |  |  | 	// 	.resetHandlerCache(action)
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: when .toggleHandlerCache('?') is 'off' this has no effect.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX EXPERIMENTAL...
 | 
					
						
							|  |  |  | 	resetHandlerCache: function(name){ | 
					
						
							|  |  |  | 		var cache = this.__handler_cache | 
					
						
							|  |  |  | 		if(cache){ | 
					
						
							|  |  |  | 			// full reset...
 | 
					
						
							|  |  |  | 			if(name == null){ | 
					
						
							|  |  |  | 				this.__handler_cache = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// reset action...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				// no local cache -> copy from parent...
 | 
					
						
							|  |  |  | 				if(!Object.hasOwnProperty(this, '__handler_cache')){ | 
					
						
							|  |  |  | 					var parent = this.__handler_cache | 
					
						
							|  |  |  | 					var cache = this.__handler_cache = {} | 
					
						
							|  |  |  | 					for(var a in parent){ | 
					
						
							|  |  |  | 						cache[a] = parent[a] | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				delete cache[name] | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// Get action handlers from the inheritance chain...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this collects both the event handlers (in order of hierarchy,
 | 
					
						
							|  |  |  | 	// 		then order of definition) and actions (in order of hierarchy)
 | 
					
						
							|  |  |  | 	// NOTE: this is the correct order for 'pre' calling, but is the 
 | 
					
						
							|  |  |  | 	// 		reverse of how the 'post' handlers must be called.
 | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 	// NOTE: if .toggleHandlerCache('?') is on, this will serch once and
 | 
					
						
							|  |  |  | 	// 		return the cached results on every subsequent call.
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// For more docs on handler sequencing and definition see: .on(..)
 | 
					
						
							|  |  |  | 	getHandlerList: function(name){ | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 		// handler cache...  XXX EXPERIMENTAL...
 | 
					
						
							|  |  |  | 		var cache = this.__handler_cache | 
					
						
							|  |  |  | 		if(cache && cache[name]){ | 
					
						
							| 
									
										
										
										
											2016-10-30 04:21:31 +03:00
										 |  |  | 			return cache[name].slice() | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// get the handlers...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 		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__ | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// handler cache... XXX EXPERIMENTAL...
 | 
					
						
							|  |  |  | 		if(cache){ | 
					
						
							|  |  |  | 			cache[name] = handlers | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 		return handlers | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get structured action handler definitions...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	[
 | 
					
						
							|  |  |  | 	// 		{
 | 
					
						
							|  |  |  | 	// 			// NOTE: only one handler per level can be present, either
 | 
					
						
							|  |  |  | 	// 			//		.pre or .post, this does not mean that one can
 | 
					
						
							|  |  |  | 	// 			//		not define both, just that they are stored separately
 | 
					
						
							|  |  |  | 	// 			pre|post: <handler>,
 | 
					
						
							|  |  |  | 	// 		},
 | 
					
						
							|  |  |  | 	// 		...
 | 
					
						
							|  |  |  | 	// 	]
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX need to get parent action or definition context for each level... 
 | 
					
						
							|  |  |  | 	// XXX is this simpler to use than the original .getHandlerList(..)
 | 
					
						
							|  |  |  | 	// XXX rename this....
 | 
					
						
							|  |  |  | 	getHandlers: function(name){ | 
					
						
							|  |  |  | 		return (this.getHandlerList || MetaActions.getHandlerList).call(this, name) | 
					
						
							|  |  |  | 			.map(function(a){  | 
					
						
							|  |  |  | 				var res = { | 
					
						
							|  |  |  | 					// action doc...
 | 
					
						
							|  |  |  | 					// XXX
 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(!a.post_handler){ | 
					
						
							|  |  |  | 					res.pre = a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					res.post = a.post_handler | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return res | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 01:27:20 +03:00
										 |  |  | 	// Handler for cases when we need to avoid the pre/post handlers...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-08-21 01:27:20 +03:00
										 |  |  | 	// Returns:
 | 
					
						
							|  |  |  | 	// 	- undefined		- handle the action normally.
 | 
					
						
							|  |  |  | 	// 	- object		- bypass action handlers.
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-08-21 01:27:20 +03:00
										 |  |  | 	// NOTE: the object result must be compatible with Action.pre(..) 
 | 
					
						
							|  |  |  | 	// 		return value...
 | 
					
						
							|  |  |  | 	// NOTE: this is mostly a stub, here for documentation reasons...
 | 
					
						
							|  |  |  | 	//preActionHandler: doWithRootAction(
 | 
					
						
							|  |  |  | 	//	function(action, name, handlers, args){ return null }),
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 01:27:20 +03:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// Register an action callback...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Register a post action callback
 | 
					
						
							|  |  |  | 	// 	.on('action', [<tag>, ]<function>)
 | 
					
						
							|  |  |  | 	// 	.on('action.post', [<tag>, ]<function>)
 | 
					
						
							|  |  |  | 	// 		-> <action-set>
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Register a pre action callback
 | 
					
						
							|  |  |  | 	// 	.on('action.pre', [<tag>, ]<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.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Handler Arguments:
 | 
					
						
							|  |  |  | 	// 	'pre'		- the handler will get the same arguments as the main
 | 
					
						
							|  |  |  | 	// 					action when called.
 | 
					
						
							|  |  |  | 	// 	'post'		- the handler will get the action return value followed
 | 
					
						
							|  |  |  | 	// 					by action arguments.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// The optional tag marks the handler to enable group removal via 
 | 
					
						
							|  |  |  | 	// .off(..)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: 'post' mode is the default.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX should we have multiple tags per handler???
 | 
					
						
							|  |  |  | 	on: function(actions, b, c){ | 
					
						
							|  |  |  | 		var handler = typeof(c) == 'function' ? c : b | 
					
						
							|  |  |  | 		var tag = typeof(c) == 'function' ? b : c | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// XXX make this split by whitespace...
 | 
					
						
							|  |  |  | 		actions = typeof(actions) == 'string' ? actions.split(/ +/) : actions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		actions.forEach(function(action){ | 
					
						
							|  |  |  | 			// prepare the handler...
 | 
					
						
							|  |  |  | 			var mode = action.split('.') | 
					
						
							|  |  |  | 			action = mode[0] | 
					
						
							|  |  |  | 			mode = mode[1] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 			that.resetHandlerCache(action) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 			// keep the original handler for future use...
 | 
					
						
							|  |  |  | 			var a_handler = handler | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// a post handler (default)...
 | 
					
						
							|  |  |  | 			if(mode == null || mode == 'post'){ | 
					
						
							|  |  |  | 				var old_handler = a_handler | 
					
						
							|  |  |  | 				a_handler = function(){ return old_handler } | 
					
						
							|  |  |  | 				a_handler.post_handler = old_handler | 
					
						
							|  |  |  | 					// NOTE: this is set so as to identify the handler 
 | 
					
						
							|  |  |  | 					// 		for removal via. .off(..)
 | 
					
						
							|  |  |  | 				a_handler.orig_handler = old_handler.orig_handler || old_handler | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 				a_handler.orig_handler.event_tag = tag | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 			// not pre mode...
 | 
					
						
							|  |  |  | 			} else if(mode != 'pre') { | 
					
						
							|  |  |  | 				// XXX
 | 
					
						
							|  |  |  | 				throw 'Unknown action mode: '+action+'.'+mode | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 			a_handler.event_tag = tag | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// register handlers locally only...
 | 
					
						
							|  |  |  | 			if(!that.hasOwnProperty('_action_handlers')){ | 
					
						
							|  |  |  | 				that._action_handlers = {} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if(!(action in that._action_handlers)){ | 
					
						
							|  |  |  | 				that._action_handlers[action] = [] | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// register a handler only once...
 | 
					
						
							|  |  |  | 			if(that._action_handlers[action].indexOf(a_handler) < 0){ | 
					
						
							|  |  |  | 				// NOTE: last registered is first...
 | 
					
						
							|  |  |  | 				that._action_handlers[action].splice(0, 0, a_handler) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Remove an action callback...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Remove all handlers from action:
 | 
					
						
							|  |  |  | 	//	.off('action')
 | 
					
						
							|  |  |  | 	//	.off('action', '*')
 | 
					
						
							|  |  |  | 	//	.off('action', 'all')
 | 
					
						
							|  |  |  | 	// 		-> <action-set>
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Remove specific handler from action:
 | 
					
						
							|  |  |  | 	//	.off('action', <handler>)
 | 
					
						
							|  |  |  | 	// 		-> <action-set>
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Remove handlers from action by tag:
 | 
					
						
							|  |  |  | 	//	.off('action', <tag>)
 | 
					
						
							|  |  |  | 	// 		-> <action-set>
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: the handler passed to .off(..) for removal must be the same
 | 
					
						
							|  |  |  | 	// 		as the handler passed to .on(..) / .one(..)
 | 
					
						
							|  |  |  | 	off: function(actions, handler){ | 
					
						
							|  |  |  | 		if(this.hasOwnProperty('_action_handlers')){ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			actions = actions == '*' ? Object.keys(this._action_handlers) | 
					
						
							|  |  |  | 				: typeof(actions) == 'string' ?  actions.split(' ') | 
					
						
							|  |  |  | 				: actions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 			actions.forEach(function(action){ | 
					
						
							|  |  |  | 				var mode = action.split('.') | 
					
						
							|  |  |  | 				action = mode[0] | 
					
						
							|  |  |  | 				mode = mode[1] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 				that.resetHandlerCache(action) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 				// get the handlers...
 | 
					
						
							|  |  |  | 				var h = that._action_handlers[action] || [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// remove explicit handler...
 | 
					
						
							|  |  |  | 				if(typeof(handler) == 'function'){ | 
					
						
							|  |  |  | 					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) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// remove all handlers...
 | 
					
						
							|  |  |  | 				} else if(handler == null || handler == 'all' || handler == '*'){ | 
					
						
							|  |  |  | 					h.splice(0, h.length) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// remove handlers by tag...
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					// filter out everything that mathches a tag in-place...
 | 
					
						
							|  |  |  | 					h.splice.apply(h,  | 
					
						
							|  |  |  | 							[0, h.length] | 
					
						
							|  |  |  | 								.concat(h.filter(function(e){  | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 									return e.event_tag != handler }))) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Register an action callback that will only fire once per event...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This is signature compatible with .on(..)
 | 
					
						
							|  |  |  | 	one: function(actions, b, c){ | 
					
						
							|  |  |  | 		var _handler = typeof(c) == 'function' ? c : b | 
					
						
							|  |  |  | 		var tag = typeof(c) == 'function' ? b : c | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		actions = typeof(actions) == 'string' ? actions.split(' *') : actions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		actions.forEach(function(action){ | 
					
						
							|  |  |  | 			// NOTE: we are using both 'that' below and 'this', so as
 | 
					
						
							|  |  |  | 			// 		to separate the call context and the bind context,
 | 
					
						
							|  |  |  | 			//		.off(..) must be called at the bind context while
 | 
					
						
							|  |  |  | 			//		the actual action is called from the call context
 | 
					
						
							|  |  |  | 			// NOTE: we are not using the closure _handler below to 
 | 
					
						
							|  |  |  | 			// 		keep the code introspectable, and direct the user
 | 
					
						
							|  |  |  | 			// 		to the original function.
 | 
					
						
							|  |  |  | 			var handler = function(){ | 
					
						
							|  |  |  | 				// remove handler...
 | 
					
						
							|  |  |  | 				that.off(action, handler.orig_handler) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// call the actual supplied handler function...
 | 
					
						
							|  |  |  | 				return handler.orig_handler.apply(this, arguments) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			handler.orig_handler = _handler | 
					
						
							|  |  |  | 			that.on(action, tag, handler) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Apply/call a function/action "inside" an action...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	.chainApply(outer, inner)
 | 
					
						
							|  |  |  | 	// 	.chainApply(outer, inner, arguments)
 | 
					
						
							|  |  |  | 	// 		-> result
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	.chainCall(outer, inner)
 | 
					
						
							|  |  |  | 	// 	.chainCall(outer, inner, ..)
 | 
					
						
							|  |  |  | 	// 		-> result
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// The inner action call is completely nested as base of the outer 
 | 
					
						
							|  |  |  | 	// action.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//		Outer action		o-------x		o-------x
 | 
					
						
							|  |  |  | 	//									v		^
 | 
					
						
							|  |  |  | 	//		Inner action				o---|---x
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// The given arguments are passed as-is to both the outer and inner
 | 
					
						
							|  |  |  | 	// actions.
 | 
					
						
							| 
									
										
										
										
											2016-11-07 18:15:53 +03:00
										 |  |  | 	// The inner action return value is passed to the outer action
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// .post handlers.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-11-07 18:15:53 +03:00
										 |  |  | 	// inner return value is handling slightly differs from the base
 | 
					
						
							|  |  |  | 	// action protocol in two respects:
 | 
					
						
							|  |  |  | 	// 	1) to keep the outer return value, inner must return undefined.
 | 
					
						
							|  |  |  | 	// 	2) to guarantee returning the context regardless of outer's return 
 | 
					
						
							|  |  |  | 	// 		value, the inner must return the context (this) explicilty.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: as a restriction of the action protocol the inner return will
 | 
					
						
							|  |  |  | 	// 		override the return value of outer, but there is no way to 
 | 
					
						
							|  |  |  | 	// 		see that value.
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// NOTE: these call the action's .chainApply(..) and .chainCall(..)
 | 
					
						
							|  |  |  | 	// 		methods, thus is not compatible with non-action methods...
 | 
					
						
							|  |  |  | 	// NOTE: .chianCall('action', ..) is equivalent to .action.chianCall(..)
 | 
					
						
							|  |  |  | 	chainApply: function(outer, inner, args){ | 
					
						
							|  |  |  | 		return this[outer].chainApply(this, inner, args) }, | 
					
						
							|  |  |  | 	chainCall: function(outer, inner){ | 
					
						
							|  |  |  | 		return this[outer].chainApply(this, inner, args2array(arguments).slice(2)) }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-02 19:40:39 +03:00
										 |  |  | 	// Get action/method resolution order...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	List mixin tags...
 | 
					
						
							|  |  |  | 	// 	.mro()
 | 
					
						
							|  |  |  | 	// 	.mro('tag')
 | 
					
						
							|  |  |  | 	// 		-> tags
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	List mixin objects...
 | 
					
						
							|  |  |  | 	// 	.mro('object')
 | 
					
						
							|  |  |  | 	// 		-> objects
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	List mixin tag-object pairs...
 | 
					
						
							|  |  |  | 	// 	.mro('item')
 | 
					
						
							|  |  |  | 	// 		-> items
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-07-02 19:50:02 +03:00
										 |  |  | 	// NOTE: this will return the full MRO including Object.prototype
 | 
					
						
							| 
									
										
										
										
											2017-07-02 19:40:39 +03:00
										 |  |  | 	mro: function(target){ | 
					
						
							|  |  |  | 		target = target || 'tag' | 
					
						
							|  |  |  | 		var res = [] | 
					
						
							|  |  |  | 		var cur = this | 
					
						
							|  |  |  | 		while(cur != null){ | 
					
						
							|  |  |  | 			res.push(target == 'tag' ? cur.__mixin_tag | 
					
						
							|  |  |  | 				: target == 'object' ? cur | 
					
						
							|  |  |  | 				: [cur.__mixin_tag, cur]) | 
					
						
							|  |  |  | 			// go to next item in chain...
 | 
					
						
							|  |  |  | 			cur = cur.__proto__ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// Get mixin object in inheritance chain...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-07-02 19:50:02 +03:00
										 |  |  | 	// NOTE: from can be either an explicit action object or a tag...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// NOTE: if pre is true this will return the chain item before the 
 | 
					
						
							|  |  |  | 	// 		mixin, this is useful, for example, to remove mixins, see 
 | 
					
						
							|  |  |  | 	// 		.mixout(..) for an example...
 | 
					
						
							|  |  |  | 	getMixin: function(from, pre){ | 
					
						
							| 
									
										
										
										
											2017-07-02 19:40:39 +03:00
										 |  |  | 		var mro = this.mro('object') | 
					
						
							|  |  |  | 		var res = (pre ? mro.slice(1) : mro) | 
					
						
							|  |  |  | 			.filter(function(e){  | 
					
						
							|  |  |  | 				return e.__mixin_tag == from  | 
					
						
							|  |  |  | 					|| e.__mixin_source === from }) | 
					
						
							|  |  |  | 			.shift() | 
					
						
							|  |  |  | 		return pre ? | 
					
						
							|  |  |  | 			mro[mro.indexOf(res)-1] | 
					
						
							|  |  |  | 			: res | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2017-07-02 19:40:39 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// Mixin a set of actions into this...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-08-24 01:55:46 +03:00
										 |  |  | 	// NOTE: if 'all' is set then mixin all the actions available, 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// 		otherwise only mixin local actions...
 | 
					
						
							|  |  |  | 	// NOTE: this will override existing own attributes.
 | 
					
						
							| 
									
										
										
										
											2016-08-24 02:43:51 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX should we include functions by default????
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 	inlineMixin: function(from, options){ | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 		// defaults...
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 		options = options || {} | 
					
						
							|  |  |  | 		var descriptors = options.descriptors || true | 
					
						
							|  |  |  | 		var all_attr_types = options.all_attr_types || false | 
					
						
							|  |  |  | 		var source_tag = options.source_tag | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 19:36:39 +03:00
										 |  |  | 		resetHandlerCache = (this.resetHandlerCache || MetaActions.resetHandlerCache) | 
					
						
							|  |  |  | 		resetHandlerCache.call(this) | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 		if(options.all){ | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 			var keys = [] | 
					
						
							|  |  |  | 			for(var k in from){ | 
					
						
							|  |  |  | 				keys.push(k) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			var keys = Object.keys(from) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		keys.forEach(function(k){ | 
					
						
							|  |  |  | 			/* | 
					
						
							|  |  |  | 			// XXX is this the right way to go???
 | 
					
						
							|  |  |  | 			// check if we are not overwriting anything...
 | 
					
						
							|  |  |  | 			if(that.hasOwnProperty(k)){ | 
					
						
							|  |  |  | 				console.warn('WARNING:', that,'already has attribute', k, '- skipping...') | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// properties....
 | 
					
						
							|  |  |  | 			var prop = Object.getOwnPropertyDescriptor(from, k) | 
					
						
							|  |  |  | 			if(descriptors && prop.get != null){ | 
					
						
							|  |  |  | 				// NOTE: so as to be able to delete this on mixout...
 | 
					
						
							|  |  |  | 				prop.configurable = true | 
					
						
							|  |  |  | 				Object.defineProperty(that, k, prop) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// actions and other attributes...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				var attr = from[k] | 
					
						
							| 
									
										
										
										
											2016-08-24 02:43:51 +03:00
										 |  |  | 				if(all_attr_types  | 
					
						
							|  |  |  | 						//|| attr instanceof Function
 | 
					
						
							|  |  |  | 						|| attr instanceof Action){ | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 					that[k] = attr | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 				// source tag actions...
 | 
					
						
							|  |  |  | 				if(source_tag && attr instanceof Action){ | 
					
						
							| 
									
										
										
										
											2016-11-07 06:36:41 +03:00
										 |  |  | 					// existing tag...
 | 
					
						
							|  |  |  | 					if(that[k].source_tag == source_tag || that[k].func.source_tag == source_tag){ | 
					
						
							|  |  |  | 						return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// new tag...
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 					// XXX not sure if this is the right way to go...
 | 
					
						
							| 
									
										
										
										
											2016-11-07 06:38:50 +03:00
										 |  |  | 					} else if(that[k].source_tag || that[k].func.source_tag){ | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 						console.warn('Aactions: about to overwrite source tag...\n' | 
					
						
							|  |  |  | 							+'  from: "'+(that[k].source_tag || that[k].func.source_tag)+'"\n' | 
					
						
							|  |  |  | 							+'  to: "'+source_tag+'"\n' | 
					
						
							|  |  |  | 							+'  on:', that[k]) | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2016-11-07 06:36:41 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 					that[k].func.source_tag = source_tag | 
					
						
							|  |  |  | 					that[k].source_tag = source_tag | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 00:48:40 +03:00
										 |  |  | 	// Same as .inlineMixin(..) but isolates a mixin in a seporate object
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// in the inheritance chain...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 	mixin: function(from, options){ | 
					
						
							| 
									
										
										
										
											2017-07-02 20:25:40 +03:00
										 |  |  | 		options = options || {} | 
					
						
							|  |  |  | 		options.source_tag = options.source_tag || from.__mixin_tag | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 		var proto = Object.create(this.__proto__) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// mixinto an empty object
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 		proto.inlineMixin(from, options) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// mark the mixin for simpler removal...
 | 
					
						
							|  |  |  | 		proto.__mixin_source = from | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-02 19:13:22 +03:00
										 |  |  | 		// add source tag to proto...
 | 
					
						
							|  |  |  | 		if(options && options.source_tag){ | 
					
						
							| 
									
										
										
										
											2017-07-02 19:08:03 +03:00
										 |  |  | 			proto.__mixin_tag = options.source_tag | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 		this.__proto__ = proto | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-02 20:25:40 +03:00
										 |  |  | 	// Mixin from after target in the mro...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: target must be .getMixin(..) compatible...
 | 
					
						
							|  |  |  | 	mixinAfter: function(target, from, options){ | 
					
						
							|  |  |  | 		this | 
					
						
							|  |  |  | 			.getMixin(target) | 
					
						
							|  |  |  | 			.mixin(from, options) | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// Mixin a set of local actions into an object...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX this will not work on non-actions...
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 	mixinTo: function(to, options){ | 
					
						
							|  |  |  | 		return this.mixin.call(to, this, options) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Remove mixed in actions from this...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this will only remove local actions, inherited actions will
 | 
					
						
							|  |  |  | 	// 		not be affected...
 | 
					
						
							|  |  |  | 	// NOTE: this will not affect event handlers, they should be removed
 | 
					
						
							|  |  |  | 	// 		manually if needed...
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 	inlineMixout: function(from, options){ | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 		// defaults...
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 		options = options || {} | 
					
						
							|  |  |  | 		var descriptors = options.descriptors || true | 
					
						
							|  |  |  | 		var all_attr_types = options.all_attr_types || false | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 18:54:17 +03:00
										 |  |  | 		(this.resetHandlerCache || MetaActions.resetHandlerCache).call(this) | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 		if(options.all){ | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 			var keys = [] | 
					
						
							|  |  |  | 			for(var k in from){ | 
					
						
							|  |  |  | 				keys.push(k) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			var keys = Object.keys(from) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var locals = Object.keys(this) | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		keys.forEach(function(k){ | 
					
						
							|  |  |  | 			var prop = Object.getOwnPropertyDescriptor(from, k) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// descriptor...
 | 
					
						
							|  |  |  | 			if(descriptors && prop.get != null){ | 
					
						
							|  |  |  | 				if(prop.get === Object.getOwnPropertyDescriptor(that, k).get){ | 
					
						
							|  |  |  | 					delete that[k] | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// actions and other attrs...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				var attr = from[k] | 
					
						
							|  |  |  | 				if((all_attr_types || attr instanceof Action)  | 
					
						
							|  |  |  | 						// remove only local attrs...
 | 
					
						
							|  |  |  | 						&& locals.indexOf(k) >= 0){ | 
					
						
							|  |  |  | 					delete that[k] | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 	// This is similar in effect but different in mechanics to .inlineMixout(..)
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// This will find and remove a mixin object from the inheritance chian.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this will remove only the first occurance of a mixin.
 | 
					
						
							|  |  |  | 	mixout: function(from){ | 
					
						
							|  |  |  | 		var o = this.getMixin(from, true) | 
					
						
							| 
									
										
										
										
											2017-07-02 20:25:40 +03:00
										 |  |  | 		var target = null | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// pop the mixin off the chain...
 | 
					
						
							|  |  |  | 		if(o != null){ | 
					
						
							| 
									
										
										
										
											2017-07-02 20:25:40 +03:00
										 |  |  | 			target = o.__proto__ | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 			o.__proto__ = o.__proto__.__proto__ | 
					
						
							| 
									
										
										
										
											2016-10-27 18:47:17 +03:00
										 |  |  | 			this.resetHandlerCache() | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-02 20:25:40 +03:00
										 |  |  | 		return target | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Remove a set of local mixed in actions from object...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 	mixoutFrom: function(to, options){ | 
					
						
							|  |  |  | 		return this.mixout.call(to, this, options) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create a child object...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this will create a .config in the instance that inherits from
 | 
					
						
							|  |  |  | 	// 		this.config...
 | 
					
						
							|  |  |  | 	// NOTE: this will not copy/clone any data.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX is this correct???
 | 
					
						
							|  |  |  | 	// XXX should this be an action???
 | 
					
						
							|  |  |  | 	clone: function(full){ | 
					
						
							|  |  |  | 		var o = Object.create(this) | 
					
						
							|  |  |  | 		if(this.config){ | 
					
						
							|  |  |  | 			if(full){ | 
					
						
							|  |  |  | 				o.config = JSON.parse(JSON.stringify(this.config)) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				o.config = Object.create(this.config) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return o | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 23:31:19 +03:00
										 |  |  | 	getHandlerSourceTags: function(name){ | 
					
						
							| 
									
										
										
										
											2017-01-25 23:26:58 +03:00
										 |  |  | 		return this.getHandlers(name) | 
					
						
							|  |  |  | 			.map(function(a){ | 
					
						
							|  |  |  | 				return a.pre ? (a.pre.source_tag || a.pre.event_tag) | 
					
						
							|  |  |  | 					: a.post ? (a.post.source_tag || a.post.event_tag) | 
					
						
							|  |  |  | 					: null | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2017-01-27 04:22:54 +03:00
										 |  |  | 			.unique() }, | 
					
						
							| 
									
										
										
										
											2017-01-25 23:26:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-13 23:38:25 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Run a function in the context of the action set...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-05-13 23:47:07 +03:00
										 |  |  | 	// This will return 'this' if func returns undefined, otherwise func
 | 
					
						
							|  |  |  | 	// return value is returned.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-05-13 23:38:25 +03:00
										 |  |  | 	// This is here simply as a utility function, to enable running code 
 | 
					
						
							|  |  |  | 	// in a concatinative manner without interruption...
 | 
					
						
							|  |  |  | 	run: function(func){ | 
					
						
							|  |  |  | 		var res = func ? func.call(this) : undefined | 
					
						
							|  |  |  | 		return res === undefined ? this : res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	// doc generators...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX would be nice to make these prop of the action itself but I 
 | 
					
						
							|  |  |  | 	// 		do not see a way to do this properly yet -- we can't get to 
 | 
					
						
							|  |  |  | 	// 		the action context from the action dynamically...
 | 
					
						
							|  |  |  | 	getHandlerDocStr: function(name){ | 
					
						
							|  |  |  | 		var lst = this.getHandlers(name) | 
					
						
							|  |  |  | 		var str = '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var handler = function(p){ | 
					
						
							|  |  |  | 			if(lst.length == 0){ | 
					
						
							|  |  |  | 				//str += p + '---'
 | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// indicate root action...
 | 
					
						
							|  |  |  | 			p = lst.length == 1 ? p+'| ' : p+' ' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var cur = lst.shift() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(cur.pre){ | 
					
						
							|  |  |  | 				str += p  | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 					// meta...
 | 
					
						
							|  |  |  | 					+ (cur.pre.event_tag ?  | 
					
						
							|  |  |  | 						normalizeTabs('// Event tag: ' + cur.pre.event_tag) + p : '') | 
					
						
							|  |  |  | 					+ (cur.pre.source_tag ?  | 
					
						
							|  |  |  | 						normalizeTabs('// Source tag: ' + cur.pre.source_tag) + p : '') | 
					
						
							|  |  |  | 					// code...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 					+ normalizeTabs(cur.pre.toString()).replace(/\n/g, p) | 
					
						
							|  |  |  | 					+ p | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			handler(p + '  |') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			str += p | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(cur.post){ | 
					
						
							|  |  |  | 				str += p + p  | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 					// meta...
 | 
					
						
							|  |  |  | 					+ (cur.post.event_tag ?  | 
					
						
							| 
									
										
										
										
											2016-11-05 19:42:49 +03:00
										 |  |  | 						normalizeTabs('// Event source tag: ' + cur.post.event_tag) + p : '') | 
					
						
							| 
									
										
										
										
											2016-11-05 19:31:26 +03:00
										 |  |  | 					+ (cur.post.source_tag ?  | 
					
						
							|  |  |  | 						normalizeTabs('// Source tag: ' + cur.post.source_tag) + p : '') | 
					
						
							|  |  |  | 					// code...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 					+ normalizeTabs(cur.post.toString()).replace(/\n/g, p) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		handler('\n|') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return str | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	getHandlerDocHTML: function(name){ | 
					
						
							|  |  |  | 		var lst = this.getHandlers(name) | 
					
						
							|  |  |  | 		var res = $('<div class="action">') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var handler = function(p){ | 
					
						
							|  |  |  | 			if(lst.length == 0){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var cur = lst.shift() | 
					
						
							|  |  |  | 			p = $('<div class="level">') | 
					
						
							|  |  |  | 				.appendTo(p) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(cur.pre){ | 
					
						
							|  |  |  | 				p.append($('<pre>').html( | 
					
						
							| 
									
										
										
										
											2016-11-05 19:42:49 +03:00
										 |  |  | 					// meta...
 | 
					
						
							|  |  |  | 					(cur.pre.event_tag ?  | 
					
						
							|  |  |  | 						normalizeTabs('// Event tag: ' + cur.pre.event_tag) + p : '') | 
					
						
							|  |  |  | 					+ (cur.pre.source_tag ?  | 
					
						
							|  |  |  | 						normalizeTabs('// Source tag: ' + cur.pre.source_tag) + p : '') | 
					
						
							|  |  |  | 					// code...
 | 
					
						
							|  |  |  | 					+ normalizeTabs(cur.pre.toString()) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 						.replace(/return/g, '<b>return</b>'))) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			handler(p) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(cur.post){ | 
					
						
							|  |  |  | 				p.append($('<pre>').html( | 
					
						
							| 
									
										
										
										
											2016-11-05 19:42:49 +03:00
										 |  |  | 					// meta...
 | 
					
						
							|  |  |  | 					(cur.post.event_tag ?  | 
					
						
							|  |  |  | 						normalizeTabs('// Event source tag: ' + cur.post.event_tag) + p : '') | 
					
						
							|  |  |  | 					+ (cur.post.source_tag ?  | 
					
						
							|  |  |  | 						normalizeTabs('// Source tag: ' + cur.post.source_tag) + p : '') | 
					
						
							|  |  |  | 					// code...
 | 
					
						
							|  |  |  | 					+ normalizeTabs(cur.post.toString()))) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		handler(res) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// This will create a .config in instances...
 | 
					
						
							|  |  |  | 	// NOTE: this makes Actions compatible with lib/object.js...
 | 
					
						
							|  |  |  | 	__init__: function(){ | 
					
						
							|  |  |  | 		if(this.__proto__.config && !Object.hasOwnProperty(this, 'config')){ | 
					
						
							|  |  |  | 			this.config = Object.create(this.__proto__.config) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ActionSet = | 
					
						
							|  |  |  | module.ActionSet = | 
					
						
							|  |  |  | object.makeConstructor('ActionSet', MetaActions) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // An action set...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	Actions(<object>)
 | 
					
						
							|  |  |  | //	Actions(<prototype>, <object>)
 | 
					
						
							|  |  |  | //		-> actions
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This will pre-process an object to setup the action mechanics.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-09-27 06:13:57 +03:00
										 |  |  | // If the 'this' and prototype both contain a .config attribute then this
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | // will make set <actions>.config.__proto__ = <prototype>.config 
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The action format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							|  |  |  | // 		// full format...
 | 
					
						
							|  |  |  | // 		<name> : [
 | 
					
						
							|  |  |  | // 			<doc>,
 | 
					
						
							|  |  |  | // 			<long-doc>,
 | 
					
						
							| 
									
										
										
										
											2016-12-29 22:41:03 +03:00
										 |  |  | // 			<attrs>,
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | // 			<function>
 | 
					
						
							|  |  |  | // 		],
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// short doc only...
 | 
					
						
							|  |  |  | // 		<name> : [
 | 
					
						
							|  |  |  | // 			<doc>,
 | 
					
						
							|  |  |  | // 			<function>
 | 
					
						
							|  |  |  | // 		],
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// only the code...
 | 
					
						
							|  |  |  | // 		<name> : [
 | 
					
						
							|  |  |  | // 			<function>
 | 
					
						
							|  |  |  | // 		],
 | 
					
						
							|  |  |  | // 		...
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: the action function is always last.
 | 
					
						
							| 
									
										
										
										
											2016-12-29 22:41:03 +03:00
										 |  |  | // NOTE: <attrs> if given must be right before the function and must not
 | 
					
						
							|  |  |  | // 		be a string...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | // NOTE: if <prototype> is not given, MetaActions will be used as default.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // For more documentation see: Action(..).
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // XXX add doc, ldoc, tags and save them to each action...
 | 
					
						
							|  |  |  | // XXX is .config processing correct here???
 | 
					
						
							|  |  |  | var Actions = | 
					
						
							|  |  |  | module.Actions = | 
					
						
							|  |  |  | function Actions(a, b){ | 
					
						
							|  |  |  | 	var obj = b == null ? a : b | 
					
						
							|  |  |  | 	var proto = b == null ? b : a | 
					
						
							|  |  |  | 	obj = obj || new ActionSet() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// NOTE: this is intentionally done only for own attributes...
 | 
					
						
							|  |  |  | 	Object.keys(obj).forEach(function(k){ | 
					
						
							|  |  |  | 		// NOTE: we are not getting the attrs directly (vars = obj[k])
 | 
					
						
							|  |  |  | 		// 		as that will trigger the getters on an object that is
 | 
					
						
							|  |  |  | 		// 		not in a consistent state...
 | 
					
						
							|  |  |  | 		// NOTE: this will skip all the getters and setters, they will 
 | 
					
						
							|  |  |  | 		// 		be included as-is...
 | 
					
						
							|  |  |  | 		var arg = Object.getOwnPropertyDescriptor(obj, k).value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// skip non-arrays...
 | 
					
						
							|  |  |  | 		if(arg == null  | 
					
						
							| 
									
										
										
										
											2016-08-24 00:48:40 +03:00
										 |  |  | 				// XXX node?: for some magical reason when running this 
 | 
					
						
							|  |  |  | 				// 		from node console instanceof tests fail...
 | 
					
						
							|  |  |  | 				//|| !(arg instanceof Array)
 | 
					
						
							|  |  |  | 				|| arg.constructor.name != 'Array' | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 				// and arrays the last element of which is not a function...
 | 
					
						
							| 
									
										
										
										
											2016-08-24 00:48:40 +03:00
										 |  |  | 				|| typeof(arg[arg.length-1]) != 'function'){ | 
					
						
							|  |  |  | 				//|| !(arg[arg.length-1] instanceof Function)){
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// create a new action...
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:58:49 +03:00
										 |  |  | 		var a = obj[k] = new Action(k, arg) | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(proto != null){ | 
					
						
							|  |  |  | 		obj.__proto__ = proto | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// XXX is this the right way to go???
 | 
					
						
							|  |  |  | 		if(obj.config != null && proto.config != null){ | 
					
						
							|  |  |  | 			obj.config.__proto__ = proto.config | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return obj | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 01:55:46 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-27 06:19:55 +03:00
										 |  |  | // NOTE: this can only mix actions sets and MetaActions, i.e. only the 
 | 
					
						
							|  |  |  | // 		actions, properties and .config will get handled...
 | 
					
						
							|  |  |  | // NOTE: MetaActions is a special case, if given it will be used as the
 | 
					
						
							|  |  |  | // 		prototype for the root object in the created chain...
 | 
					
						
							|  |  |  | // 		...MetaActions order in the list has no effect.
 | 
					
						
							| 
									
										
										
										
											2016-09-27 15:56:50 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // XXX what the mix order should be?
 | 
					
						
							|  |  |  | // 		base, extending, surface		- order of application (current)
 | 
					
						
							|  |  |  | // 		surface, extending, base		- python-like
 | 
					
						
							| 
									
										
										
										
											2016-08-24 01:55:46 +03:00
										 |  |  | var mix = | 
					
						
							|  |  |  | module.mix =  | 
					
						
							|  |  |  | function(){ | 
					
						
							|  |  |  | 	var args = [].slice.call(arguments) | 
					
						
							|  |  |  | 	var res = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-27 06:13:57 +03:00
										 |  |  | 	// special case: if MetaActions is in the args then inherit the root
 | 
					
						
							|  |  |  | 	// 		object from it...
 | 
					
						
							|  |  |  | 	if(args.indexOf(MetaActions) >= 0){ | 
					
						
							|  |  |  | 		args.splice(args.indexOf(MetaActions), 1) | 
					
						
							|  |  |  | 		res.__proto__ = MetaActions | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 01:55:46 +03:00
										 |  |  | 	var mixin = MetaActions.inlineMixin | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	args.forEach(function(p){ | 
					
						
							|  |  |  | 		res = Object.create(mixin.call(res, p)) | 
					
						
							| 
									
										
										
										
											2016-09-27 04:02:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// merge config...
 | 
					
						
							|  |  |  | 		if(p.config){ | 
					
						
							|  |  |  | 			var config = res.config = res.config || Object.create({}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Object.keys(p.config).forEach(function(k){ | 
					
						
							|  |  |  | 				res.config.__proto__[k] = JSON.parse(JSON.stringify(p.config[k])) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-08-24 01:55:46 +03:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:46:34 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var test = | 
					
						
							|  |  |  | module.test = | 
					
						
							|  |  |  | function test(){ | 
					
						
							|  |  |  | 	// NOTE: this is needed only to add action methods to TestActions...
 | 
					
						
							|  |  |  | 	var BaseActions = new ActionSet() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var TestActions =  | 
					
						
							|  |  |  | 	module.TestActions =  | 
					
						
							|  |  |  | 	Actions(BaseActions, { | 
					
						
							|  |  |  | 		testActionGen1: ['baisc test action...', | 
					
						
							|  |  |  | 			'some extra info', | 
					
						
							|  |  |  | 			function(){ | 
					
						
							|  |  |  | 				console.log('  test 1!') | 
					
						
							|  |  |  | 				return function(){ | 
					
						
							|  |  |  | 					console.log('  test 2!') | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		testActionGen2: ['baisc 2\'nd gen test action...', | 
					
						
							|  |  |  | 			// no extra info...
 | 
					
						
							|  |  |  | 			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!') | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		testAction2: ['this is an action', | 
					
						
							|  |  |  | 			function(){ | 
					
						
							|  |  |  | 				console.log('testAction2 args:', arguments) | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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
 | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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...
 | 
					
						
							|  |  |  | 	TestActions2.on('testActionGen1.post',  | 
					
						
							|  |  |  | 			function(){ console.log('  post handler! (first defined)') }) | 
					
						
							|  |  |  | 	TestActions2.on('testActionGen1',  | 
					
						
							|  |  |  | 			function(){ console.log('  post handler! (last defined)') }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	console.log('TestActions2.testActionGen1()') | 
					
						
							|  |  |  | 	TestActions2.testActionGen1() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                                                */ | 
					
						
							|  |  |  | return module }) |