"use strict";
/**
* Extends the Event-instance by adding the object `Listener` to it.
* The returned object should be merged into any Class-instance or object you want to
* extend with the listener-methods, so the appropriate methods can be invoked on the instance.
*
*
* <i>Copyright (c) 2014 ITSA - https://github.com/itsa</i>
* New BSD License - http://choosealicense.com/licenses/bsd-3-clause/
*
*
* Should be called using the provided `extend`-method like this:
* @example
* var Event = require('event');<br>
*
* @module event
* @submodule event-listener
* @class Event.Listener
* @since 0.0.1
*/
require('js-ext/lib/object.js');
var Event = require('./event-base.js'),
Classes = require("js-ext/extra/classes.js"),
callbackFn, ClassListener;
Event.Listener = {
/**
* Subscribes to a customEvent on behalf of the object who calls this method.
* The callback will be executed `after` the defaultFn.
*
* @method after
* @param customEvent {String|Array} the custom-event (or Array of events) to subscribe to. CustomEvents should
* have the syntax: `emitterName:eventName`. Wildcard `*` may be used for both `emitterName` as well as `eventName`.
* If `emitterName` is not defined, `UI` is assumed.
* @param callback {Function} subscriber:will be invoked when the event occurs. An `eventobject` will be passed
* as its only argument.
* @param [filter] {String|Function} to filter the event.
* Use a String if you want to filter DOM-events by a `selector`
* Use a function if you want to filter by any other means. If the function returns a trully value, the
* subscriber gets invoked. The function gets the `eventobject` as its only argument and the context is
* the subscriber.
* @param [prepend=false] {Boolean} whether the subscriber should be the first in the list of after-subscribers.
* @return {Object} handler with a `detach()`-method which can be used to detach the subscriber
* @since 0.0.1
*/
after: function (customEvent, callback, filter, prepend) {
return Event.after(customEvent, callback, this, filter, prepend);
},
/**
* Subscribes to a customEvent on behalf of the object who calls this method.
* The callback will be executed `before` the defaultFn.
*
* @method before
* @param customEvent {String|Array} the custom-event (or Array of events) to subscribe to. CustomEvents should
* have the syntax: `emitterName:eventName`. Wildcard `*` may be used for both `emitterName` as well as `eventName`.
* If `emitterName` is not defined, `UI` is assumed.
* @param callback {Function} subscriber:will be invoked when the event occurs. An `eventobject` will be passed
* as its only argument.
* @param [filter] {String|Function} to filter the event.
* Use a String if you want to filter DOM-events by a `selector`
* Use a function if you want to filter by any other means. If the function returns a trully value, the
* subscriber gets invoked. The function gets the `eventobject` as its only argument and the context is
* the subscriber.
* @param [prepend=false] {Boolean} whether the subscriber should be the first in the list of before-subscribers.
* @return {Object} handler with a `detach()`-method which can be used to detach the subscriber
* @since 0.0.1
*/
before: function (customEvent, callback, filter, prepend) {
return Event.before(customEvent, callback, this, filter, prepend);
},
/**
* Detaches (unsubscribes) the listener from the specified customEvent,
* on behalf of the object who calls this method.
*
* @method detach
* @param customEvent {String} conform the syntax: `emitterName:eventName`, wildcard `*` may be used for both
* `emitterName` as well as only `eventName`, in which case 'UI' will become the emitterName.
* @since 0.0.1
*/
detach: function(customEvent) {
Event.detach(this, customEvent);
},
/**
* Detaches (unsubscribes) the listener from all customevents,
* on behalf of the object who calls this method.
*
* @method detachAll
* @since 0.0.1
*/
detachAll: function() {
Event.detachAll(this);
},
/**
* Subscribes to a customEvent on behalf of the object who calls this method.
* The callback will be executed `after` the defaultFn.
* The subscriber will be automaticly removed once the callback executed the first time.
* No need to `detach()` (unless you want to undescribe before the first event)
*
* @method onceAfter
* @param customEvent {String|Array} the custom-event (or Array of events) to subscribe to. CustomEvents should
* have the syntax: `emitterName:eventName`. Wildcard `*` may be used for both `emitterName` as well as `eventName`.
* If `emitterName` is not defined, `UI` is assumed.
* @param callback {Function} subscriber:will be invoked when the event occurs. An `eventobject` will be passed
* as its only argument.
* @param [filter] {String|Function} to filter the event.
* Use a String if you want to filter DOM-events by a `selector`
* Use a function if you want to filter by any other means. If the function returns a trully value, the
* subscriber gets invoked. The function gets the `eventobject` as its only argument and the context is
* the subscriber.
* @param [prepend=false] {Boolean} whether the subscriber should be the first in the list of after-subscribers.
* @return {Object} handler with a `detach()`-method which can be used to detach the subscriber
* @since 0.0.1
*/
onceAfter: function (customEvent, callback, filter, prepend) {
return Event.onceAfter(customEvent, callback, this, filter, prepend);
},
/**
* Subscribes to a customEvent on behalf of the object who calls this method.
* The callback will be executed `before` the defaultFn.
* The subscriber will be automaticly removed once the callback executed the first time.
* No need to `detach()` (unless you want to undescribe before the first event)
*
* @method onceBefore
* @param customEvent {String|Array} the custom-event (or Array of events) to subscribe to. CustomEvents should
* have the syntax: `emitterName:eventName`. Wildcard `*` may be used for both `emitterName` as well as `eventName`.
* If `emitterName` is not defined, `UI` is assumed.
* @param callback {Function} subscriber:will be invoked when the event occurs. An `eventobject` will be passed
* as its only argument.
* @param [filter] {String|Function} to filter the event.
* Use a String if you want to filter DOM-events by a `selector`
* Use a function if you want to filter by any other means. If the function returns a trully value, the
* subscriber gets invoked. The function gets the `eventobject` as its only argument and the context is
* the subscriber.
* @param [prepend=false] {Boolean} whether the subscriber should be the first in the list of before-subscribers.
* @return {Object} handler with a `detach()`-method which can be used to detach the subscriber
* @since 0.0.1
*/
onceBefore: function (customEvent, callback, filter, prepend) {
return Event.onceBefore(customEvent, callback, this, filter, prepend);
}
};
callbackFn = function(callback, e) {
var instance = this,
eTarget = e.target,
accept;
accept = (eTarget===instance) || (eTarget.vnode && instance.vnode && instance.contains(eTarget));
accept && callback.call(instance, e);
};
Event._CE_listener = ClassListener = {
/**
* Is automaticly available for Classes.
* Subscribes to a customEvent on behalf of the class-instance and will only
* be executed when the emitter is the instance itself.
*
* The callback will be executed `after` the defaultFn.
*
* @method selfAfter
* @param customEvent {String|Array} the custom-event (or Array of events) to subscribe to. CustomEvents should
* have the syntax: `emitterName:eventName`. Wildcard `*` may be used for both `emitterName` as well as `eventName`.
* If `emitterName` is not defined, `UI` is assumed.
* @param callback {Function} subscriber:will be invoked when the event occurs. An `eventobject` will be passed
* as its only argument.
* @param [filter] {String|Function} to filter the event.
* Use a String if you want to filter DOM-events by a `selector`
* Use a function if you want to filter by any other means. If the function returns a trully value, the
* subscriber gets invoked. The function gets the `eventobject` as its only argument and the context is
* the subscriber.
* @param [prepend=false] {Boolean} whether the subscriber should be the first in the list of after-subscribers.
* @return {Object} handler with a `detach()`-method which can be used to detach the subscriber
* @since 0.0.1
*/
selfAfter: function (customEvent, callback, filter, prepend) {
return Event.after(customEvent, callbackFn.bind(this, callback), this, filter, prepend);
},
/**
* Is automaticly available for Classes.
* Subscribes to a customEvent on behalf of the class-instance and will only
* be executed when the emitter is the instance itself.
*
* The callback will be executed `before` the defaultFn.
*
* @method selfBefore
* @param customEvent {String|Array} the custom-event (or Array of events) to subscribe to. CustomEvents should
* have the syntax: `emitterName:eventName`. Wildcard `*` may be used for both `emitterName` as well as `eventName`.
* If `emitterName` is not defined, `UI` is assumed.
* @param callback {Function} subscriber:will be invoked when the event occurs. An `eventobject` will be passed
* as its only argument.
* @param [filter] {String|Function} to filter the event.
* Use a String if you want to filter DOM-events by a `selector`
* Use a function if you want to filter by any other means. If the function returns a trully value, the
* subscriber gets invoked. The function gets the `eventobject` as its only argument and the context is
* the subscriber.
* @param [prepend=false] {Boolean} whether the subscriber should be the first in the list of before-subscribers.
* @return {Object} handler with a `detach()`-method which can be used to detach the subscriber
* @since 0.0.1
*/
selfBefore: function (customEvent, callback, filter, prepend) {
return Event.before(customEvent, callbackFn.bind(this, callback), this, filter, prepend);
},
/**
* Is automaticly available for Classes.
* Subscribes to a customEvent on behalf of the class-instance and will only
* be executed when the emitter is the instance itself.
*
* The callback will be executed `after` the defaultFn.
* The subscriber will be automaticly removed once the callback executed the first time.
* No need to `detach()` (unless you want to undescribe before the first event)
*
* @method selfOnceAfter
* @param customEvent {String|Array} the custom-event (or Array of events) to subscribe to. CustomEvents should
* have the syntax: `emitterName:eventName`. Wildcard `*` may be used for both `emitterName` as well as `eventName`.
* If `emitterName` is not defined, `UI` is assumed.
* @param callback {Function} subscriber:will be invoked when the event occurs. An `eventobject` will be passed
* as its only argument.
* @param [filter] {String|Function} to filter the event.
* Use a String if you want to filter DOM-events by a `selector`
* Use a function if you want to filter by any other means. If the function returns a trully value, the
* subscriber gets invoked. The function gets the `eventobject` as its only argument and the context is
* the subscriber.
* @param [prepend=false] {Boolean} whether the subscriber should be the first in the list of after-subscribers.
* @return {Object} handler with a `detach()`-method which can be used to detach the subscriber
* @since 0.0.1
*/
selfOnceAfter: function (customEvent, callback, filter, prepend) {
return Event.onceAfter(customEvent, callbackFn.bind(this, callback), this, filter, prepend);
},
/**
* Is automaticly available for Classes.
* Subscribes to a customEvent on behalf of the class-instance and will only
* be executed when the emitter is the instance itself.
*
* The callback will be executed `before` the defaultFn.
* The subscriber will be automaticly removed once the callback executed the first time.
* No need to `detach()` (unless you want to undescribe before the first event)
*
* @method selfOnceBefore
* @param customEvent {String|Array} the custom-event (or Array of events) to subscribe to. CustomEvents should
* have the syntax: `emitterName:eventName`. Wildcard `*` may be used for both `emitterName` as well as `eventName`.
* If `emitterName` is not defined, `UI` is assumed.
* @param callback {Function} subscriber:will be invoked when the event occurs. An `eventobject` will be passed
* as its only argument.
* @param [filter] {String|Function} to filter the event.
* Use a String if you want to filter DOM-events by a `selector`
* Use a function if you want to filter by any other means. If the function returns a trully value, the
* subscriber gets invoked. The function gets the `eventobject` as its only argument and the context is
* the subscriber.
* @param [prepend=false] {Boolean} whether the subscriber should be the first in the list of before-subscribers.
* @return {Object} handler with a `detach()`-method which can be used to detach the subscriber
* @since 0.0.1
*/
selfOnceBefore: function (customEvent, callback, filter, prepend) {
return Event.onceBefore(customEvent, callbackFn.bind(this, callback), this, filter, prepend);
},
destroy: function(notChained) {
var instance = this,
superDestroy;
if (!instance._destroyed) {
superDestroy = function(constructor) {
// don't call `hasOwnProperty` directly on obj --> it might have been overruled
Object.prototype.hasOwnProperty.call(constructor.prototype, '_destroy') && constructor.prototype._destroy.call(instance);
if (!notChained && constructor.$$super) {
instance.__classCarier__ = constructor.$$super.constructor;
superDestroy(constructor.$$super.constructor);
}
};
superDestroy(instance.constructor);
instance.detachAll();
instance.undefAllEvents && instance.undefAllEvents();
Object.protectedProp(instance, '_destroyed', true);
}
}
};
// Patching Classes.BaseClass to make it an eventlistener that auto cleans-up:
Classes.BaseClass.mergePrototypes(Event.Listener, true)
.mergePrototypes(ClassListener, true, {}, {});
module.exports = Event;