index.js 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. module.exports = function eventify(subject) {
  2. validateSubject(subject);
  3. var eventsStorage = createEventsStorage(subject);
  4. subject.on = eventsStorage.on;
  5. subject.off = eventsStorage.off;
  6. subject.fire = eventsStorage.fire;
  7. return subject;
  8. };
  9. function createEventsStorage(subject) {
  10. // Store all event listeners to this hash. Key is event name, value is array
  11. // of callback records.
  12. //
  13. // A callback record consists of callback function and its optional context:
  14. // { 'eventName' => [{callback: function, ctx: object}] }
  15. var registeredEvents = Object.create(null);
  16. return {
  17. on: function (eventName, callback, ctx) {
  18. if (typeof callback !== 'function') {
  19. throw new Error('callback is expected to be a function');
  20. }
  21. var handlers = registeredEvents[eventName];
  22. if (!handlers) {
  23. handlers = registeredEvents[eventName] = [];
  24. }
  25. handlers.push({callback: callback, ctx: ctx});
  26. return subject;
  27. },
  28. off: function (eventName, callback) {
  29. var wantToRemoveAll = (typeof eventName === 'undefined');
  30. if (wantToRemoveAll) {
  31. // Killing old events storage should be enough in this case:
  32. registeredEvents = Object.create(null);
  33. return subject;
  34. }
  35. if (registeredEvents[eventName]) {
  36. var deleteAllCallbacksForEvent = (typeof callback !== 'function');
  37. if (deleteAllCallbacksForEvent) {
  38. delete registeredEvents[eventName];
  39. } else {
  40. var callbacks = registeredEvents[eventName];
  41. for (var i = 0; i < callbacks.length; ++i) {
  42. if (callbacks[i].callback === callback) {
  43. callbacks.splice(i, 1);
  44. }
  45. }
  46. }
  47. }
  48. return subject;
  49. },
  50. fire: function (eventName) {
  51. var callbacks = registeredEvents[eventName];
  52. if (!callbacks) {
  53. return subject;
  54. }
  55. var fireArguments;
  56. if (arguments.length > 1) {
  57. fireArguments = Array.prototype.splice.call(arguments, 1);
  58. }
  59. for(var i = 0; i < callbacks.length; ++i) {
  60. var callbackInfo = callbacks[i];
  61. callbackInfo.callback.apply(callbackInfo.ctx, fireArguments);
  62. }
  63. return subject;
  64. }
  65. };
  66. }
  67. function validateSubject(subject) {
  68. if (!subject) {
  69. throw new Error('Eventify cannot use falsy object as events subject');
  70. }
  71. var reservedWords = ['on', 'fire', 'off'];
  72. for (var i = 0; i < reservedWords.length; ++i) {
  73. if (subject.hasOwnProperty(reservedWords[i])) {
  74. throw new Error("Subject cannot be eventified, since it already has property '" + reservedWords[i] + "'");
  75. }
  76. }
  77. }