UNPKG

4.06 kBJavaScriptView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @format
8 * @flow
9 */
10
11'use strict';
12
13const EventEmitter = require('EventEmitter');
14const EventEmitterWithHolding = require('EventEmitterWithHolding');
15const EventHolder = require('EventHolder');
16
17const invariant = require('invariant');
18/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
19 * found when Flow v0.54 was deployed. To see the error delete this comment and
20 * run Flow. */
21const keyOf = require('fbjs/lib/keyOf');
22
23import type EmitterSubscription from 'EmitterSubscription';
24
25const TYPES_KEY = keyOf({__types: true});
26
27/**
28 * API to setup an object or constructor to be able to emit data events.
29 *
30 * @example
31 * function Dog() { ...dog stuff... }
32 * mixInEventEmitter(Dog, {bark: true});
33 *
34 * var puppy = new Dog();
35 * puppy.addListener('bark', function (volume) {
36 * console.log('Puppy', this, 'barked at volume:', volume);
37 * });
38 * puppy.emit('bark', 'quiet');
39 * // Puppy <puppy> barked at volume: quiet
40 *
41 *
42 * // A "singleton" object may also be commissioned:
43 *
44 * var Singleton = {};
45 * mixInEventEmitter(Singleton, {lonely: true});
46 * Singleton.emit('lonely', true);
47 */
48function mixInEventEmitter(cls: Function | Object, types: Object) {
49 invariant(types, 'Must supply set of valid event types');
50
51 // If this is a constructor, write to the prototype, otherwise write to the
52 // singleton object.
53 const target = cls.prototype || cls;
54
55 invariant(!target.__eventEmitter, 'An active emitter is already mixed in');
56
57 const ctor = cls.constructor;
58 if (ctor) {
59 invariant(
60 ctor === Object || ctor === Function,
61 'Mix EventEmitter into a class, not an instance',
62 );
63 }
64
65 // Keep track of the provided types, union the types if they already exist,
66 // which allows for prototype subclasses to provide more types.
67 if (target.hasOwnProperty(TYPES_KEY)) {
68 Object.assign(target.__types, types);
69 } else if (target.__types) {
70 target.__types = Object.assign({}, target.__types, types);
71 } else {
72 target.__types = types;
73 }
74 Object.assign(target, EventEmitterMixin);
75}
76
77const EventEmitterMixin = {
78 emit: function(eventType, a, b, c, d, e, _) {
79 return this.__getEventEmitter().emit(eventType, a, b, c, d, e, _);
80 },
81
82 emitAndHold: function(eventType, a, b, c, d, e, _) {
83 return this.__getEventEmitter().emitAndHold(eventType, a, b, c, d, e, _);
84 },
85
86 addListener: function(eventType, listener, context): EmitterSubscription {
87 return this.__getEventEmitter().addListener(eventType, listener, context);
88 },
89
90 once: function(eventType, listener, context) {
91 return this.__getEventEmitter().once(eventType, listener, context);
92 },
93
94 addRetroactiveListener: function(eventType, listener, context) {
95 return this.__getEventEmitter().addRetroactiveListener(
96 eventType,
97 listener,
98 context,
99 );
100 },
101
102 addListenerMap: function(listenerMap, context) {
103 return this.__getEventEmitter().addListenerMap(listenerMap, context);
104 },
105
106 addRetroactiveListenerMap: function(listenerMap, context) {
107 return this.__getEventEmitter().addListenerMap(listenerMap, context);
108 },
109
110 removeAllListeners: function() {
111 this.__getEventEmitter().removeAllListeners();
112 },
113
114 removeCurrentListener: function() {
115 this.__getEventEmitter().removeCurrentListener();
116 },
117
118 releaseHeldEventType: function(eventType) {
119 this.__getEventEmitter().releaseHeldEventType(eventType);
120 },
121
122 __getEventEmitter: function() {
123 if (!this.__eventEmitter) {
124 let emitter = new EventEmitter();
125 if (__DEV__) {
126 const EventValidator = require('EventValidator');
127 emitter = EventValidator.addValidation(emitter, this.__types);
128 }
129
130 const holder = new EventHolder();
131 this.__eventEmitter = new EventEmitterWithHolding(emitter, holder);
132 }
133 return this.__eventEmitter;
134 },
135};
136
137module.exports = mixInEventEmitter;