exports.Hookable = Hookable; function Hookable() { // hookable class }; Hookable.afterInitialize = null; Hookable.beforeValidation = null; Hookable.afterValidation = null; Hookable.beforeSave = null; Hookable.afterSave = null; Hookable.beforeCreate = null; Hookable.afterCreate = null; Hookable.beforeUpdate = null; Hookable.afterUpdate = null; Hookable.beforeDestroy = null; Hookable.afterDestroy = null; Hookable.prototype.trigger = function trigger(actionName, work, data) { var capitalizedName = capitalize(actionName); var afterHook = this.constructor["after" + capitalizedName]; var beforeHook = this.constructor["before" + capitalizedName]; var inst = this; // we only call "before" hook when we have actual action (work) to perform if (work) { if (beforeHook) { // before hook should be called on instance with one param: callback beforeHook.call(inst, function () { // actual action also have one param: callback work.call(inst, next); }, data); } else { work.call(inst, next); } } else { next(); } function next(done) { if (afterHook) { afterHook.call(inst, done); } else if (done) { done.call(this); } } }; function capitalize(string) { return string.charAt(0).toUpperCase() + string.slice(1); }