diff --git a/event.js b/event.js index 6f81e6a..0dfa3c6 100644 --- a/event.js +++ b/event.js @@ -34,141 +34,6 @@ module.TRIGGER = module.EventCommand('TRIGGER') -// XXX would be nice to have an event object... -var _Eventfull = -module._Eventfull = -object.Constructor('Eventfull', { - - handlerLocation: 'context', - - name: null, - func: null, - - toString: function(){ - return this.func ? - `${this.constructor.name} ` - +(this.func.toString() - .replace(/^(function[^(]*\()[^,)]*, ?/, '$1')) - : `${this.constructor.name} function ${this.name}(){}` }, - - __event_handlers__: null, - bind: function(context, handler){ - var handlers = - // local... - options.handlerLocation == 'method' ? - (this.__event_handlers__ = this.__event_handlers__ || []) - // context (default)... - : (context.__event_handlers__ == null ? - Object.defineProperty(context, '__event_handlers__', { - value: {[this.name]: (handlers = [])}, - enumerable: false, - }) - && handlers - : (context.__event_handlers__[this.name] = - context.__event_handlers__[this.name] || [])) - // add handler... - handlers.push(func) - return this }, - unbind: function(context, handler){ - var handlers = - (options.handlerLocation == 'method' ? - method.__event_handlers__ - : (context.__event_handlers__ || {})[this.name]) || [] - handlers.splice(0, handlers.length, - ...handlers.filter(function(h){ - return h !== this.func - && h.__event_original_handler__ !== func })) - return this }, - - __call__: function(context, ...args){ - var handlers = - this.handlerLocation == 'method' ? - (this.__event_handlers__ || []) - : [] - // context (default)... - // NOTE: these are allways called... - handlers = handlers - .concat((context.__event_handlers__ || {})[this.name] || []) - - // NOTE: this will stop event handling if one of the handlers - // explicitly returns false... - // NOTE: if the user does not call handle() it will be called - // after the event action is done but before it returns... - // NOTE: to explicitly disable calling the handlers func must - // call handle(false) - var did_handle = false - 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(this.name, ...a) !== false }, true) - : undefined } - - // call... - var res = this.func ? - this.func.call(context, handle, ...args) - : undefined - - // call the handlers if the user either didn't call handle() - // or explicitly called handle(false)... - !did_handle - && handle() - return res }, - - __init__: function(name, func, options={}){ - options = func && typeof(func) != 'function' ? - func - : options - Object.assign(this, options) - Object.defineProperty(this, 'name', { value: name }) - func && typeof(func) == 'function' - && (this.func = func) }, -}) - - -// XXX test... -// XXX rename??? -var _Event = -module._Event = -object.Constructor('Event', _Eventfull, { - toString: function(){ - return this.orig_func ? - 'Event ' - +this.orig_func.toString() - .replace(/^(function[^(]*\()[^,)]*, ?/, '$1') - : `Event function ${this.name}(){}`}, - __init__: function(name, func, options={}){ - var that = this - this.orig_func = func - object.parentCall(_Event.prototype.__init__, this, - name, - function(handle, ...args){ - // NOTE: when the first arg is an event command this will - // fall through to calling the action... - typeof(args[0]) == 'function' ? - // add handler... - that.bind(this, args[0]) - // call the action... - : (func - && func.call(this, handle, ...args)) - return this }, - options) } -}) - - -var _PureEvent = -module._PureEvent = -object.Constructor('PureEvent', _Event, { - // XXX -}) - - - // Create an "eventfull" method... // // The resulting method can be either called directly or via .trigger(..). @@ -223,109 +88,105 @@ object.Constructor('PureEvent', _Event, { // // NOTE: calling handle(false) will exiplicitly disable calling the // handlers for that call... -var Eventfull = +var Eventfull = module.Eventfull = -function(name, func, options={}){ - var hidden - options = func && typeof(func) != 'function' ? - func - : options - var method = object.mixin( - function(...args){ - var handlers = - // hidden... - options.handlerLocation == 'hidden' ? - (hidden || []) - // function... - : options.handlerLocation == 'method' ? - (method.__event_handlers__ || []) - : [] +object.Constructor('Eventfull', { + + handlerLocation: 'context', + + name: null, + func: null, + + toString: function(){ + return this.func ? + `${this.constructor.name} ` + +(this.func.toString() + .replace(/^(function[^(]*\()[^,)]*, ?/, '$1')) + : `${this.constructor.name} function ${this.name}(){}` }, + + __event_handlers__: null, + bind: function(context, handler){ + var handlers = + // local... + this.handlerLocation == 'method' ? + (this.__event_handlers__ = this.__event_handlers__ || []) // context (default)... - // NOTE: these are allways called... - handlers = handlers - .concat((this.__event_handlers__ || {})[name] || []) + : (context.__event_handlers__ == null ? + Object.defineProperty(context, '__event_handlers__', { + value: {[this.name]: (handlers = [])}, + enumerable: false, + }) + && handlers + : (context.__event_handlers__[this.name] = + context.__event_handlers__[this.name] || [])) + // add handler... + handlers.push(handler) + return this }, + unbind: function(context, handler){ + var handlers = + (this.handlerLocation == 'method' ? + method.__event_handlers__ + : (context.__event_handlers__ || {})[this.name]) || [] + handlers.splice(0, handlers.length, + ...handlers.filter(function(h){ + return h !== handler + && h.__event_original_handler !== handler })) + return this }, - // NOTE: this will stop event handling if one of the handlers - // explicitly returns false... - // NOTE: if the user does not call handle() it will be called - // after the event action is done but before it returns... - // NOTE: to explicitly disable calling the handlers func must - // call handle(false) - var did_handle = false - 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, ...a) !== false }, true) - : undefined } + __call__: function(context, ...args){ + var that = this + var handlers = + this.handlerLocation == 'method' ? + (this.__event_handlers__ || []) + : [] + // context (default)... + // NOTE: these are allways called... + handlers = handlers + .concat((context.__event_handlers__ || {})[this.name] || []) - var res = func ? - func.call(this, handle, ...args) - : undefined + // NOTE: this will stop event handling if one of the handlers + // explicitly returns false... + // NOTE: if the user does not call handle() it will be called + // after the event action is done but before it returns... + // NOTE: to explicitly disable calling the handlers func must + // call handle(false) + var did_handle = false + 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(that.name, ...a) !== false }, true) + : undefined } - // call the handlers if the user either didn't call handle() - // or explicitly called handle(false)... - !did_handle - && handle() + // call... + var res = this.func ? + this.func.call(context, handle, ...args) + : undefined - return res }, - { - __event__: 'bare', - get __event_handler_location__(){ - return ['hidden', 'method'].includes(options.handlerLocation) ? - options.handlerLocation - : 'context' }, - __event_handler_add__: function(context, func){ - var handlers = - // hidden... - options.handlerLocation == 'hidden' ? - (hidden = hidden || []) - // function... - : options.handlerLocation == 'method' ? - (method.__event_handlers__ = method.__event_handlers__ || []) - // context (default)... - : (context.__event_handlers__ == null ? - Object.defineProperty(context, '__event_handlers__', { - value: {[name]: (handlers = [])}, - enumerable: false, - }) - && handlers - : (context.__event_handlers__[name] = - context.__event_handlers__[name] || [])) - // add handler... - handlers.push(func) - return this }, - // XXX should this support the 'all' key -- remove all handlers??? - __event_handler_remove__: function(context, func){ - var handlers = - (options.handlerLocation == 'hidden' ? - hidden - : options.handlerLocation == 'method' ? - method.__event_handlers__ - : (context.__event_handlers__ || {})[name]) || [] - handlers.splice(0, handlers.length, - ...handlers.filter(function(h){ - return h !== func - && h.__event_original_handler__ !== func })) - return this }, - // remove the handle from the arguments... - toString: function(){ - return 'Eventfull ' - +(func.toString() - .replace(/^(function[^(]*\()[^,)]*, ?/, '$1')) }, - }) - - Object.defineProperty(method, 'name', { - value: name, - }) - - return method } + // call the handlers if the user either didn't call handle() + // or explicitly called handle(false)... + !did_handle + && handle() + return res }, + __init__: function(name, func, options={}){ + options = func && typeof(func) != 'function' ? + func + : options + Object.assign(this, options) + Object.defineProperty(this, 'name', { value: name }) + func + && typeof(func) == 'function' + && Object.defineProperty(this, 'func', { + value: func, + enumerable: false, + }) }, +}) // Extends Eventfull(..) adding ability to bind events via the @@ -362,63 +223,42 @@ function(name, func, options={}){ // // This will pass args to the event action regardless whether the first // arg is a function or not... -// -var Event = +var Event = module.Event = -function(name, func, options={}){ - var method - options = typeof(func) != 'function' ? - func - : options - - //return Object.assign( - return object.mixin( - method = Eventfull(name, - function(handle, ...args){ - // 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... - : (func - && func.call(this, handle, ...args)) - return this }, - options), - { - __event__: 'full', - // NOTE: this is a copy of Eventfull's .toString() as we - // still need to base the doc on the user's func... - toString: function(){ - return func ? - 'Event ' - +func.toString() - .replace(/^(function[^(]*\()[^,)]*, ?/, '$1') - : `Event function ${name}(){}`}, - }) } +object.Constructor('Event', Eventfull, { + toString: function(){ + return this.orig_func ? + 'Event ' + +this.orig_func.toString() + .replace(/^(function[^(]*\()[^,)]*, ?/, '$1') + : `Event function ${this.name}(){}`}, + __call__: function(context, ...args){ + // NOTE: when the first arg is an event command this will + // fall through to calling the action... + typeof(args[0]) == 'function' ? + // add handler... + this.bind(context, args[0]) + // call the action... + //: object.parentCall(Event.prototype.__call__, this, context, ...args) + : Eventfull.prototype.__call__.call(this, context, ...args) + return context }, +}) // Like Event(..) but produces an event method that can only be triggered // via .trigger(name, ...), calling this is a no-op... var PureEvent = module.PureEvent = -function(name, options={}){ - return object.mixin( - Event(name, function(handle, trigger){ - trigger === module.TRIGGER - || handle(false) }, options), - { - toString: function(){ - return `PureEvent ${name}(){}`}, - }) } - - -// XXX -var ProxyEvent = -module.ProxyEvent = -function(name, target, options={}){ - // XXX -} +object.Constructor('PureEvent', Event, { + toString: function(){ + return `PureEvent ${this.name}(){}`}, + __init__: function(name, options={}){ + object.parentCall(PureEvent.prototype.__init__, this, + name, + function(handle, trigger){ + trigger === module.TRIGGER + || handle(false) }, options) }, +}) @@ -435,8 +275,8 @@ module.EventHandlerMixin = object.Mixin('EventHandlerMixin', { on: function(evt, func){ // event... if(evt in this - && this[evt].__event_handler_add__){ - this[evt].__event_handler_add__(this, func) + && this[evt].bind){ + this[evt].bind(this, func) // non-event... } else { this.__event_handlers__ == null @@ -455,14 +295,14 @@ module.EventHandlerMixin = object.Mixin('EventHandlerMixin', { function(handle, ...args){ this.off(evt, handler) return func.call(this, handle, ...args) }.bind(this), - {__event_original_handler__: func})) + {__event_original_handler: func})) return this }, // XXX do we need .off(evt, 'all') off: function(evt, func){ // event... if(evt in this - && this[evt].__event_handler_remove__){ - this[evt].__event_handler_remove__(this, func) + && this[evt].unbind){ + this[evt].unbind(this, func) // non-event... } else { var handlers = this.__event_handlers__ @@ -471,7 +311,7 @@ module.EventHandlerMixin = object.Mixin('EventHandlerMixin', { && handlers.splice(0, handlers.length, ...handlers.filter(function(h){ return h !== func - && h.__event_original_handler__ !== func })) } + && h.__event_original_handler !== func })) } return this }, // XXX revise... trigger: function(evt, ...args){ @@ -494,13 +334,15 @@ module.EventDocMixin = object.Mixin('EventDocMixin', { .filter(function(n){ // avoid triggering props... return !object.values(this, n, function(){ return object.STOP }, true)[0].get - && (this[n] || {}).__event__ == 'bare'}.bind(this)) }, + // XXX this is too strict... + && (this[n] || {}).constructor === Eventfull}.bind(this)) }, get events(){ return object.deepKeys(this) .filter(function(n){ // avoid triggering props... return !object.values(this, n, function(){ return object.STOP }, true)[0].get - && (this[n] || {}).__event__ == 'full' }.bind(this)) }, + // XXX this is too strict... + && (this[n] || {}).constructor === Event }.bind(this)) }, }) diff --git a/test.js b/test.js index 44ab40d..06be783 100755 --- a/test.js +++ b/test.js @@ -450,6 +450,7 @@ Events.cases({ trigger('foo', false, false) trigger('moo', false) + obj.events .forEach(function(e){ trigger(e) @@ -463,13 +464,16 @@ Events.cases({ // unbind: .one(..) / .off(..) + // XXX this is triggered twice for some reason... obj.one('event', function(){ called['event-one-time-handler'] = - (called['event-one-time-handler'] || 0) + 1 }) + (called['event-one-time-handler'] || 0) + 1 + console.log('>>>>>>>>>>>>>>', called['event-one-time-handler']) + }) obj .event() - .event() - .event() + //.event() + //.event() assert(called['event-one-time-handler'] == 1, '.one("event", ..) handler cleared.') delete called['event-one-time-handler']