events.js
4.12 KB
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
119
120
121
122
123
124
125
126
127
// Events
// ---------------
import Promise from './promise';
import events from 'events'
import { each, flatMap, once as _once } from 'lodash';
const { EventEmitter } = events;
const eventNames = text => text.split(/\s+/);
/**
* @class Events
* @description
* Base Event class inherited by {@link Model} and {@link Collection}. It's not
* meant to be used directly, and is only displayed here for completeness.
*/
export default class Events extends EventEmitter {
/**
* @method Events#on
* @description
* Register an event listener. The callback will be invoked whenever the event
* is fired. The event string may also be a space-delimited list of several
* event names.
*
* @param {string} nameOrNames
* The name of the event or space separated list of events to register a
* callback for.
* @param {function} callback
* That callback to invoke whenever the event is fired.
*/
on(nameOrNames, handler) {
each(eventNames(nameOrNames), (name) => {
super.on(name, handler)
});
return this;
}
/**
* @method Events#off
* @description
* Remove a previously-bound callback event listener from an object. If no
* event name is specified, callbacks for all events will be removed.
*
* @param {string} nameOrNames
* The name of the event or space separated list of events to stop listening
* to.
*/
off(nameOrNames) {
if (nameOrNames == null) {
return this.removeAllListeners();
}
each(eventNames(nameOrNames), name => this.removeAllListeners(name));
return this;
}
/**
* @method Events#trigger
* @description
* Trigger callbacks for the given event, or space-delimited list of events.
* Subsequent arguments to `trigger` will be passed along to the event
* callback.
*
* @param {string} nameOrNames
* The name of the event to trigger. Also accepts a space separated list of
* event names.
* @param {...mixed} [args]
* Extra arguments to pass to the event listener callback function.
*/
trigger(nameOrNames, ...args) {
each(eventNames(nameOrNames), (name) => {
this.emit(name, ...args)
});
return this;
}
/**
* @method Events#triggerThen
* @description
* A promise version of {@link Events#trigger}, returning a promise which
* resolves with all return values from triggered event handlers. If any of the
* event handlers throw an `Error` or return a rejected promise, the promise
* will be rejected. Used internally on the {@link Model#creating "creating"},
* {@link Model#updating "updating"}, {@link Model#saving "saving"}, and {@link
* Model@destroying "destroying"} events, and can be helpful when needing async
* event handlers (for validations, etc).
*
* @param {string} name
* The event name, or a whitespace-separated list of event names, to be
* triggered.
* @param {...mixed} [args]
* Arguments to be passed to any registered event handlers.
* @returns Promise<mixed[]>
* A promise resolving the the resolved return values of any triggered handlers.
*/
triggerThen(nameOrNames, ...args) {
const names = eventNames(nameOrNames);
const listeners = flatMap(names, name => this.listeners(name));
return Promise.map(listeners, listener => listener.apply(this, args));
}
/**
* @method Events#once
* @description
* Just like {@link Events#on}, but causes the bound callback to fire only
* once before being removed. Handy for saying "the next time that X happens,
* do this". When multiple events are passed in using the space separated
* syntax, the event will fire once for every event you passed in, not once
* for a combination of all events.
*
* @param {string} nameOrNames
* The name of the event or space separated list of events to register a
* callback for.
* @param {function} callback
* That callback to invoke only once when the event is fired.
*/
once(name, callback) {
const wrapped = _once((...args) => {
this.off(name, wrapped);
return callback.apply(this, args);
});
wrapped._callback = callback;
return this.on(name, wrapped);
}
}