Skip to content

Commit

Permalink
ui: Expands create-listeners API to allow recursive and functions (#5616
Browse files Browse the repository at this point in the history
)

1. Adds a Listeners class, which lets us...
2. Add Listeners recursively. So you can
createListeners().add(createListeners())
3. Also add the ability to `.add` as a plain function

This moves the entire idea more towards a generic teardown utility
  • Loading branch information
johncowen authored and John Cowen committed Sep 4, 2019
1 parent 4ed5515 commit eccff12
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 29 deletions.
64 changes: 36 additions & 28 deletions ui-v2/app/utils/dom/create-listeners.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,40 @@
export default function(listeners = []) {
const add = function(target, event, handler) {
let addEventListener = 'addEventListener';
let removeEventListener = 'removeEventListener';
if (typeof target[addEventListener] === 'undefined') {
addEventListener = 'on';
removeEventListener = 'off';
class Listeners {
constructor(listeners = []) {
this.listeners = listeners;
}
add(target, event, handler) {
let remove;
if (typeof target === 'function') {
remove = target;
} else if (target instanceof Listeners) {
remove = target.remove.bind(target);
} else {
let addEventListener = 'addEventListener';
let removeEventListener = 'removeEventListener';
if (typeof target[addEventListener] === 'undefined') {
addEventListener = 'on';
removeEventListener = 'off';
}
target[addEventListener](event, handler);
remove = function() {
target[removeEventListener](event, handler);
return handler;
};
}
target[addEventListener](event, handler);
const remove = function() {
target[removeEventListener](event, handler);
return handler;
this.listeners.push(remove);
return () => {
const pos = this.listeners.findIndex(function(item) {
return item === remove;
});
return this.listeners.splice(pos, 1)[0]();
};
listeners.push(remove);
return remove;
};
// TODO: Allow passing of a 'listener remove' in here
// call it, find in the array and remove
// Post-thoughts, pretty sure this is covered now by returning the remove
// function above, use-case for wanting to use this method to remove individual
// listeners is probably pretty limited, this method itself could be easily implemented
// from the outside also, but I suppose its handy to keep here
const remove = function() {
const handlers = listeners.map(item => item());
listeners.splice(0, listeners.length);
}
remove() {
const handlers = this.listeners.map(item => item());
this.listeners.splice(0, this.listeners.length);
return handlers;
};
return {
add: add,
remove: remove,
};
}
}
export default function(listeners = []) {
return new Listeners(listeners);
}
26 changes: 25 additions & 1 deletion ui-v2/tests/unit/utils/dom/create-listeners-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ test('it has add and remove methods', function(assert) {
assert.ok(typeof listeners.add === 'function');
assert.ok(typeof listeners.remove === 'function');
});
test('add returns an remove function', function(assert) {
test('add returns a remove function', function(assert) {
const listeners = createListeners();
const remove = listeners.add({
addEventListener: function() {},
Expand Down Expand Up @@ -64,6 +64,30 @@ test('listeners are removed on remove', function(assert) {
assert.ok(stub.calledOnce);
assert.ok(stub.calledWith(name, handler));
});
test('listeners as functions are removed on remove', function(assert) {
const listeners = createListeners();
const stub = this.stub();
const remove = listeners.add(stub);
remove();
assert.ok(stub.calledOnce);
});
test('listeners as other listeners are removed on remove', function(assert) {
const listeners = createListeners();
const listeners2 = createListeners();
const stub = this.stub();
listeners2.add(stub);
const remove = listeners.add(listeners2);
remove();
assert.ok(stub.calledOnce);
});
test('listeners as functions of other listeners are removed on remove', function(assert) {
const listeners = createListeners();
const listeners2 = createListeners();
const stub = this.stub();
const remove = listeners.add(listeners2.add(stub));
remove();
assert.ok(stub.calledOnce);
});
test('remove returns the original handler', function(assert) {
const listeners = createListeners();
const target = {
Expand Down

0 comments on commit eccff12

Please sign in to comment.