-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathlisteners.js
118 lines (93 loc) · 2.37 KB
/
listeners.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/**
* A storage for per-target callbacks.
* WeakMap is the most safe solution.
*
* @module emmy/listeners
*/
// target: {evt: callbacks}
var LISTENERS = new WeakMap()
/**
* Get listeners for the target/evt (optionally).
*
* @param {object} target a target object
* @param {string}? evt an evt name, if undefined - return object with events
*
* @return {(object|array)} List/set of listeners
*/
function get(target, evt, tags) {
var cbs = LISTENERS.get(target);
var result;
if (!evt) {
result = cbs || {};
// filter cbs by tags
if (tags && tags.length) {
var filteredResult = {};
for (var evt in result) {
filteredResult[evt] = result[evt].filter(function (cb) {
return hasTags(cb, tags);
});
}
result = filteredResult;
}
return result;
}
if (!cbs || !cbs[evt]) {
return [];
}
result = cbs[evt];
// if there are evt namespaces specified - filter callbacks
if (tags && tags.length) {
result = result.filter(function (cb) {
return hasTags(cb, tags);
});
}
return result;
}
/**
* Remove listener, if any
*/
function remove(target, evt, cb, tags) {
// get callbacks for the evt
var evtCallbacks = LISTENERS.get(target);
if (!evtCallbacks || !evtCallbacks[evt]) return false;
var callbacks = evtCallbacks[evt];
// if tags are passed - make sure callback has some tags before removing
if (tags && tags.length && !hasTags(cb, tags)) return false;
// remove specific handler
for (var i = 0; i < callbacks.length; i++) {
// once method has original callback in .cb
if (callbacks[i] === cb) {
callbacks.splice(i, 1);
break;
}
}
};
/**
* Add a new listener
*/
function add(target, evt, cb, tags) {
if (!cb) return;
var targetCallbacks = LISTENERS.get(target);
// ensure set of callbacks for the target exists
if (!targetCallbacks) {
targetCallbacks = {}
LISTENERS.set(target, targetCallbacks)
}
// save a new callback
(targetCallbacks[evt] = targetCallbacks[evt] || []).push(cb);
// save ns for a callback, if any
if (tags && tags.length) {
cb._ns = tags;
}
};
/** Detect whether an cb has at least one tag from the list */
function hasTags(cb, tags) {
if (!cb._ns) return false
// if cb is tagged with a ns and includes one of the ns passed - keep it
for (var i = tags.length; i--;) {
if (cb._ns.indexOf(tags[i]) >= 0) return true;
}
}
module.exports = {
get: get, remove: remove, add: add
};