Adding changes from feedback:

- Cleared listners on emit
- Added an off method to Events
- Added destory to State
This commit is contained in:
Chris Cowan 2014-08-05 13:59:58 -07:00
parent 6897ceda63
commit b45933217d
9 changed files with 129 additions and 66 deletions

View file

@ -25,7 +25,7 @@ define(function (require) {
// Check to see if the state already exists. If it does then we need
// to call the destory method.
if (!_.isUndefined(currentAppState)) {
currentAppState.$destroy();
currentAppState.destroy();
}
currentAppState = new AppState(defaults);

View file

@ -5,8 +5,7 @@ define(function (require) {
var applyDiff = require('utils/diff_object');
return function StateProvider(Private, $rootScope, $location) {
var BaseObject = Private(require('components/state_management/_base_object'));
var Events = Private(require('components/state_management/_events'));
var Events = Private(require('factories/_events'));
_.inherits(State, Events);
function State(urlParam, defaults) {
@ -76,6 +75,14 @@ define(function (require) {
this.on('fetch_with_changes', cb);
};
/**
* Cleans up the state object
* @returns {void}
*/
State.prototype.destroy = function () {
this.off(); // removes all listners
};
return State;
};

View file

@ -2,7 +2,7 @@ define(function (require) {
var _ = require('lodash');
return function EventsProvider(Private, PromiseEmitter) {
var BaseObject = Private(require('components/state_management/_base_object'));
var BaseObject = Private(require('factories/_base_object'));
_.inherits(Events, BaseObject);
function Events() {
@ -24,10 +24,35 @@ define(function (require) {
}
return new PromiseEmitter(function (resolve, reject, defer) {
defer._handler = handler;
self._listeners[name].push(defer);
}, handler);
};
/**
* Removes a event listner
* @param {string} name The name of the event
* @param {function} [handler] The handler to remove
* @return {void}
*/
Events.prototype.off = function (name, handler) {
if (_.isEmpty(name) && _.isEmpty(handler)) {
this._listeners = {};
}
// exit early if there is not an event that matches
if (!this._listeners[name]) return;
// If no hander remove all the events
if (_.isEmpty(handler)) {
delete this._listeners[name];
} else {
this._listeners[name] = _.filter(this._listeners[name], function (defer) {
return handler !== defer._handler;
});
}
};
/**
* Emits and event using the PromiseEmitter
* @param {string} name The name of the event
@ -38,7 +63,9 @@ define(function (require) {
var args = Array.prototype.slice.call(arguments);
var name = args.shift();
if (this._listeners[name]) {
_.each(this._listeners[name], function (defer) {
// We need to empty the array when we resolve the listners. PromiseEmitter
// will regenerate the listners array with new promises.
_.each(this._listeners[name].slice(0), function (defer) {
defer.resolve.apply(defer, args);
});
}

View file

@ -74,10 +74,10 @@
'specs/utils/versionmath',
'specs/utils/routes/index',
'specs/courier/search_source/_get_normalized_sort',
'specs/state_management/_base_object',
'specs/factories/_base_object',
'specs/state_management/state',
'specs/utils/diff_object',
'specs/state_management/_events'
'specs/factories/_events'
], function (kibana, sinon) {
kibana.load(function () {
var xhr = sinon.useFakeXMLHttpRequest();

View file

@ -17,7 +17,7 @@ define(function (require) {
inject(function (_$rootScope_, Private) {
$rootScope = _$rootScope_;
BaseObject = Private(require('components/state_management/_base_object'));
BaseObject = Private(require('factories/_base_object'));
});
});

View file

@ -0,0 +1,86 @@
define(function (require) {
var angular = require('angular');
var _ = require('lodash');
var sinon = require('sinon/sinon');
require('services/private');
// Load kibana
require('index');
describe('State Management', function () {
describe('Events', function () {
var $rootScope;
var Events;
beforeEach(function () {
module('kibana');
inject(function (_$rootScope_, Private) {
$rootScope = _$rootScope_;
Events = Private(require('factories/_events'));
});
});
it('should handle on events', function (done) {
var obj = new Events();
obj.on('test', function (message) {
expect(message).to.equal('Hello World');
done();
});
obj.emit('test', 'Hello World');
$rootScope.$apply();
});
it('should work with inherited objects', function (done) {
_.inherits(MyEventedObject, Events);
function MyEventedObject() {
MyEventedObject.Super.call(this);
}
var obj = new MyEventedObject();
obj.on('test', function (message) {
expect(message).to.equal('Hello World');
done();
});
obj.emit('test', 'Hello World');
$rootScope.$apply();
});
it('should clear events when off is called', function () {
var obj = new Events();
obj.on('test', _.noop);
expect(obj._listeners).to.have.property('test');
expect(obj._listeners['test']).to.have.length(1);
obj.off();
expect(obj._listeners).to.not.have.property('test');
});
it('should clear a specific handler when off is called for an event', function () {
var obj = new Events();
var handler1 = sinon.stub();
var handler2 = sinon.stub();
obj.on('test', handler1);
obj.on('test', handler2);
expect(obj._listeners).to.have.property('test');
obj.off('test', handler1);
obj.emit('test', 'Hello World');
$rootScope.$apply();
sinon.assert.calledOnce(handler2);
sinon.assert.notCalled(handler1);
});
it('should clear a all handlers when off is called for an event', function () {
var obj = new Events();
var handler1 = sinon.stub();
obj.on('test', handler1);
expect(obj._listeners).to.have.property('test');
obj.off('test');
expect(obj._listeners).to.not.have.property('test');
obj.emit('test', 'Hello World');
$rootScope.$apply();
sinon.assert.notCalled(handler1);
});
});
});
});

View file

@ -1,51 +0,0 @@
define(function (require) {
var angular = require('angular');
var _ = require('lodash');
var sinon = require('sinon/sinon');
require('services/private');
// Load kibana
require('index');
describe('State Management', function () {
describe('Events', function () {
var $rootScope;
var Events;
beforeEach(function () {
module('kibana');
inject(function (_$rootScope_, Private) {
$rootScope = _$rootScope_;
Events = Private(require('components/state_management/_events'));
});
});
it('should handle on events', function (done) {
var obj = new Events();
obj.on('test', function (message) {
expect(message).to.equal('Hello World');
done();
});
obj.emit('test', 'Hello World');
$rootScope.$apply();
});
it('should work with inherited objects', function (done) {
_.inherits(MyEventedObject, Events);
function MyEventedObject() {
MyEventedObject.Super.call(this);
}
var obj = new MyEventedObject();
obj.on('test', function (message) {
expect(message).to.equal('Hello World');
done();
});
obj.emit('test', 'Hello World');
$rootScope.$apply();
});
});
});
});

View file

@ -19,7 +19,7 @@ define(function (require) {
$location = _$location_;
$rootScope = _$rootScope_;
State = Private(require('components/state_management/state'));
Events = Private(require('components/state_management/_events'));
Events = Private(require('factories/_events'));
});
});
@ -48,12 +48,6 @@ define(function (require) {
$rootScope.$apply();
});
it('should fetch the state from $location.search()', function () {
var state = new State();
$location.search({ _s: '(foo:bar)' });
state.fetch();
expect(state).to.have.property('foo', 'bar');
});
it('should emit an event if changes are fetched', function (done) {
var state = new State();