mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-10-31 11:20:09 +00:00 
			
		
		
		
	added a more generic version of he toggler (jli.js), not tested yet...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									2fcb376f13
								
							
						
					
					
						commit
						55fcab441a
					
				| @ -15,38 +15,67 @@ define(function(require){ var module = {} | |||||||
| // Actions are an extension to the JavaScript object model tailored for
 | // Actions are an extension to the JavaScript object model tailored for
 | ||||||
| // a set of specific tasks.
 | // a set of specific tasks.
 | ||||||
| //
 | //
 | ||||||
| // The action system consists of these parts:
 | // Goals:
 | ||||||
| //
 | // 	- provide a unified mechanism to define and manage user API's for 
 | ||||||
| // 1) documentation generation and introspection
 | // 	  use in UI-hooks, keyboard mappings, scripting, ...
 | ||||||
| // 	XXX not all helpers are defined at this point...
 | // 	- a means to generate configuration UI's
 | ||||||
|  | // 	- a means to generate documentation
 | ||||||
| //
 | //
 | ||||||
| //
 | //
 | ||||||
| // 2) event-like callbacks for actions
 | // The main entities:
 | ||||||
| //
 | //
 | ||||||
| // 		MyActions.on('action', function(){ ... })
 | // 	Action set
 | ||||||
| // 		MyActions.on('action.post', function(){ ... })
 | // 		- 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)
 | ||||||
| //
 | //
 | ||||||
| // 		MyActions.on('action.pre', function(){ ... })
 | // 	Action
 | ||||||
|  | // 		- a method, created by Action(..),
 | ||||||
|  | // 		- calls all the shadowed 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 full shadow.
 | ||||||
|  | // 		- returns the action set (for call chaining),
 | ||||||
|  | // 		- can consist of two parts: the first is called before the 
 | ||||||
|  | // 		  shadowed action (pre-callback) and the second after (post-callback).
 | ||||||
|  | // 		- 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.
 | ||||||
| //
 | //
 | ||||||
| //
 | //
 | ||||||
| // 3) a mechanism to extend already defined actions
 | //
 | ||||||
|  | // The action system provides three components:
 | ||||||
|  | //
 | ||||||
|  | // 1) Documentation generation and introspection (MetaActions)
 | ||||||
|  | //
 | ||||||
|  | // 		<action-set>.getDoc()
 | ||||||
|  | // 		<action-set>.getDoc(<action-name>[, ..])
 | ||||||
|  | // 				-> dict of action-name, doc
 | ||||||
|  | //
 | ||||||
|  | // 		<action-set>.actions
 | ||||||
|  | // 				-> list of action names
 | ||||||
|  | // 	
 | ||||||
|  | //
 | ||||||
|  | // 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 
 | // 	This replaces / complements the standard JavaScript overloading 
 | ||||||
| // 	mechanisms, here is a direct comparison:
 | // 	mechanisms (Action, Actions)
 | ||||||
| //
 |  | ||||||
| //
 |  | ||||||
| // 		// Native...
 |  | ||||||
| // 		var X = {
 |  | ||||||
| // 			m: function(){ console.log('m') }
 |  | ||||||
| // 		}
 |  | ||||||
| // 		var O = {
 |  | ||||||
| // 			m: function(){
 |  | ||||||
| // 				console.log('pre')
 |  | ||||||
| // 				B.__proto__.m.call(this)
 |  | ||||||
| // 				console.log('post')
 |  | ||||||
| // 			}
 |  | ||||||
| // 		}
 |  | ||||||
| // 		O.__proto__ = X
 |  | ||||||
| //
 |  | ||||||
| //
 | //
 | ||||||
| // 		// Actions...
 | // 		// Actions...
 | ||||||
| // 		var X = Actions({
 | // 		var X = Actions({
 | ||||||
| @ -61,15 +90,10 @@ define(function(require){ var module = {} | |||||||
| // 			}]
 | // 			}]
 | ||||||
| // 		})
 | // 		})
 | ||||||
| //
 | //
 | ||||||
| //
 | //	NOTE: what is done here is similar to calling O.__proto__.m.call(..)
 | ||||||
| // Comparing to the native system:
 | //		but is implicit, and not dependant on the original containing 
 | ||||||
| // 	+ no need to chain overloaded calls by hand (automatic)
 | //		object name/reference ('O'), thus enabling an action to be 
 | ||||||
| // 	+/- more restrictive -- no way to prevent original actions from 
 | //		referenced and called from any object and still chain correctly.
 | ||||||
| // 	  running, i.e. no way to shadow.
 |  | ||||||
| // 	+/- hidden the internals (.__proto__ assignment)
 |  | ||||||
| // 	- more structural code (returning a callback vs. B.__proto__.m.call)
 |  | ||||||
| // 		NOTE: that the Actions(..) call and lists containing functions
 |  | ||||||
| // 			is not added complexity as they are mainly used for docs.
 |  | ||||||
| //
 | //
 | ||||||
| //
 | //
 | ||||||
| //
 | //
 | ||||||
| @ -246,6 +270,7 @@ module.MetaActions = { | |||||||
| 		var res = {} | 		var res = {} | ||||||
| 		var that = this | 		var that = this | ||||||
| 		actions = actions == null ? this.actions()  | 		actions = actions == null ? this.actions()  | ||||||
|  | 			: arguments.length > 1 ? args2array(arguments) | ||||||
| 			: typeof(actions) == typeof('str') ? [actions] | 			: typeof(actions) == typeof('str') ? [actions] | ||||||
| 			: actions | 			: actions | ||||||
| 		// get the first defined set of docs in the inheritance chain...
 | 		// get the first defined set of docs in the inheritance chain...
 | ||||||
| @ -262,9 +287,14 @@ module.MetaActions = { | |||||||
| 		return res | 		return res | ||||||
| 	}, | 	}, | ||||||
| 
 | 
 | ||||||
| 	// Collect all the handlers from the inheritance chain and arrange
 | 	// Get action handlers from the inheritance chain...
 | ||||||
| 	// them up-down, first defined to last...
 |  | ||||||
| 	//
 | 	//
 | ||||||
|  | 	// 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.
 | ||||||
|  | 	//
 | ||||||
|  | 	// For more docs on handler sequencing and definition see: .on(..)
 | ||||||
| 	getHandlers: function(name){ | 	getHandlers: function(name){ | ||||||
| 		var handlers = [] | 		var handlers = [] | ||||||
| 		var cur = this | 		var cur = this | ||||||
|  | |||||||
| @ -231,6 +231,189 @@ function createCSSClassToggler(elem, class_list, callback_a, callback_b){ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | // Make a generic toggler function/method...
 | ||||||
|  | //
 | ||||||
|  | // state_accessor signature:
 | ||||||
|  | //
 | ||||||
|  | // 	Get current state:
 | ||||||
|  | // 	state_accessor()
 | ||||||
|  | // 		-> <current-state>
 | ||||||
|  | //
 | ||||||
|  | // 	Set new state:
 | ||||||
|  | // 	state_accessor(<new-state>)
 | ||||||
|  | // 		-> <new-state>
 | ||||||
|  | //
 | ||||||
|  | // NOTE: for single state toggling, 'none' will get passed to 
 | ||||||
|  | // 		state_accessor to indicate an "empty" state...
 | ||||||
|  | //
 | ||||||
|  | function makeToggler(state_accessor, states, callback_a, callback_b){ | ||||||
|  | 	// normalize states...
 | ||||||
|  | 	states = typeof(states) == typeof('str') ? ['none', states] : states | ||||||
|  | 	// normalize the callbacks...
 | ||||||
|  | 	if(callback_b == null){ | ||||||
|  | 		var callback_pre = null | ||||||
|  | 		var callback_post = callback_a | ||||||
|  | 	} else { | ||||||
|  | 		var callback_pre = callback_a | ||||||
|  | 		var callback_post = callback_b | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var bool_action = (states.length == 2 && states[0] == 'none') | ||||||
|  | 
 | ||||||
|  | 	var func = function(a, b){ | ||||||
|  | 		// so as to be able to distinguish between a method and a root 
 | ||||||
|  | 		// context in a simple manner...
 | ||||||
|  | 		'use strict' | ||||||
|  | 
 | ||||||
|  | 		// parse arguments...
 | ||||||
|  | 		if(b == null){ | ||||||
|  | 			var action = a == 'next' ? null : a | ||||||
|  | 			// XXX is this correct???
 | ||||||
|  | 			var e = this | ||||||
|  | 		} else { | ||||||
|  | 			var e = a | ||||||
|  | 			var action = b == 'next' ? null : b | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// option number...
 | ||||||
|  | 		if(typeof(action) == typeof(1)){ | ||||||
|  | 			// range check...
 | ||||||
|  | 			if(action < 0 || action >= states.length){ | ||||||
|  | 				return null | ||||||
|  | 			} | ||||||
|  | 			if(bool_action){ | ||||||
|  | 				action = action == 0 ? 'off' : 'on' | ||||||
|  | 			} else { | ||||||
|  | 				action = states[action] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// we need to get the current state...
 | ||||||
|  | 		if(action == null || action == '?' || action == '!'){ | ||||||
|  | 			// get current state...
 | ||||||
|  | 			var cur = state_accessor.call(e) | ||||||
|  | 
 | ||||||
|  | 			// just asking for info...
 | ||||||
|  | 			if(action == '?'){ | ||||||
|  | 				return bool_action ? (cur == 'none' ? 'off' : 'on') : cur | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// force reload of current state...
 | ||||||
|  | 			if(action == '!'){ | ||||||
|  | 				action = bool_action ? (cur == 'none' ? 'off' : 'on') : cur | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 		// invalid action...
 | ||||||
|  | 		} else if((bool_action && ['on', 'off'].indexOf(action) == -1) | ||||||
|  | 				|| (!bool_action && states.indexOf(action) == -1)){ | ||||||
|  | 			return null | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		var state = bool_action ? states[1] : action | ||||||
|  | 		// get the right class...
 | ||||||
|  | 		if(action == null){ | ||||||
|  | 			var i = states.indexOf(cur)+1 | ||||||
|  | 			i = i == -1 ? 0 : i | ||||||
|  | 			i = i == states.length ? 0 : i | ||||||
|  | 			state = states[i] | ||||||
|  | 
 | ||||||
|  | 			if(bool_action){ | ||||||
|  | 				action = state == 'none' ? 'off' : 'on' | ||||||
|  | 			} else { | ||||||
|  | 				action = state | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// NOTE: the callbacks are passed the same this as the calling 
 | ||||||
|  | 		// 		function, this will enable them to act as metods correctly
 | ||||||
|  | 		// pre callback...
 | ||||||
|  | 		if(callback_pre != null){ | ||||||
|  | 			if(callback_pre.apply(this, [action, e].concat(args)) === false){ | ||||||
|  | 				//return
 | ||||||
|  | 				return func('?') | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// update the element...
 | ||||||
|  | 		state_accessor.call(e, state) | ||||||
|  | 
 | ||||||
|  | 		// post callback...
 | ||||||
|  | 		if(callback_post != null){ | ||||||
|  | 			callback_post.apply(this, [action, e].concat(args)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return action | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	func.states = states | ||||||
|  | 	if(bool_action){ | ||||||
|  | 		func.doc = 'With no arguments this will toggle between "on" and '+ | ||||||
|  | 			'"off".\n'+ | ||||||
|  | 			'If either "on" or "off" are given then this will switch '+ | ||||||
|  | 			'to that mode.\n'+ | ||||||
|  | 			'If "?" is given, this will return either "on" or "off" '+ | ||||||
|  | 			'depending on the current state.' | ||||||
|  | 	}else{ | ||||||
|  | 		func.doc = 'With no arguments this will toggle between '+ | ||||||
|  | 			states +' in cycle.\n' +  | ||||||
|  | 			'if any of the state names or its number is given then that '+ | ||||||
|  | 			'state is switched on.'+ | ||||||
|  | 			'If "?" is given, this will return the current state.' | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return func | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // XXX this should be drop-in compatible with createCSSClassToggler(..)
 | ||||||
|  | // 		test and replace...
 | ||||||
|  | function makeCSSClassToggler(elem, classes, callback_a, callback_b){ | ||||||
|  | 	// normalize the states...
 | ||||||
|  | 	classes = typeof(classes) == typeof('str') ? ['none', classes] : classes | ||||||
|  | 	// remove the dot from class names...
 | ||||||
|  | 	// NOTE: this is here because I've made the error of including a 
 | ||||||
|  | 	// 		leading "." almost every time I use this after I forget 
 | ||||||
|  | 	// 		the UI...
 | ||||||
|  | 	classes = classes | ||||||
|  | 		.map(function(e){ | ||||||
|  | 			return e.split(' ') | ||||||
|  | 				.map(function(c){ | ||||||
|  | 					c = c.trim() | ||||||
|  | 					return c[0] == '.' ? c.slice(1) : c | ||||||
|  | 				}).join(' ') | ||||||
|  | 		}) | ||||||
|  | 	 | ||||||
|  | 	return makeToggler( | ||||||
|  | 		function(state){ | ||||||
|  | 			var e = $(this == null ? elem : this) | ||||||
|  | 			// get the state...
 | ||||||
|  | 			if(state == null){ | ||||||
|  | 				var cur = 'none' | ||||||
|  | 				for(var i=0; i < classes.length; i++){ | ||||||
|  | 					// XXX make this faster by getting the class list once 
 | ||||||
|  | 					// 		and checking in that rather than doing a 
 | ||||||
|  | 					// 		.hasClass(..) per iteration...
 | ||||||
|  | 					if(e.hasClass(classes[i])){ | ||||||
|  | 						cur = classes[i] | ||||||
|  | 						break | ||||||
|  | 					} | ||||||
|  | 				}  | ||||||
|  | 				return cur | ||||||
|  | 
 | ||||||
|  | 			// set the state...
 | ||||||
|  | 			} else { | ||||||
|  | 				e.removeClass(classes.join(' ')) | ||||||
|  | 				if(state != 'none' && action != 'off'){ | ||||||
|  | 					e.addClass(state) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		},  | ||||||
|  | 		classes,  | ||||||
|  | 		callback_a,  | ||||||
|  | 		callback_b) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
| // show a jQuary opject in viewer overlay...
 | // show a jQuary opject in viewer overlay...
 | ||||||
| @ -1121,6 +1304,7 @@ Array.prototype.compact = function(){ | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // like .length but for sparse arrays will return the element count...
 | // like .length but for sparse arrays will return the element count...
 | ||||||
|  | // XXX make this a prop...
 | ||||||
| Array.prototype.len = function(){ | Array.prototype.len = function(){ | ||||||
| 	return this.compact().length | 	return this.compact().length | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,7 +11,20 @@ console.log('>>> viewer') | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /*********************************************************************/ | /*********************************************************************/ | ||||||
|  | //
 | ||||||
|  | // XXX Tasks to accomplish here:
 | ||||||
|  | // 	- life-cycle actions/events
 | ||||||
|  | // 		- setup
 | ||||||
|  | // 		- reset
 | ||||||
|  | // 	- "features" and the mechanism to turn them on or off (action-sets)
 | ||||||
|  | //
 | ||||||
|  | //
 | ||||||
| 
 | 
 | ||||||
|  | var Client = { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var Viewer = { | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user