From fca286be32112f96bb08bb141379fad6241132de Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Thu, 10 Oct 2019 02:34:50 +0300 Subject: [PATCH] added MetaActions.callSortedAction(..)... Signed-off-by: Alex A. Naanou --- README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ actions.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2247f18..7b3aa35 100755 --- a/README.md +++ b/README.md @@ -522,6 +522,48 @@ 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 + +This sorts action handlers by priority `.sortedActionPriority` then +order and calls them. + +This protocol enables us to call actions in a deterministic order +independent of the order the handlers are defined in the prototype chain. + +``` +.callSortedAction(name, ...args) + -> this +``` + +Example action: +```javascript + someAction: [ + { sortedActionPriority: 'high' }, + function(){ + ... + }], +``` + +`sortedActionPriority` can take the following values: +- *number* +- `'high'` (equivalent to `50`) +- `'normal'` (equivalent to `0`) +- `'low'` (equivalent to `-50`) + +The greater the priority the earlier the handler is called. Handlers with +prioorities greater than `0` will always precede the unprioretized (i.e. +`.sortedActionPriority` unset, `null` or `0`) handlers; Handlers with +prioorities less than `0` will always follow the unprioretized handlers. +Unprioretized handlers keep their relative order. + +**Notes:** +- `.callSortedAction(..)` ignores handler return values by design. This is +done to prevent actions competing to return a value. +- if action name does not exist this will do nothing and return normally +(without error)... + + + ### Alias protocols: 1. Defining aliases in runtime (MetaActions) diff --git a/actions.js b/actions.js index 782a3b1..9f49e5b 100755 --- a/actions.js +++ b/actions.js @@ -1821,6 +1821,56 @@ module.MetaActions = { chainCall: function(outer, inner){ return this[outer].chainApply(this, inner, args2array(arguments).slice(2)) }, + + // Call action handlers serted by .sortedActionPriority... + // + // NOTE: this by design ignores the action call results to avoid + // actions competing on who will return a value... + // NOTE: if action name does not exist this will do nothing and + // return normally (without error)... + // NOTE: this essentially re-implements parts of the .pre(..)/.post(..) + // action protocol... + // NOTE: this may not support some legacy action protocol features... + callSortedAction: function(name, ...args){ + var that = this + this.getHandlers(name) + .map(function(h, i){ + var p = (h.pre || {}).sortedActionPriority + // normalize priority... + p = p == 'high' ? + 50 + : p == 'normal' ? + 0 + : p == 'low' ? + -50 + : p + return [i, p, h] }) + // sort by .sortedActionPriority ascending... + .sort(function([ia, pa, a], [ib, pb, b]){ + return (pa != null && pb != null) ? + pa - pb + : (pa > 0 || pb < 0) ? + 1 + : (pb > 0 || pa < 0) ? + -1 + : ia - ib }) + // the list should be ordered descending form highest + // priority or closeness to root action... + .reverse() + // call the actions (pre)... + .map(function([i, p, a]){ + return a.pre ? + a.pre.call(that, ...args) + : a.post }) + .reverse() + // call the actions (post)... + // NOTE: we do not care about call results here... + .forEach(function(func){ + func instanceof Function + && func.call(that, ...args) }) }, + + + // Get action/method resolution order... // // List mixin tags... diff --git a/package.json b/package.json index a6f9d23..9370004 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ig-actions", - "version": "3.23.0", + "version": "3.24.0", "description": "", "main": "actions.js", "scripts": {