/**
@namespace
*/
(function(module, ns) {
/**
* Constructor
*
* @param {Object} list of events to add onto responder.
*/
function Responder(events) {
this._$events = Object.create(null);
if (typeof(events) !== 'undefined') {
this.addEventListener(events);
}
};
/**
* Stringifies request to websocket
*
*
* @param {String} command command name.
* @param {Object} data object to be sent over the wire.
* @return {String} json object.
*/
Responder.stringify = function stringify(command, data) {
return JSON.stringify([command, data]);
};
/**
* Parses request from WebSocket.
*
* @param {String} json json string to translate.
* @return {Object} ex: { event: 'test', data: {} }.
*/
Responder.parse = function parse(json) {
var data;
try {
data = (json.forEach) ? json : JSON.parse(json);
} catch (e) {
throw new Error("Could not parse json: '" + json + '"');
}
return {event: data[0], data: data[1]};
};
Responder.prototype = {
parse: Responder.parse,
stringify: Responder.stringify,
/**
* Events on this instance
*
* @type Object
*/
_$events: null,
/**
* Recieves json string event and dispatches an event.
*
* @param {String|Object} json data object to respond to.
* @param {String} json.event event to emit.
* @param {Object} json.data data to emit with event.
* @param {Object} [params] option number of params to pass to emit.
* @return {Object} result of WebSocketCommon.parse.
*/
respond: function respond(json) {
var event = Responder.parse(json),
args = Array.prototype.slice.call(arguments).slice(1);
args.unshift(event.data);
args.unshift(event.event);
this.emit.apply(this, args);
return event;
},
//TODO: Extract event emitter logic
/**
* Adds an event listener to this object.
*
*
* @param {String} type event name.
* @param {Function} callback event callback.
*/
addEventListener: function addEventListener(type, callback) {
var event;
if (typeof(callback) === 'undefined' && typeof(type) === 'object') {
for (event in type) {
if (Object.hasOwnProperty.call(type, event)) {
this.addEventListener(event, type[event]);
}
}
return this;
}
if (!(type in this._$events)) {
this._$events[type] = [];
}
this._$events[type].push(callback);
return this;
},
/**
* Adds an event listener which will
* only fire once and then remove itself.
*
*
* @param {String} type event name.
* @param {Function} callback fired when event is emitted.
*/
once: function once(type, callback) {
var self = this;
function onceCb() {
self.removeEventListener(type, onceCb);
callback.apply(this, arguments);
}
this.addEventListener(type, onceCb);
return this;
},
/**
* Emits an event.
*
* Accepts any number of additional arguments to pass unto
* event listener.
*
* @param {String} eventName name of the event to emit.
* @param {Object} [arguments] additional arguments to pass.
*/
emit: function emit() {
var args = Array.prototype.slice.call(arguments),
event = args.shift(),
eventList,
self = this;
if (event in this._$events) {
eventList = this._$events[event];
eventList.forEach(function(callback) {
callback.apply(self, args);
});
}
return this;
},
/**
* Removes all event listeners for a given event type
*
*
* @param {String} event event type to remove.
*/
removeAllEventListeners: function removeAllEventListeners(name) {
if (name in this._$events) {
//reuse array
this._$events[name].length = 0;
}
return this;
},
/**
* Removes a single event listener from a given event type
* and callback function.
*
*
* @param {String} eventName event name.
* @param {Function} callback same instance of event handler.
*/
removeEventListener: function removeEventListener(name, callback) {
var i, length, events;
if (!(name in this._$events)) {
return false;
}
events = this._$events[name];
for (i = 0, length = events.length; i < length; i++) {
if (events[i] && events[i] === callback) {
events.splice(i, 1);
return true;
}
}
return false;
}
};
Responder.prototype.on = Responder.prototype.addEventListener;
module.exports = Responder;
}.apply(
this,
(this.Caldav) ?
[Caldav('responder'), Caldav] :
[module, require('./caldav')]
));