пятница, 19 июля 2013 г.

Observer Library

function Observer () {
    this.eventList = {};
}

Observer.prototype = {
   
      _isInt: function (x) {
            var y = parseInt(x, 10);
            if (isNaN(y)) {
              return false;
            }
            return x === y && x.toString() === y.toString();
      }
   
    , addEvent: function (eventName, callbackFunction) {      
            // TEST BEGIN =================================================
            if (Object.prototype.toString.call(eventName)  !== '[object String]') {
                throw new Error('Error! Observer\'s first argument of addEvent method must be a string.');
            }
            if (Object.prototype.toString.call(callbackFunction) !== '[object Function]') {
                throw new Error('Error! Observer\'s second argument of addEvent method must be a function.');
            }
            // TEST END =================================================
           
            if (!this.eventList[eventName]) {
                this.eventList[eventName] = [];
            }
            this.eventList[eventName].push(callbackFunction);
            return this;        
     }
   
   , addEventOnceThenRemoveItAfterEmission: function (eventName, callbackFunction) {
            // TEST BEGIN =================================================
            var self = this
                , removeEventAfterEmission;
            if (Object.prototype.toString.call(eventName)  !== '[object String]') {
                throw new Error('Error! Observer\'s first argument of addEventOnceThenRemoveItAfterEmission method must be a string.');
            }
            if (Object.prototype.toString.call(callbackFunction) !== '[object Function]') {
                throw new Error('Error! Observer\'s second argument of addEventOnceThenRemoveItAfterEmission method must be a function.');
            }
            // TEST END =================================================
           
            if (!this.eventList[eventName]) {
                this.eventList[eventName] = [];
            }
            removeEventAfterEmission = function () {
                callbackFunction.apply(this, arguments);
                self.removeEventByIndex(eventName, this.eventList[eventName].indexOf(removeEventAfterEmission));
            }
            this.eventList[eventName].push(removeEventAfterEmission);
            return this;
     }
   
   , removeEventByIndex: function (eventName, index) {
            // TEST BEGIN =================================================
            if (Object.prototype.toString.call(eventName)  !== '[object String]') {
                throw new Error('Error! Observer\'s first argument of removeEventByIndex method must be a string.');
            }
            if (Object.prototype.toString.call(index)  !== '[object Number]') {
                throw new Error('Error! Observer\'s first argument of removeEventByIndex method must be a number.');
            }
            if (!this._isInt(index)) {
                throw new Error('Error! Observer\'s first argument of removeEventByIndex method must be an integer.');
            }
            // TEST END =================================================
           
            if (this.eventList[eventName]) {
                if (index > -1 && index < this.eventList[eventName].length) {
                    Array.prototype.splice.call(this.eventList[eventName], index, 1);
                }
                if (this.eventList[eventName].length === 0) {
                    delete this.eventList[eventName];
                }
            }
            return this;  
      }
     
    , removeAllEventsByName: function (eventName) {
            // TEST BEGIN =================================================
            if (Object.prototype.toString.call(eventName)  !== '[object String]') {
                throw new Error('Error! Observer\'s first argument of removeAllEvents method must be a string.');
            }
            // TEST END =================================================
           
            if (this.eventList[eventName]) {
                delete this.eventList[eventName];
            }
            return this;
      }
   
    , emitEvent: function (eventName) {
            // TEST BEGIN =================================================
            var data
                , eventListFunctionsLength
                , i;
            if (arguments.length > 1) {
                  data = Array.prototype.slice.call(arguments, 1);
            } else if (arguments.length < 1) {
                  throw new Error('Error! You must pass arguments into observer\'s emitEvent method.');
            }
            if (Object.prototype.toString.call(eventName)  !== '[object String]') {
                throw new Error('Error! Observer\'s first argument of emitEvent method must be a string.');
            }
            // TEST END =================================================
           
            if (this.eventList[eventName]) {
                eventListFunctionsLength = this.eventList[eventName].length;
                for (i = 0; i < eventListFunctionsLength; i++) {
                    this.eventList[eventName][i].apply(this, data);
                }
            }
            return this;
      }
   
    , triggerEvent: function (eventName) {
            // TEST BEGIN =================================================
            var data
                , key
                , i;
            if (arguments.length > 1) {
                  data = Array.prototype.slice.call(arguments, 1);
            } else if (arguments.length < 1) {
                  throw new Error('Error! You must pass arguments into observer\'s triggerEvent method.');
            }
            if (Object.prototype.toString.call(eventName)  !== '[object String]') {
                throw new Error('Error! Observer\'s first argument of triggerEvent method must be a string.');
            }
            // TEST END =================================================
           
            for (key in this.eventList) {
                if (key === eventName) {
                    for (i = 0; i < this.eventList[key].length; i++) {
                        this.eventList[key][i].apply(this, data);
                    }
                }
            }
            return this;
      }
     
    , triggerEventByIndex: function (eventName, index) {
            // TEST BEGIN =================================================
            var data
                , key;
            if (arguments.length > 2) {
                  data = Array.prototype.slice.call(arguments, 2);
            } else if (arguments.length < 1 || arguments.length < 2) {
                  throw new Error('Error! You must pass event name and event index into observer\'s triggerEventByIndex method.');
            }
            if (Object.prototype.toString.call(eventName)  !== '[object String]') {
                throw new Error('Error! Observer\'s first argument of triggerEventByIndex method must be a string.');
            }
            if (Object.prototype.toString.call(index)  !== '[object Number]') {
                throw new Error('Error! Observer\'s first argument of triggerEventByIndex method must be a number.');
            }
            if (!this._isInt(index)) {
                throw new Error('Error! Observer\'s first argument of triggerEventByIndex method must be an integer.');
            }
            // TEST END =================================================
           
            for (key in this.eventList) {
                if (key === eventName) {
                    if (index > -1 && index < this.eventList[key].length) {
                        this.eventList[key][index].apply(this, data);
                    }                  
                }
            }
            return this;
      }
     
    , countAllEventsByName: function(eventName) {
            // TEST BEGIN =================================================
            if (Object.prototype.toString.call(eventName)  !== '[object String]') {
                throw new Error('Error! Observer\'s first argument of countAllEventsByName method must be a string.');
            }
            // TEST END =================================================
           
            if (this.eventList[eventName]) {
                return this.eventList[eventName].length;
            }
            return 0;
     }
   
    , countAllEventsByType: function() {
            var eventsLength = 0
                , key;
            for (key in this.eventList) {
                if (this.eventList.hasOwnProperty(key)) {
                    eventsLength++;
                }
            }
            return eventsLength;
     }
   
     // Shortcuts

   , on: function () {
            return this.addEvent.apply(this, arguments);
     }
   
   , once: function () {
            return this.addEventOnceThenRemoveItAfterEmission.apply(this, arguments);
     }
   
   , off: function () {
            return this.removeEventByIndex.apply(this, arguments);
     }
 
   , offAll: function () {
            return this.removeAllEventsByName.apply(this, arguments);
     }
   
   , emit: function () {
            return this.emitEvent.apply(this, arguments);
     }
   
   , trigger: function () {
            return this.triggerEvent.apply(this, arguments);
     }
   
   , triggerByIndex: function () {
            return this.triggerEventByIndex.apply(this, arguments);
     }
   
   , count: function () {
            return this.countAllEventsByName.apply(this, arguments);
     }
   
   , countAll: function () {
            return this.countAllEventsByType.apply(this, arguments);
     }
   
     // Other synonyms
   
     // Add event
   
   , subscribe: function () {
            return this.addEvent.apply(this, arguments);
     }

   , addEventListener: function () {
            return this.addEvent.apply(this, arguments);
     }

   , attach: function () {
            return this.addEvent.apply(this, arguments);
     }

   , one: function () {
            return this.addEventOnceThenRemoveItAfterEmission.apply(this, arguments);
     }
   
     // Remove event
   
   , unsubscribe: function () {
            return this.removeEventByIndex.apply(this, arguments);
     }

   , removeEventListener: function () {
            return this.removeEventByIndex.apply(this, arguments);
     }

   , detach: function () {
            return this.removeEventByIndex.apply(this, arguments);
     }
   
     // Emit event
   
   , publish: function () {
            return this.emitEvent.apply(this, arguments);
     }

   , broadcastEvent: function () {
            return this.emitEvent.apply(this, arguments);
     }

   , broadcast: function () {
            return this.emitEvent.apply(this, arguments);
     }

   , translateEvent: function () {
            return this.emitEvent.apply(this, arguments);
     }

   , notify: function () {
            return this.emitEvent.apply(this, arguments);
     }
   
     // Trigger event
   
   , fireEvent: function () {
            return this.triggerEvent.apply(this, arguments);
     }
   
   , fire: function () {
            return this.triggerEvent.apply(this, arguments);
     }
   
     // Count events
   
   , countEvents: function () {
            return this.countAllEventsByName.apply(this, arguments);
     }
 
   , countAllEvents: function () {
            return this.countAllEventsByType.apply(this, arguments);
     }
   
};

Observer.extend = function (obj) {
    var key;
    for (key in Observer) {
      obj[key] = Observer[key];
    }
};

// TESTS

var observer = new Observer();

observer.addEvent('one', function(){console.log('One event');}); console.log('1: Added One');
observer.addEvent('two', function(){console.log('Two event');}); console.log('2: Added Two');

console.log('3: countAllEventsByName: ' + observer.countAllEventsByName('one'));
console.log('4: countAllEventsByType: ' + observer.countAllEventsByType());

observer.removeEventByIndex('one', 0); console.log('5: Removed One');
   
console.log('6: countAllEventsByName: ' + observer.countAllEventsByName('one'));

observer.removeAllEventsByName('two'); console.log('7: Removed Two');

console.log('8: countAllEventsByName: ' + observer.countAllEventsByName('two'));

console.log('9: countAllEventsByType: ' + observer.countAllEventsByType());

observer.addEvent('three', function(data1){console.log('Three data1: ' + data1);}); console.log('10: Added Three');
observer.addEvent('four', function(data1, data2){console.log('Four data1: ' + data1 + ', data2: ' + data2);}); console.log('11: Added Four');

console.log('12: countAllEventsByName: ' + observer.countAllEventsByName('three'));
console.log('13: countAllEventsByType: ' + observer.countAllEventsByType());

console.log('14: Triggered Three');
observer.triggerEvent('three', 'a', 'b');

console.log('15: Triggered Four');
observer.triggerEvent('four', 'c', 'd');

observer.addEvent('three', function(data1){console.log('Second Three data1: ' + data1);}); console.log('16: Added Second Three');

console.log('17: Triggered Second Three');
observer.triggerEventByIndex('three', 1, 'g');

console.log('18: Emit event Three DOUBLE');

observer.emitEvent('three', 'f');

console.log('19: Synonyms');

console.log('20: countAllEventsByName: ' + observer.count('three'));  
console.log('21: countAllEventsByType: ' + observer.countAll());

observer.off('three', 1); console.log('22: Removed Second Three');
observer.offAll('three');  console.log('23: Removed Three');

console.log('24: countAllEventsByName: ' + observer.count('three'));  
console.log('25: countAllEventsByType: ' + observer.countAll());

console.log('26: Triggered Four');
observer.trigger('four', 'x', 'y');

console.log('27: Emit event Four');

observer.emit('four', 'h', 'k');

observer.on('five', function(){console.log('Five event');}); console.log('28: Added Five 1');
observer.emit('five');

console.log('29: Test addEventOnceThenRemoveItAfterEmission');

observer.addEventOnceThenRemoveItAfterEmission('six', function(data) {console.log('Six data: ' + data);});  console.log('30: Added Six Once');

console.log('31: Emit Six Once');
observer.emit('six', 'OK');

console.log('32: countAllEventsByName: ' + observer.count('six'));

console.log('33: Test Once');

observer.once('six', function(data) {console.log('Six data: ' + data);});  console.log('34: Added Six Once');

console.log('35: Emit Six Once');
observer.emit('six', 'GOOD');

console.log('36: countAllEventsByName: ' + observer.count('six'));

Комментариев нет:

Отправить комментарий