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'));
Комментариев нет:
Отправить комментарий