mirror of
https://github.com/flynx/actions.js.git
synced 2025-10-28 18:00:11 +00:00
adde action pre-call test and debounce test generator...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
03b52f6f9f
commit
7b23e84dcc
66
README.md
66
README.md
@ -158,6 +158,29 @@ n
|
|||||||
languages such as Python where the order is reversed.
|
languages such as Python where the order is reversed.
|
||||||
|
|
||||||
|
|
||||||
|
## Index
|
||||||
|
- [Actions](#actions)
|
||||||
|
- [The problem:](#the-problem)
|
||||||
|
- [The solution:](#the-solution)
|
||||||
|
- [What we get:](#what-we-get)
|
||||||
|
- [Restrictions comparing to native JavaScript:](#restrictions-comparing-to-native-javascript)
|
||||||
|
- [Index](#index)
|
||||||
|
- [The main entities:](#the-main-entities)
|
||||||
|
- [The action system main protocols:](#the-action-system-main-protocols)
|
||||||
|
- [1. Documentation generation and introspection (`MetaActions`)](#1-documentation-generation-and-introspection-metaactions)
|
||||||
|
- [2. Event-like callbacks for actions (`MetaActions`, `Action`)](#2-event-like-callbacks-for-actions-metaactions-action)
|
||||||
|
- [3. A mechanism to define and extend already defined actions](#3-a-mechanism-to-define-and-extend-already-defined-actions)
|
||||||
|
- [Secondary action protocols:](#secondary-action-protocols)
|
||||||
|
- [1. A mechanism to manually call the pre/post stages of an action](#1-a-mechanism-to-manually-call-the-prepost-stages-of-an-action)
|
||||||
|
- [2. A mechanism to chain/wrap actions or an action and a function.](#2-a-mechanism-to-chainwrap-actions-or-an-action-and-a-function)
|
||||||
|
- [3. `.__actioncall__` action / handler](#3-__actioncall__-action--handler)
|
||||||
|
- [4. Action attributes](#4-action-attributes)
|
||||||
|
- [5. Pre-call testing if an action can be called](#5-pre-call-testing-if-an-action-can-be-called)
|
||||||
|
- [6. Scheduling a call after the running action](#6-scheduling-a-call-after-the-running-action)
|
||||||
|
- [7. Calling action handlers sorted independently of the prototype chain](#7-calling-action-handlers-sorted-independently-of-the-prototype-chain)
|
||||||
|
- [Alias protocols:](#alias-protocols)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
|
|
||||||
### The main entities:
|
### The main entities:
|
||||||
|
|
||||||
@ -479,6 +502,17 @@ the second arguments, and as normal a result on the post phase.
|
|||||||
|
|
||||||
#### 4. Action attributes
|
#### 4. Action attributes
|
||||||
|
|
||||||
|
Setting action attributes:
|
||||||
|
```javascript
|
||||||
|
someAction: [
|
||||||
|
{attr: 'value', .. },
|
||||||
|
function(){
|
||||||
|
...
|
||||||
|
}],
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Attribute access:
|
||||||
```
|
```
|
||||||
<action-set>.getActionAttr('action', 'attr')
|
<action-set>.getActionAttr('action', 'attr')
|
||||||
-> <value>
|
-> <value>
|
||||||
@ -487,7 +521,35 @@ the second arguments, and as normal a result on the post phase.
|
|||||||
-> <value>
|
-> <value>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 5. Scheduling a call after the running action
|
|
||||||
|
#### 5. Pre-call testing if an action can be called
|
||||||
|
|
||||||
|
A pre call test is called before the action's pre handlers are called and if
|
||||||
|
it returns anything truthy the action is not called and that return value is
|
||||||
|
returned instead.
|
||||||
|
|
||||||
|
To return a falsey value wrap it in `actions.ASIS(..)`
|
||||||
|
|
||||||
|
Only the top-most pre call test is called.
|
||||||
|
|
||||||
|
Defining a pre call test:
|
||||||
|
```javascript
|
||||||
|
someAction: [
|
||||||
|
{precall: actions.debounce(200, true)},
|
||||||
|
function(){
|
||||||
|
...
|
||||||
|
}],
|
||||||
|
```
|
||||||
|
|
||||||
|
The test is called in the context of the `<action-set>`
|
||||||
|
```
|
||||||
|
<pre-call-test>(<action>, ...)
|
||||||
|
-> undefined
|
||||||
|
-> <value>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### 6. Scheduling a call after the running action
|
||||||
|
|
||||||
This enables the action code to schedule a call after the current
|
This enables the action code to schedule a call after the current
|
||||||
action level or the root action is done.
|
action level or the root action is done.
|
||||||
@ -520,7 +582,7 @@ Example:
|
|||||||
- This is pointless outside of an action call, thus an exception will be thrown.
|
- This is pointless outside of an action call, thus an exception will be thrown.
|
||||||
|
|
||||||
|
|
||||||
#### 6. Calling action handlers sorted independently of the prototype chain
|
#### 7. Calling action handlers sorted independently of the prototype chain
|
||||||
|
|
||||||
This sorts action handlers by priority `.sortedActionPriority` then
|
This sorts action handlers by priority `.sortedActionPriority` then
|
||||||
order and calls them.
|
order and calls them.
|
||||||
|
|||||||
108
actions.js
108
actions.js
@ -58,6 +58,46 @@ function(func){
|
|||||||
return func.apply(this, [handlers.pop()].concat(args)) } }
|
return func.apply(this, [handlers.pop()].concat(args)) } }
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
// pre-call tests...
|
||||||
|
|
||||||
|
// Debounce action call...
|
||||||
|
//
|
||||||
|
// debounce()
|
||||||
|
// debounce(timeout[, postcall])
|
||||||
|
// -> this
|
||||||
|
// -> false
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// XXX would be good to add a version of this that would debounce taking
|
||||||
|
// into acoount args...
|
||||||
|
// XXX EXPERIMENTAL (precall)...
|
||||||
|
var debounce =
|
||||||
|
module.debounce =
|
||||||
|
function(timeout=200, postcall=true){
|
||||||
|
var debounced = false
|
||||||
|
var last_args
|
||||||
|
|
||||||
|
return function(action, ...args){
|
||||||
|
// call...
|
||||||
|
if(!debounced){
|
||||||
|
debounced = setTimeout(
|
||||||
|
function(){
|
||||||
|
debounced = false
|
||||||
|
// post call...
|
||||||
|
postcall
|
||||||
|
&& last_args !== undefined
|
||||||
|
&& action.call(this, ...last_args) }.bind(this),
|
||||||
|
timeout)
|
||||||
|
// cleanup...
|
||||||
|
last_args = undefined
|
||||||
|
return false
|
||||||
|
// skip...
|
||||||
|
} else {
|
||||||
|
last_args = args
|
||||||
|
return this } } }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// String action parser/runner...
|
// String action parser/runner...
|
||||||
@ -483,6 +523,29 @@ object.Constructor('Action', Function, {
|
|||||||
|| MetaActions.getHandlers
|
|| MetaActions.getHandlers
|
||||||
var handlers = getHandlers.call(context, outer)
|
var handlers = getHandlers.call(context, outer)
|
||||||
|
|
||||||
|
// precall test...
|
||||||
|
// NOTE: we are calling only the top-most precall method, the
|
||||||
|
// rest are ignored...
|
||||||
|
// XXX EXPERIMENTAL (precall)...
|
||||||
|
var precall = handlers
|
||||||
|
.map(function(h){
|
||||||
|
return (h.pre || {}).precall ?
|
||||||
|
[h.pre.precall]
|
||||||
|
: [] })
|
||||||
|
.flat()
|
||||||
|
.pop()
|
||||||
|
if(typeof(precall) == 'function'){
|
||||||
|
// XXX revise args...
|
||||||
|
precall = precall.call(context, this, ...args)
|
||||||
|
if(precall){
|
||||||
|
return {
|
||||||
|
rejected: true,
|
||||||
|
// XXX revise how default value is returned...
|
||||||
|
result: precall instanceof ASIS ?
|
||||||
|
precall.value
|
||||||
|
: precall,
|
||||||
|
} } }
|
||||||
|
|
||||||
// handle cases where .func is not in handlers...
|
// handle cases where .func is not in handlers...
|
||||||
//
|
//
|
||||||
// NOTE: see Special cases in method doc above...
|
// NOTE: see Special cases in method doc above...
|
||||||
@ -554,13 +617,10 @@ object.Constructor('Action', Function, {
|
|||||||
throw error }
|
throw error }
|
||||||
|
|
||||||
// return context if nothing specific is returned...
|
// return context if nothing specific is returned...
|
||||||
res = res === undefined ? context
|
res = res === undefined ?
|
||||||
: res instanceof ASIS ? res.value
|
context
|
||||||
// XXX returning an explicit [undefined]...
|
: res instanceof ASIS ?
|
||||||
//: res instanceof Array
|
res.value
|
||||||
// && res.length == 1
|
|
||||||
// && res.indexOf(undefined) == 0 ?
|
|
||||||
// undefined
|
|
||||||
: res
|
: res
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -626,12 +686,17 @@ object.Constructor('Action', Function, {
|
|||||||
// chaining...
|
// chaining...
|
||||||
//
|
//
|
||||||
// For docs see: MetaActions.chainApply(..) and the base module doc.
|
// For docs see: MetaActions.chainApply(..) and the base module doc.
|
||||||
chainApply: function(context, inner, args){
|
chainCall: function(context, inner, ...args){
|
||||||
args = [...(args || [])]
|
args = args || []
|
||||||
var outer = this.name
|
var outer = this.name
|
||||||
|
|
||||||
var data = this.pre(context, args)
|
var data = this.pre(context, args)
|
||||||
|
|
||||||
|
// precall test...
|
||||||
|
// XXX EXPERIMENTAL (precall)...
|
||||||
|
if(data.rejected == true){
|
||||||
|
return data.result }
|
||||||
|
|
||||||
// call the inner action/function if preset....
|
// call the inner action/function if preset....
|
||||||
// NOTE: this is slightly different (see docs) to what happens in
|
// NOTE: this is slightly different (see docs) to what happens in
|
||||||
// .pre(..)/.post(..), thus we are doing this separately and
|
// .pre(..)/.post(..), thus we are doing this separately and
|
||||||
@ -640,9 +705,9 @@ object.Constructor('Action', Function, {
|
|||||||
var res = inner instanceof Function ?
|
var res = inner instanceof Function ?
|
||||||
inner.apply(context, args)
|
inner.apply(context, args)
|
||||||
: inner instanceof Array && inner.length > 0 ?
|
: inner instanceof Array && inner.length > 0 ?
|
||||||
context[inner.pop()].chainApply(context, inner, args)
|
context[inner.pop()].chainCall(context, inner, ...args)
|
||||||
: typeof(inner) == typeof('str') ?
|
: typeof(inner) == typeof('str') ?
|
||||||
context[inner].chainApply(context, null, args)
|
context[inner].chainCall(context, null, ...args)
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
// call the resulting function...
|
// call the resulting function...
|
||||||
@ -667,8 +732,8 @@ object.Constructor('Action', Function, {
|
|||||||
return that.post(context, data) }) }
|
return that.post(context, data) }) }
|
||||||
|
|
||||||
return this.post(context, data) },
|
return this.post(context, data) },
|
||||||
chainCall: function(context, inner){
|
chainApply: function(context, inner, args){
|
||||||
return this.chainApply(context, inner, [...arguments].slice(2)) },
|
return this.chainCall(context, inner, ...args) },
|
||||||
|
|
||||||
|
|
||||||
// constructor...
|
// constructor...
|
||||||
@ -686,7 +751,7 @@ object.Constructor('Action', Function, {
|
|||||||
|
|
||||||
// create the actual instance we will be returning...
|
// create the actual instance we will be returning...
|
||||||
var meth = function(){
|
var meth = function(){
|
||||||
return meth.chainApply(this, null, arguments) }
|
return meth.chainCall(this, null, ...arguments) }
|
||||||
meth.__proto__ = this.__proto__
|
meth.__proto__ = this.__proto__
|
||||||
|
|
||||||
// precess args...
|
// precess args...
|
||||||
@ -1481,14 +1546,13 @@ module.MetaActions = {
|
|||||||
|
|
||||||
// Apply/call a function/action "inside" an action...
|
// Apply/call a function/action "inside" an action...
|
||||||
//
|
//
|
||||||
// .chainApply(outer, inner)
|
|
||||||
// .chainApply(outer, inner, arguments)
|
|
||||||
// -> result
|
|
||||||
//
|
|
||||||
// .chainCall(outer, inner)
|
// .chainCall(outer, inner)
|
||||||
// .chainCall(outer, inner, ..)
|
// .chainCall(outer, inner, ..)
|
||||||
// -> result
|
// -> result
|
||||||
//
|
//
|
||||||
|
// .chainApply(outer, inner)
|
||||||
|
// .chainApply(outer, inner, arguments)
|
||||||
|
// -> result
|
||||||
//
|
//
|
||||||
// The inner action call is completely nested as base of the outer
|
// The inner action call is completely nested as base of the outer
|
||||||
// action.
|
// action.
|
||||||
@ -1514,10 +1578,10 @@ module.MetaActions = {
|
|||||||
// NOTE: these call the action's .chainApply(..) and .chainCall(..)
|
// NOTE: these call the action's .chainApply(..) and .chainCall(..)
|
||||||
// methods, thus is not compatible with non-action methods...
|
// methods, thus is not compatible with non-action methods...
|
||||||
// NOTE: .chainCall('action', ..) is equivalent to .action.chainCall(..)
|
// NOTE: .chainCall('action', ..) is equivalent to .action.chainCall(..)
|
||||||
chainApply: function(outer, inner, args){
|
chainCall: function(outer, inner, ...args){
|
||||||
return this[outer].chainApply(this, inner, args) },
|
return this[outer].chainCall(this, inner, ...args) },
|
||||||
chainCall: function(outer, inner){
|
chainApply: function(outer, inner, ...args){
|
||||||
return this[outer].chainApply(this, inner, [...arguments].slice(2)) },
|
return this[outer].chainCall(this, inner, args) },
|
||||||
|
|
||||||
|
|
||||||
// Call action handlers serted by .sortedActionPriority...
|
// Call action handlers serted by .sortedActionPriority...
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ig-actions",
|
"name": "ig-actions",
|
||||||
"version": "3.24.19",
|
"version": "3.24.20",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "actions.js",
|
"main": "actions.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user