ui: Enable creating listeners using an object/hash (#5975)

Makes listening to multiple events on one target slightly easier.
Adding events can be rolled up into passing through an object, and the
returned remove function removes all of the handlers in the object

For example:

```
//this.listen...
const remove = listeners.add(
  {
    'message': handler,
    'error': handler
  }
);
remove(); // removes all listeners in the object
```

The entire API for listeners is now becoming slightly overloaded, so
potentially we'd use this API always and remove the ability to use a
string/function pair.
This commit is contained in:
John Cowen 2019-06-20 09:39:08 +01:00 committed by John Cowen
parent e66a1b3874
commit 011fb8a559
2 changed files with 50 additions and 10 deletions

View file

@ -15,11 +15,25 @@ class Listeners {
addEventListener = 'on';
removeEventListener = 'off';
}
let obj = event;
if (typeof obj === 'string') {
obj = {
[event]: handler,
};
}
const removers = Object.keys(obj).map(function(key) {
return (function(event, handler) {
target[addEventListener](event, handler);
remove = function() {
return function() {
target[removeEventListener](event, handler);
return handler;
};
})(key, obj[key]);
});
// TODO: if event was a string only return the first
// although the problem remains that it could sometimes return
// a function, sometimes an array, so this needs some more thought
remove = () => removers.map(item => item());
}
this.listeners.push(remove);
return () => {

View file

@ -11,9 +11,12 @@ test('it has add and remove methods', function(assert) {
});
test('add returns a remove function', function(assert) {
const listeners = createListeners();
const remove = listeners.add({
const remove = listeners.add(
{
addEventListener: function() {},
});
},
'click'
);
assert.ok(typeof remove === 'function');
});
test('remove returns an array of removed handlers (the return of a saved remove)', function(assert) {
@ -50,6 +53,29 @@ test('listeners are added on add', function(assert) {
assert.ok(stub.calledOnce);
assert.ok(stub.calledWith(name, handler));
});
test('listeners as objects are added on add and removed on remove', function(assert) {
const listeners = createListeners();
const addStub = this.stub();
const removeStub = this.stub();
const target = {
addEventListener: addStub,
removeEventListener: removeStub,
};
const handler = function(e) {};
const remove = listeners.add(target, {
message: handler,
error: handler,
});
assert.ok(addStub.calledTwice);
assert.ok(addStub.calledWith('message', handler));
assert.ok(addStub.calledWith('error', handler));
remove();
assert.ok(removeStub.calledTwice);
assert.ok(removeStub.calledWith('message', handler));
assert.ok(removeStub.calledWith('error', handler));
});
test('listeners are removed on remove', function(assert) {
const listeners = createListeners();
const stub = this.stub();
@ -88,7 +114,7 @@ test('listeners as functions of other listeners are removed on remove', function
remove();
assert.ok(stub.calledOnce);
});
test('remove returns the original handler', function(assert) {
test('remove returns an array containing the original handler', function(assert) {
const listeners = createListeners();
const target = {
addEventListener: function() {},
@ -98,6 +124,6 @@ test('remove returns the original handler', function(assert) {
const expected = this.stub();
const remove = listeners.add(target, name, expected);
const actual = remove();
actual();
actual[0]();
assert.ok(expected.calledOnce);
});