adde action pre-call test and debounce test generator...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-12-03 03:33:51 +03:00
parent 03b52f6f9f
commit 7b23e84dcc
3 changed files with 151 additions and 25 deletions

View File

@ -158,6 +158,29 @@ n
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:
@ -479,6 +502,17 @@ the second arguments, and as normal a result on the post phase.
#### 4. Action attributes
Setting action attributes:
```javascript
someAction: [
{attr: 'value', .. },
function(){
...
}],
```
Attribute access:
```
<action-set>.getActionAttr('action', 'attr')
-> <value>
@ -487,7 +521,35 @@ the second arguments, and as normal a result on the post phase.
-> <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
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.
#### 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
order and calls them.

View File

@ -58,6 +58,46 @@ function(func){
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...
@ -483,6 +523,29 @@ object.Constructor('Action', Function, {
|| MetaActions.getHandlers
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...
//
// NOTE: see Special cases in method doc above...
@ -554,13 +617,10 @@ object.Constructor('Action', Function, {
throw error }
// return context if nothing specific is returned...
res = res === undefined ? context
: res instanceof ASIS ? res.value
// XXX returning an explicit [undefined]...
//: res instanceof Array
// && res.length == 1
// && res.indexOf(undefined) == 0 ?
// undefined
res = res === undefined ?
context
: res instanceof ASIS ?
res.value
: res
return {
@ -626,12 +686,17 @@ object.Constructor('Action', Function, {
// chaining...
//
// For docs see: MetaActions.chainApply(..) and the base module doc.
chainApply: function(context, inner, args){
args = [...(args || [])]
chainCall: function(context, inner, ...args){
args = args || []
var outer = this.name
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....
// NOTE: this is slightly different (see docs) to what happens in
// .pre(..)/.post(..), thus we are doing this separately and
@ -640,9 +705,9 @@ object.Constructor('Action', Function, {
var res = inner instanceof Function ?
inner.apply(context, args)
: inner instanceof Array && inner.length > 0 ?
context[inner.pop()].chainApply(context, inner, args)
context[inner.pop()].chainCall(context, inner, ...args)
: typeof(inner) == typeof('str') ?
context[inner].chainApply(context, null, args)
context[inner].chainCall(context, null, ...args)
: undefined
// call the resulting function...
@ -667,8 +732,8 @@ object.Constructor('Action', Function, {
return that.post(context, data) }) }
return this.post(context, data) },
chainCall: function(context, inner){
return this.chainApply(context, inner, [...arguments].slice(2)) },
chainApply: function(context, inner, args){
return this.chainCall(context, inner, ...args) },
// constructor...
@ -686,7 +751,7 @@ object.Constructor('Action', Function, {
// create the actual instance we will be returning...
var meth = function(){
return meth.chainApply(this, null, arguments) }
return meth.chainCall(this, null, ...arguments) }
meth.__proto__ = this.__proto__
// precess args...
@ -1481,14 +1546,13 @@ module.MetaActions = {
// Apply/call a function/action "inside" an action...
//
// .chainApply(outer, inner)
// .chainApply(outer, inner, arguments)
// -> result
//
// .chainCall(outer, inner)
// .chainCall(outer, inner, ..)
// -> result
//
// .chainApply(outer, inner)
// .chainApply(outer, inner, arguments)
// -> result
//
// The inner action call is completely nested as base of the outer
// action.
@ -1514,10 +1578,10 @@ module.MetaActions = {
// NOTE: these call the action's .chainApply(..) and .chainCall(..)
// methods, thus is not compatible with non-action methods...
// NOTE: .chainCall('action', ..) is equivalent to .action.chainCall(..)
chainApply: function(outer, inner, args){
return this[outer].chainApply(this, inner, args) },
chainCall: function(outer, inner){
return this[outer].chainApply(this, inner, [...arguments].slice(2)) },
chainCall: function(outer, inner, ...args){
return this[outer].chainCall(this, inner, ...args) },
chainApply: function(outer, inner, ...args){
return this[outer].chainCall(this, inner, args) },
// Call action handlers serted by .sortedActionPriority...

View File

@ -1,6 +1,6 @@
{
"name": "ig-actions",
"version": "3.24.19",
"version": "3.24.20",
"description": "",
"main": "actions.js",
"scripts": {