Newer
Older
pixi.js / src / pixi / utils / EventTarget.js
@Chad Engler Chad Engler on 23 Mar 2014 4 KB move listeners to be lazy added
/**
 * @author Mat Groves http://matgroves.com/ @Doormat23
 * @author Chad Engler https://github.com/englercj @Rolnaaba
 */

/**
 * Originally based on https://github.com/mrdoob/eventtarget.js/ from mr DOob.
 * Currently takes inspiration from the nodejs EventEmitter, and EventEmitter3
 */

/**
 * Mixins event emitter functionality to a class
 *
 * @class EventTarget
 * @example
 *      function MyEmitter() {
 *          PIXI.EventTarget.call(this); //mixes in event target stuff
 *      }
 *
 *      var em = new MyEmitter();
 *      em.emit('eventName', 'some data', 'some moar data', {}, null, ...);
 */
PIXI.EventTarget = function() {
    /**
     * Return a list of assigned event listeners.
     *
     * @param eventName {String} The events that should be listed.
     * @returns {Array}
     * @api public
     */
    this.listeners = function listeners(eventName) {
        return Array.apply(this, this._listeners[eventName] || []);
    };

    /**
     * Emit an event to all registered event listeners.
     *
     * @param eventName {String} The name of the event.
     * @returns {Boolean} Indication if we've emitted an event.
     * @api public
     */
    this.emit = function emit(eventName, data) {
        if(!data || data.__isEventObject !== true)
            data = new PIXI.Event(this, eventName, data);

        if(this._listeners && this._listeners[eventName]) {
            var listeners = this._listeners[eventName],
                length = listeners.length,
                fn = listeners[0],
                i;

            for(i = 0; i < length; fn = listeners[++i]) {
                //call the event listener
                fn.call(this, data);

                //remove the listener if this is a "once" event
                if(fn.__isOnce)
                    this.off(eventName, fn);

                //if "stopImmediatePropagation" is called, stop calling all events
                if(data.stoppedImmediate)
                    return;
            }

            //if "stopPropagation" is called then don't bubble the event
            if(data.stopped)
                return;
        }

        if(this.parent && this.parent.emit) {
            this.parent.emit.call(this.parent, eventName, data);
        }

        return true;
    };

    /**
     * Register a new EventListener for the given event.
     *
     * @param eventName {String} Name of the event.
     * @param callback {Functon} fn Callback function.
     * @api public
     */
    this.on = function on(eventName, fn) {
        if(!this._listeners)
            this._listeners = {};

        if(!this._listeners[eventName])
            this._listeners[eventName] = [];

        this._listeners[eventName].push(fn);

        return this;
    };

    /**
     * Add an EventListener that's only called once.
     *
     * @param eventName {String} Name of the event.
     * @param callback {Function} Callback function.
     * @api public
     */
    this.once = function once(eventName, fn) {
        fn.__isOnce = true;
        return this.on(eventName, fn);
    };

    /**
     * Remove event listeners.
     *
     * @param eventName {String} The event we want to remove.
     * @param callback {Function} The listener that we need to find.
     * @api public
     */
    this.off = function off(eventName, fn) {
        if(!this._listeners[eventName])
            return this;

        var index = this._listeners[eventName].indexOf(fn);

        if(index !== -1) {
            this._listeners[eventName].splice(index, 1);
        }

        return this;
    };

    /**
     * Remove all listeners or only the listeners for the specified event.
     *
     * @param eventName {String} The event want to remove all listeners for.
     * @api public
     */
    this.removeAllListeners = function removeAllListeners(eventName) {
        if(!this._listeners[eventName])
            return this;

        this._listeners[eventName].length = 0;

        return this;
    };

    /**
     * Alias methods names because people roll like that.
     */
    this.removeEventListener = this.off;
    this.addEventListener = this.on;
    this.dispatchEvent = this.emit;
};

PIXI.Event = function(target, name, data) {
    this.__isEventObject = true;

    this.stopped = false;
    this.stoppedImmediate = false;

    this.target = target;
    this.type = name;
    this.data = data;

    this.timeStamp = Date.now();
};

PIXI.Event.prototype.stopPropagation = function() {
    this.stopped = true;
};

PIXI.Event.prototype.stopImmediatePropagation = function() {
    this.stoppedImmediate = true;
};