refactoring and fixes...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-11-25 20:39:55 +03:00
parent b164450c0f
commit cce5eaf1e7
3 changed files with 109 additions and 37 deletions

View File

@ -18,6 +18,14 @@ var object = require('ig-object')
/*********************************************************************/
// Event method wrappers...
var EventCommand =
module.EventCommand =
object.Constructor('EventCommand', {
name: null,
__init__: function(name, data={}){
Object.assign(this, data, {name}) },
})
// Create an "eventfull" method...
//
// The resulting method can be either called directly or via .trigger(..).
@ -32,6 +40,7 @@ var object = require('ig-object')
// -> method
//
//
// Trigger the event...
// method(...args)
// -> ..
//
@ -40,6 +49,35 @@ var object = require('ig-object')
// -> ..
//
//
// trigger event handlers...
// handle()
// handle(true)
// -> true
// -> false
//
// prevent event handlers from triggering...
// handle(false)
// -> undefined
//
//
//
// Special case: EventCommand...
//
// EventCommand instance can be passed as the first argument of method,
// in this case the event function will get it but the event handlers
// will not...
// This is done to be able to externally pass commands to event methods
// that get handled in a special way by the function but not passed to
// the event handlers...
//
// method(<event-command>, ...args)
// -> ..
//
// func(handle, <event-command>, ...args)
// -> ..
//
//
//
// NOTE: calling handle(false) will exiplicitly disable calling the
// handlers for that call...
var Eventfull =
@ -69,17 +107,18 @@ function(name, func, options={}){
// after the event action is done but before it returns...
// NOTE: to explicitly disable calling the handlers func must
// call handle(false)
// XXX should he user be able to control the args passed to
// the handlers???
var did_handle = false
var handle = function(skip=false){
did_handle = skip === true
return skip ?
undefined
: handlers
var handle = function(run=true){
did_handle = run === false
var a = args[0] instanceof EventCommand ?
args.slice(1)
: args
return run ?
handlers
.reduce(function(res, handler){
return res === true
&& handler(name, ...args) !== false }, true) }
&& handler(name, ...a) !== false }, true)
: undefined }
var res = func ?
func.call(this, handle, ...args)
@ -142,7 +181,8 @@ function(name, func, options={}){
return method }
module.TRIGGER = {doc: 'force event method to trigger'}
module.TRIGGER = module.EventCommand('TRIGGER')
// Extends Eventfull(..) adding ability to bind events via the
// resulting method directly by passing it a function...
@ -179,9 +219,6 @@ module.TRIGGER = {doc: 'force event method to trigger'}
// This will pass args to the event action regardless whether the first
// arg is a function or not...
//
//
// XXX might be a good idea to adde an event that can't be triggered by
// calling...
var Event =
module.Event =
function(name, func, options={}){
@ -194,18 +231,14 @@ function(name, func, options={}){
return object.mixin(
method = Eventfull(name,
function(handle, ...args){
// add handler...
if(typeof(args[0]) == 'function'){
// NOTE: when the first arg is an event command this will
// fall through to calling the action...
typeof(args[0]) == 'function' ?
// add handler...
method.__event_handler_add__(this, args[0])
// call the action...
} else {
// special case: force trigger -> remove TRIGGER from args...
args[0] === module.TRIGGER
&& args.shift()
func
&& func.call(this, handle, ...args) }
// call the action...
: (func
&& func.call(this, handle, ...args))
return this },
options),
{
@ -220,6 +253,16 @@ function(name, func, options={}){
}) }
// Like Event(..) but produces an event that can only be triggered via
// .trigger(name, ...), calling this is a no-op...
var PureEvent =
module.PureEvent =
function(name, options={}){
return Event(name, function(handle, trigger){
trigger === module.TRIGGER
|| handle(false) }, options)}
//---------------------------------------------------------------------
// Mixins...

View File

@ -1,6 +1,6 @@
{
"name": "ig-types",
"version": "5.0.9",
"version": "5.0.10",
"description": "Generic JavaScript types and type extensions...",
"main": "main.js",
"scripts": {

View File

@ -337,6 +337,38 @@ object.Mixin('TaskMixin', 'soft', {
})
// Make the ticket more usable...
var TaskTicket =
module.TaskTicket =
object.Constructor('TaskTicket', {
__data: null,
title: null,
resolve: function(...args){
this.__data.resolve(...args)
return this },
reject: function(...args){
this.__data.reject(...args)
return this },
onmessage: function(msg, func){
this.__data.onmessage(
typeof(msg) == 'function' ?
msg
: function(m, ...args){
m == msg
&& func(...args) })
return this },
__init__: function(title, resolve, reject, onmessage){
this.title = title
Object.defineProperty(this, '__data', {
__data: {resolve, reject, onmessage},
enumerable: false,
}) },
})
// XXX we should keep the API here similar to Queue...
// ...but this is no a queue in principle (internal vs. external
// management) so we'll also need to keep them different enough to
@ -359,6 +391,8 @@ object.Constructor('TaskManager', Array, events.EventMixin('flat', {
.filter(function(task){
return titles.has(task.title) }) },
// actions...
//
send: function(title, ...args){
if(title == 'all' || title == '*'){
this.forEach(function(task){
@ -369,7 +403,6 @@ object.Constructor('TaskManager', Array, events.EventMixin('flat', {
title
: [title])
.send('all', ...args) },
// XXX each task should also trigger this when stopping and this
// should not result in this and tasks infinitely playing
// ping-pong...
@ -380,8 +413,11 @@ object.Constructor('TaskManager', Array, events.EventMixin('flat', {
function(handlers, title='all'){
this.send(title, 'stop') }),
done: events.Event('done'),
error: events.Event('error'),
// events...
//
done: events.PureEvent('done'),
tasksDone: events.PureEvent('tasksDone'),
error: events.PureEvent('error'),
//
@ -416,10 +452,6 @@ object.Constructor('TaskManager', Array, events.EventMixin('flat', {
//
// NOTE: the args are passed only if
// NOTE: the task is started as soon as it is accepted.
//
// XXX seems that we have a dangling promise someplace...
// ...if a task rejects node/chrome report an unhandled promise
// reject...
Task: function(title, task, ...args){
var that = this
@ -461,12 +493,9 @@ object.Constructor('TaskManager', Array, events.EventMixin('flat', {
// the context is ready...
run = function(){
var res =
task({
title,
resolve,
reject,
onmessage,
}, ...args)
task(
TaskTicket(title, resolve, reject, onmessage),
...args)
// NOTE: if the client calls resolve(..) this
// second resolve(..) call has no effect,
// and the same is true with reject...