mirror of
https://github.com/flynx/ImageGrid.git
synced 2025-10-29 10:20:08 +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
|
||||
// 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
|
||||
// use in UI-hooks, keyboard mappings, scripting, ...
|
||||
// - a means to generate configuration UI's
|
||||
// - a means to generate documentation
|
||||
//
|
||||
// 1) documentation generation and introspection
|
||||
// XXX not all helpers are defined at this point...
|
||||
//
|
||||
// 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
|
||||
// - 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.
|
||||
//
|
||||
//
|
||||
//
|
||||
// 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
|
||||
// 2) Event-like callbacks for actions (MetaActions, Action)
|
||||
//
|
||||
// MyActions.on('action', function(){ ... })
|
||||
// MyActions.on('action.post', function(){ ... })
|
||||
// <action-set>.on('action', function(){ ... })
|
||||
// <action-set>.on('action.post', function(){ ... })
|
||||
//
|
||||
// MyActions.on('action.pre', function(){ ... })
|
||||
// <action-set>.on('action.pre', function(){ ... })
|
||||
//
|
||||
//
|
||||
// 3) a mechanism to extend already defined actions
|
||||
// 3) A mechanism to define and extend already defined actions
|
||||
// This replaces / complements the standard JavaScript overloading
|
||||
// mechanisms, here is a direct comparison:
|
||||
//
|
||||
//
|
||||
// // Native...
|
||||
// var X = {
|
||||
// m: function(){ console.log('m') }
|
||||
// }
|
||||
// var O = {
|
||||
// m: function(){
|
||||
// console.log('pre')
|
||||
// B.__proto__.m.call(this)
|
||||
// console.log('post')
|
||||
// }
|
||||
// }
|
||||
// O.__proto__ = X
|
||||
//
|
||||
// mechanisms (Action, Actions)
|
||||
//
|
||||
// // Actions...
|
||||
// var X = Actions({
|
||||
@ -61,15 +90,10 @@ define(function(require){ var module = {}
|
||||
// }]
|
||||
// })
|
||||
//
|
||||
//
|
||||
// Comparing to the native system:
|
||||
// + no need to chain overloaded calls by hand (automatic)
|
||||
// +/- more restrictive -- no way to prevent original actions from
|
||||
// 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.
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
//
|
||||
@ -246,6 +270,7 @@ module.MetaActions = {
|
||||
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...
|
||||
@ -262,9 +287,14 @@ module.MetaActions = {
|
||||
return res
|
||||
},
|
||||
|
||||
// Collect all the handlers from the inheritance chain and arrange
|
||||
// them up-down, first defined to last...
|
||||
// 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.
|
||||
//
|
||||
// For more docs on handler sequencing and definition see: .on(..)
|
||||
getHandlers: function(name){
|
||||
var handlers = []
|
||||
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...
|
||||
@ -1121,6 +1304,7 @@ Array.prototype.compact = function(){
|
||||
|
||||
|
||||
// like .length but for sparse arrays will return the element count...
|
||||
// XXX make this a prop...
|
||||
Array.prototype.len = function(){
|
||||
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