From 5e16f1976cbb9f63f05005ba491f8b1aa342e337 Mon Sep 17 00:00:00 2001 From: Mikael Brassman Date: Tue, 29 Jul 2014 22:22:37 +0200 Subject: [PATCH] Added hooks preEmit and shouldEmit on actions. Fixes #16 --- dist/reflux.js | 21 +++++++++- dist/reflux.min.js | 2 +- src/createAction.js | 21 +++++++++- test/creatingActions.spec.js | 80 +++++++++++++++++++++++++++++++++++- test/creatingStores.spec.js | 2 +- 5 files changed, 120 insertions(+), 6 deletions(-) diff --git a/dist/reflux.js b/dist/reflux.js index 29fa026..bd28b5c 100644 --- a/dist/reflux.js +++ b/dist/reflux.js @@ -227,7 +227,10 @@ module.exports = function() { functor; functor = function() { - action.emit(eventLabel, arguments); + functor.preEmit.apply(functor, arguments); + if (functor.shouldEmit.apply(functor, arguments)) { + action.emit(eventLabel, arguments); + } }; /** @@ -248,6 +251,22 @@ module.exports = function() { }; }; + /** + * Hook used by the action functor that is invoked before emitting + * and before `shouldEmit`. The arguments are the ones that the action + * is invoked with. + */ + functor.preEmit = function() {}; + + /** + * Hook used by the action functor after `preEmit` to determine if the + * event should be emitted with given arguments. This may be overridden + * in your application, default implementation always returns true. + * + * @returns {Boolean} true if event should be emitted + */ + functor.shouldEmit = function() { return true; }; + return functor; }; diff --git a/dist/reflux.min.js b/dist/reflux.min.js index ac9b9ec..e9de120 100644 --- a/dist/reflux.min.js +++ b/dist/reflux.min.js @@ -1 +1 @@ -!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;"undefined"!=typeof window?b=window:"undefined"!=typeof global?b=global:"undefined"!=typeof self&&(b=self),b.Reflux=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;gh;h++)g[h-1]=arguments[h];l.apply(l.__EE3_context||this,g)}else{for(h=1,g=new Array(k-1);k>h;h++)g[h-1]=arguments[h];for(h=0;j>h;l=i[++h])l.__EE3_once&&this.removeListener(a,l),l.apply(l.__EE3_context||this,g)}return!0},c.prototype.on=function(a,b,c){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),b.__EE3_context=c,this._events[a].push(b),this},c.prototype.once=function(a,b,c){return b.__EE3_once=!0,this.on(a,b,c)},c.prototype.removeListener=function(a,b){if(!this._events||!this._events[a])return this;for(var c=this._events[a],d=[],e=0,f=c.length;f>e;e++)b&&c[e]!==b&&d.push(c[e]);return this._events[a]=d.length?d:null,this},c.prototype.removeAllListeners=function(a){return this._events?(a?this._events[a]=null:this._events={},this):this},c.prototype.off=c.prototype.removeListener,c.prototype.addListener=c.prototype.on,c.prototype.setMaxListeners=function(){return this},c.EventEmitter=c,c.EventEmitter2=c,c.EventEmitter3=c;try{b.exports=c}catch(d){}},{}],2:[function(a,b){b.exports={componentWillMount:function(){this.subscriptions=[]},listenTo:function(a,b){var c=a.listen(b,this);this.subscriptions.push(c)},componentWillUnmount:function(){this.subscriptions.forEach(function(a){a()}),this.subscriptions=[]}}},{}],3:[function(a,b){var c=a("./utils");b.exports=function(){var a,b=new c.EventEmitter,d="action";return a=function(){b.emit(d,arguments)},a.listen=function(a,c){var e=function(b){a.apply(c,b)};return b.addListener(d,e),function(){b.removeListener(d,e)}},a}},{"./utils":6}],4:[function(a,b){var c=a("./utils");b.exports=function(a){function b(){this.init&&c.isFunction(this.init)&&this.init()}var d=new c.EventEmitter,e="change";return c.extend(b.prototype,a),b.prototype.listenTo=function(a,b){if(!c.isFunction(a.listen))throw new TypeError(a+" is missing a listen method");return a.listen(b,this)},b.prototype.listen=function(a,b){var c=function(c){a.apply(b,c)};return d.addListener(e,c),function(){d.removeListener(e,c)}},b.prototype.trigger=function(){d.emit(e,arguments)},new b}},{"./utils":6}],5:[function(a,b,c){c.createAction=a("./createAction"),c.createStore=a("./createStore"),c.ListenerMixin=a("./ListenerMixin"),c.createActions=function(a){for(var b=0,d={};be;e++){b=arguments[e];for(d in b)a[d]=b[d]}return a},b.exports.isFunction=function(a){return"function"==typeof a},b.exports.EventEmitter=a("eventemitter3")},{eventemitter3:1}]},{},[5])(5)}); \ No newline at end of file +!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;"undefined"!=typeof window?b=window:"undefined"!=typeof global?b=global:"undefined"!=typeof self&&(b=self),b.Reflux=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;gh;h++)g[h-1]=arguments[h];l.apply(l.__EE3_context||this,g)}else{for(h=1,g=new Array(k-1);k>h;h++)g[h-1]=arguments[h];for(h=0;j>h;l=i[++h])l.__EE3_once&&this.removeListener(a,l),l.apply(l.__EE3_context||this,g)}return!0},c.prototype.on=function(a,b,c){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),b.__EE3_context=c,this._events[a].push(b),this},c.prototype.once=function(a,b,c){return b.__EE3_once=!0,this.on(a,b,c)},c.prototype.removeListener=function(a,b){if(!this._events||!this._events[a])return this;for(var c=this._events[a],d=[],e=0,f=c.length;f>e;e++)b&&c[e]!==b&&d.push(c[e]);return this._events[a]=d.length?d:null,this},c.prototype.removeAllListeners=function(a){return this._events?(a?this._events[a]=null:this._events={},this):this},c.prototype.off=c.prototype.removeListener,c.prototype.addListener=c.prototype.on,c.prototype.setMaxListeners=function(){return this},c.EventEmitter=c,c.EventEmitter2=c,c.EventEmitter3=c;try{b.exports=c}catch(d){}},{}],2:[function(a,b){b.exports={componentWillMount:function(){this.subscriptions=[]},listenTo:function(a,b){var c=a.listen(b,this);this.subscriptions.push(c)},componentWillUnmount:function(){this.subscriptions.forEach(function(a){a()}),this.subscriptions=[]}}},{}],3:[function(a,b){var c=a("./utils");b.exports=function(){var a,b=new c.EventEmitter,d="action";return a=function(){a.preEmit.apply(a,arguments),a.shouldEmit.apply(a,arguments)&&b.emit(d,arguments)},a.listen=function(a,c){var e=function(b){a.apply(c,b)};return b.addListener(d,e),function(){b.removeListener(d,e)}},a.preEmit=function(){},a.shouldEmit=function(){return!0},a}},{"./utils":6}],4:[function(a,b){var c=a("./utils");b.exports=function(a){function b(){this.init&&c.isFunction(this.init)&&this.init()}var d=new c.EventEmitter,e="change";return c.extend(b.prototype,a),b.prototype.listenTo=function(a,b){if(!c.isFunction(a.listen))throw new TypeError(a+" is missing a listen method");return a.listen(b,this)},b.prototype.listen=function(a,b){var c=function(c){a.apply(b,c)};return d.addListener(e,c),function(){d.removeListener(e,c)}},b.prototype.trigger=function(){d.emit(e,arguments)},new b}},{"./utils":6}],5:[function(a,b,c){c.createAction=a("./createAction"),c.createStore=a("./createStore"),c.ListenerMixin=a("./ListenerMixin"),c.createActions=function(a){for(var b=0,d={};be;e++){b=arguments[e];for(d in b)a[d]=b[d]}return a},b.exports.isFunction=function(a){return"function"==typeof a},b.exports.EventEmitter=a("eventemitter3")},{eventemitter3:1}]},{},[5])(5)}); \ No newline at end of file diff --git a/src/createAction.js b/src/createAction.js index 1162017..5ce7021 100644 --- a/src/createAction.js +++ b/src/createAction.js @@ -10,7 +10,10 @@ module.exports = function() { functor; functor = function() { - action.emit(eventLabel, arguments); + functor.preEmit.apply(functor, arguments); + if (functor.shouldEmit.apply(functor, arguments)) { + action.emit(eventLabel, arguments); + } }; /** @@ -31,6 +34,22 @@ module.exports = function() { }; }; + /** + * Hook used by the action functor that is invoked before emitting + * and before `shouldEmit`. The arguments are the ones that the action + * is invoked with. + */ + functor.preEmit = function() {}; + + /** + * Hook used by the action functor after `preEmit` to determine if the + * event should be emitted with given arguments. This may be overridden + * in your application, default implementation always returns true. + * + * @returns {Boolean} true if event should be emitted + */ + functor.shouldEmit = function() { return true; }; + return functor; }; diff --git a/test/creatingActions.spec.js b/test/creatingActions.spec.js index 8c56d73..f27917e 100644 --- a/test/creatingActions.spec.js +++ b/test/creatingActions.spec.js @@ -7,10 +7,12 @@ chai.use(require('chai-as-promised')); describe('Creating action', function() { - var action; + var action, + testArgs; beforeEach(function () { action = Reflux.createAction(); + testArgs = [1337, 'test']; }); it('should be a callable functor', function() { @@ -31,12 +33,86 @@ describe('Creating action', function() { it('should receive the correct arguments', function() { - var testArgs = [1337, 'test']; action(testArgs[0], testArgs[1]); return assert.eventually.deepEqual(promise, testArgs); }); + describe('when adding preEmit hook', function() { + + var savedPreEmit, + receivedArgs; + + beforeEach(function() { + savedPreEmit = action.preEmit; + action.preEmit = function() { + receivedArgs = Array.prototype.slice.call(arguments, 0); + }; + }); + + afterEach(function () { + action.preEmit = savedPreEmit; + }); + + it('should receive arguments from action functor', function() { + action.apply(null, testArgs); + + assert.deepEqual(receivedArgs, testArgs); + }); + + }); + + describe('when replacing shouldEmit', function() { + + var savedShouldEmit, + emitReturnValue, + receivedArgs; + + beforeEach(function () { + emitReturnValue = true; + savedShouldEmit = action.shouldEmit; + action.shouldEmit = function() { + receivedArgs = Array.prototype.slice.call(arguments, 0); + return emitReturnValue; + }; + hasRun = false; + }); + + afterEach(function() { + action.shouldEmit = savedShouldEmit; + }); + + it('should receive arguments from action functor', function() { + action.apply(null, testArgs); + + assert.deepEqual(receivedArgs, testArgs); + }); + + describe('when shouldEmit returns false', function() { + + beforeEach(function() { + emitReturnValue = false; + }); + + + it('should not emit when shouldEmit returns false', function(done) { + var resolved = false; + promise.then(function() { + resolved = true; + }); + + action.apply(null, testArgs); + + setTimeout(function() { + assert.isFalse(resolved); + done(); + }, 20); + }); + + }); + + }); + }); }); diff --git a/test/creatingStores.spec.js b/test/creatingStores.spec.js index 216bcd5..bf97c3a 100644 --- a/test/creatingStores.spec.js +++ b/test/creatingStores.spec.js @@ -58,7 +58,7 @@ describe('Creating stores', function() { setTimeout(function() { assert.isFalse(resolved); done(); - }, 200); + }, 20); }); });