RN: Delete `mixInEventEmitter`
Summary: Deletes `mixInEventEmitter` and its dependencies that are no longer being used by anything in `react-native`. Changelog: [Internal] Reviewed By: TheSavior Differential Revision: D17879835 fbshipit-source-id: 45f30d21cb01365fcfc723cf564ebb47794ea176
This commit is contained in:
Родитель
2becdfd404
Коммит
fc9feb16e0
|
@ -1,170 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type EmitterSubscription from './EmitterSubscription';
|
||||
import type EventEmitter from './EventEmitter';
|
||||
import type EventHolder from './EventHolder';
|
||||
|
||||
/**
|
||||
* @class EventEmitterWithHolding
|
||||
* @description
|
||||
* An EventEmitterWithHolding decorates an event emitter and enables one to
|
||||
* "hold" or cache events and then have a handler register later to actually
|
||||
* handle them.
|
||||
*
|
||||
* This is separated into its own decorator so that only those who want to use
|
||||
* the holding functionality have to and others can just use an emitter. Since
|
||||
* it implements the emitter interface it can also be combined with anything
|
||||
* that uses an emitter.
|
||||
*/
|
||||
class EventEmitterWithHolding {
|
||||
_emitter: EventEmitter;
|
||||
_eventHolder: EventHolder;
|
||||
_currentEventToken: ?Object;
|
||||
_emittingHeldEvents: boolean;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {object} emitter - The object responsible for emitting the actual
|
||||
* events.
|
||||
* @param {object} holder - The event holder that is responsible for holding
|
||||
* and then emitting held events.
|
||||
*/
|
||||
constructor(emitter: EventEmitter, holder: EventHolder) {
|
||||
this._emitter = emitter;
|
||||
this._eventHolder = holder;
|
||||
this._currentEventToken = null;
|
||||
this._emittingHeldEvents = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventEmitter#addListener
|
||||
*/
|
||||
addListener(eventType: string, listener: Function, context: ?Object): any {
|
||||
return this._emitter.addListener(eventType, listener, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventEmitter#once
|
||||
*/
|
||||
once(eventType: string, listener: Function, context: ?Object): any {
|
||||
return this._emitter.once(eventType, listener, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to be invoked when events of the specified type are
|
||||
* emitted. An optional calling context may be provided. The data arguments
|
||||
* emitted will be passed to the listener function. In addition to subscribing
|
||||
* to all subsequent events, this method will also handle any events that have
|
||||
* already been emitted, held, and not released.
|
||||
*
|
||||
* @param {string} eventType - Name of the event to listen to
|
||||
* @param {function} listener - Function to invoke when the specified event is
|
||||
* emitted
|
||||
* @param {*} context - Optional context object to use when invoking the
|
||||
* listener
|
||||
*
|
||||
* @example
|
||||
* emitter.emitAndHold('someEvent', 'abc');
|
||||
*
|
||||
* emitter.addRetroactiveListener('someEvent', function(message) {
|
||||
* console.log(message);
|
||||
* }); // logs 'abc'
|
||||
*/
|
||||
addRetroactiveListener(
|
||||
eventType: string,
|
||||
listener: Function,
|
||||
context: ?Object,
|
||||
): EmitterSubscription {
|
||||
const subscription = this._emitter.addListener(
|
||||
eventType,
|
||||
listener,
|
||||
context,
|
||||
);
|
||||
|
||||
this._emittingHeldEvents = true;
|
||||
this._eventHolder.emitToListener(eventType, listener, context);
|
||||
this._emittingHeldEvents = false;
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventEmitter#removeAllListeners
|
||||
*/
|
||||
removeAllListeners(eventType: string) {
|
||||
this._emitter.removeAllListeners(eventType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventEmitter#removeCurrentListener
|
||||
*/
|
||||
removeCurrentListener() {
|
||||
this._emitter.removeCurrentListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventEmitter#listeners
|
||||
*/
|
||||
listeners(eventType: string): any /* TODO: Annotate return type here */ {
|
||||
return this._emitter.listeners(eventType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventEmitter#emit
|
||||
*/
|
||||
emit(eventType: string, ...args: any) {
|
||||
this._emitter.emit(eventType, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits an event of the given type with the given data, and holds that event
|
||||
* in order to be able to dispatch it to a later subscriber when they say they
|
||||
* want to handle held events.
|
||||
*
|
||||
* @param {string} eventType - Name of the event to emit
|
||||
* @param {...*} Arbitrary arguments to be passed to each registered listener
|
||||
*
|
||||
* @example
|
||||
* emitter.emitAndHold('someEvent', 'abc');
|
||||
*
|
||||
* emitter.addRetroactiveListener('someEvent', function(message) {
|
||||
* console.log(message);
|
||||
* }); // logs 'abc'
|
||||
*/
|
||||
emitAndHold(eventType: string, ...args: any) {
|
||||
this._currentEventToken = this._eventHolder.holdEvent(eventType, ...args);
|
||||
this._emitter.emit(eventType, ...args);
|
||||
this._currentEventToken = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventHolder#releaseCurrentEvent
|
||||
*/
|
||||
releaseCurrentEvent() {
|
||||
if (this._currentEventToken) {
|
||||
this._eventHolder.releaseEvent(this._currentEventToken);
|
||||
} else if (this._emittingHeldEvents) {
|
||||
this._eventHolder.releaseCurrentEvent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventHolder#releaseEventType
|
||||
* @param {string} eventType
|
||||
*/
|
||||
releaseHeldEventType(eventType: string) {
|
||||
this._eventHolder.releaseEventType(eventType);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EventEmitterWithHolding;
|
|
@ -1,122 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
class EventHolder {
|
||||
_heldEvents: Object;
|
||||
_currentEventKey: ?Object;
|
||||
|
||||
constructor() {
|
||||
this._heldEvents = {};
|
||||
this._currentEventKey = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds a given event for processing later.
|
||||
*
|
||||
* TODO: Annotate return type better. The structural type of the return here
|
||||
* is pretty obvious.
|
||||
*
|
||||
* @param {string} eventType - Name of the event to hold and later emit
|
||||
* @param {...*} Arbitrary arguments to be passed to each registered listener
|
||||
* @return {object} Token that can be used to release the held event
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* holder.holdEvent({someEvent: 'abc'});
|
||||
*
|
||||
* holder.emitToHandler({
|
||||
* someEvent: function(data, event) {
|
||||
* console.log(data);
|
||||
* }
|
||||
* }); //logs 'abc'
|
||||
*
|
||||
*/
|
||||
holdEvent(
|
||||
eventType: string,
|
||||
...args: any
|
||||
): {|eventType: string, index: $FlowFixMeEmpty|} {
|
||||
this._heldEvents[eventType] = this._heldEvents[eventType] || [];
|
||||
const eventsOfType = this._heldEvents[eventType];
|
||||
const key = {
|
||||
eventType: eventType,
|
||||
index: eventsOfType.length,
|
||||
};
|
||||
eventsOfType.push(args);
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits the held events of the specified type to the given listener.
|
||||
*
|
||||
* @param {?string} eventType - Optional name of the events to replay
|
||||
* @param {function} listener - The listener to which to dispatch the event
|
||||
* @param {?object} context - Optional context object to use when invoking
|
||||
* the listener
|
||||
*/
|
||||
emitToListener(eventType: ?string, listener: Function, context: ?Object) {
|
||||
const eventsOfType = this._heldEvents[eventType];
|
||||
if (!eventsOfType) {
|
||||
return;
|
||||
}
|
||||
const origEventKey = this._currentEventKey;
|
||||
eventsOfType.forEach((/*?array*/ eventHeld, /*number*/ index) => {
|
||||
if (!eventHeld) {
|
||||
return;
|
||||
}
|
||||
this._currentEventKey = {
|
||||
eventType: eventType,
|
||||
index: index,
|
||||
};
|
||||
listener.apply(context, eventHeld);
|
||||
});
|
||||
this._currentEventKey = origEventKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an API that can be called during an eventing cycle to release
|
||||
* the last event that was invoked, so that it is no longer "held".
|
||||
*
|
||||
* If it is called when not inside of an emitting cycle it will throw.
|
||||
*
|
||||
* @throws {Error} When called not during an eventing cycle
|
||||
*/
|
||||
releaseCurrentEvent() {
|
||||
invariant(
|
||||
this._currentEventKey !== null,
|
||||
'Not in an emitting cycle; there is no current event',
|
||||
);
|
||||
this._currentEventKey && this.releaseEvent(this._currentEventKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the event corresponding to the handle that was returned when the
|
||||
* event was first held.
|
||||
*
|
||||
* @param {object} token - The token returned from holdEvent
|
||||
*/
|
||||
releaseEvent(token: Object) {
|
||||
delete this._heldEvents[token.eventType][token.index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all events of a certain type.
|
||||
*
|
||||
* @param {string} type
|
||||
*/
|
||||
releaseEventType(type: string) {
|
||||
this._heldEvents[type] = [];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EventHolder;
|
|
@ -1,139 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* EventValidator is designed to validate event types to make it easier to catch
|
||||
* common mistakes. It accepts a map of all of the different types of events
|
||||
* that the emitter can emit. Then, if a user attempts to emit an event that is
|
||||
* not one of those specified types the emitter will throw an error. Also, it
|
||||
* provides a relatively simple matcher so that if it thinks that you likely
|
||||
* mistyped the event name it will suggest what you might have meant to type in
|
||||
* the error message.
|
||||
*/
|
||||
const EventValidator = {
|
||||
/**
|
||||
* @param {Object} emitter - The object responsible for emitting the actual
|
||||
* events
|
||||
* @param {Object} types - The collection of valid types that will be used to
|
||||
* check for errors
|
||||
* @return {Object} A new emitter with event type validation
|
||||
* @example
|
||||
* const types = {someEvent: true, anotherEvent: true};
|
||||
* const emitter = EventValidator.addValidation(emitter, types);
|
||||
*/
|
||||
addValidation: function(emitter: Object, types: Object): {emit: any => any} {
|
||||
const eventTypes = Object.keys(types);
|
||||
const emitterWithValidation = Object.create(emitter);
|
||||
|
||||
Object.assign(emitterWithValidation, {
|
||||
emit: function emit(type, a, b, c, d, e, _) {
|
||||
assertAllowsEventType(type, eventTypes);
|
||||
return emitter.emit.call(this, type, a, b, c, d, e, _);
|
||||
},
|
||||
});
|
||||
|
||||
return emitterWithValidation;
|
||||
},
|
||||
};
|
||||
|
||||
function assertAllowsEventType(type, allowedTypes) {
|
||||
if (allowedTypes.indexOf(type) === -1) {
|
||||
throw new TypeError(errorMessageFor(type, allowedTypes));
|
||||
}
|
||||
}
|
||||
|
||||
function errorMessageFor(type, allowedTypes) {
|
||||
let message = 'Unknown event type "' + type + '". ';
|
||||
if (__DEV__) {
|
||||
message += recommendationFor(type, allowedTypes);
|
||||
}
|
||||
message += 'Known event types: ' + allowedTypes.join(', ') + '.';
|
||||
return message;
|
||||
}
|
||||
|
||||
// Allow for good error messages
|
||||
if (__DEV__) {
|
||||
var recommendationFor = function(type, allowedTypes) {
|
||||
const closestTypeRecommendation = closestTypeFor(type, allowedTypes);
|
||||
if (isCloseEnough(closestTypeRecommendation, type)) {
|
||||
return 'Did you mean "' + closestTypeRecommendation.type + '"? ';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
const closestTypeFor = function(type, allowedTypes) {
|
||||
const typeRecommendations = allowedTypes.map(
|
||||
typeRecommendationFor.bind(this, type),
|
||||
);
|
||||
return typeRecommendations.sort(recommendationSort)[0];
|
||||
};
|
||||
|
||||
const typeRecommendationFor = function(type, recommendedType) {
|
||||
return {
|
||||
type: recommendedType,
|
||||
distance: damerauLevenshteinDistance(type, recommendedType),
|
||||
};
|
||||
};
|
||||
|
||||
const recommendationSort = function(recommendationA, recommendationB) {
|
||||
if (recommendationA.distance < recommendationB.distance) {
|
||||
return -1;
|
||||
} else if (recommendationA.distance > recommendationB.distance) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
const isCloseEnough = function(closestType, actualType) {
|
||||
return closestType.distance / actualType.length < 0.334;
|
||||
};
|
||||
|
||||
const damerauLevenshteinDistance = function(a, b) {
|
||||
let i, j;
|
||||
const d = [];
|
||||
|
||||
for (i = 0; i <= a.length; i++) {
|
||||
d[i] = [i];
|
||||
}
|
||||
|
||||
for (j = 1; j <= b.length; j++) {
|
||||
d[0][j] = j;
|
||||
}
|
||||
|
||||
for (i = 1; i <= a.length; i++) {
|
||||
for (j = 1; j <= b.length; j++) {
|
||||
const cost = a.charAt(i - 1) === b.charAt(j - 1) ? 0 : 1;
|
||||
|
||||
d[i][j] = Math.min(
|
||||
d[i - 1][j] + 1,
|
||||
d[i][j - 1] + 1,
|
||||
d[i - 1][j - 1] + cost,
|
||||
);
|
||||
|
||||
if (
|
||||
i > 1 &&
|
||||
j > 1 &&
|
||||
a.charAt(i - 1) === b.charAt(j - 2) &&
|
||||
a.charAt(i - 2) === b.charAt(j - 1)
|
||||
) {
|
||||
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return d[a.length][b.length];
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = EventValidator;
|
|
@ -1,134 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('./EventEmitter');
|
||||
const EventEmitterWithHolding = require('./EventEmitterWithHolding');
|
||||
const EventHolder = require('./EventHolder');
|
||||
|
||||
const invariant = require('invariant');
|
||||
const keyOf = require('fbjs/lib/keyOf');
|
||||
|
||||
import type EmitterSubscription from './EmitterSubscription';
|
||||
|
||||
const TYPES_KEY = keyOf({__types: true});
|
||||
|
||||
/**
|
||||
* API to setup an object or constructor to be able to emit data events.
|
||||
*
|
||||
* @example
|
||||
* function Dog() { ...dog stuff... }
|
||||
* mixInEventEmitter(Dog, {bark: true});
|
||||
*
|
||||
* var puppy = new Dog();
|
||||
* puppy.addListener('bark', function (volume) {
|
||||
* console.log('Puppy', this, 'barked at volume:', volume);
|
||||
* });
|
||||
* puppy.emit('bark', 'quiet');
|
||||
* // Puppy <puppy> barked at volume: quiet
|
||||
*
|
||||
*
|
||||
* // A "singleton" object may also be commissioned:
|
||||
*
|
||||
* var Singleton = {};
|
||||
* mixInEventEmitter(Singleton, {lonely: true});
|
||||
* Singleton.emit('lonely', true);
|
||||
*/
|
||||
function mixInEventEmitter(cls: Function | Object, types: Object) {
|
||||
invariant(types, 'Must supply set of valid event types');
|
||||
|
||||
// If this is a constructor, write to the prototype, otherwise write to the
|
||||
// singleton object.
|
||||
const target = cls.prototype || cls;
|
||||
|
||||
invariant(!target.__eventEmitter, 'An active emitter is already mixed in');
|
||||
|
||||
const ctor = cls.constructor;
|
||||
if (ctor) {
|
||||
invariant(
|
||||
ctor === Object || ctor === Function,
|
||||
'Mix EventEmitter into a class, not an instance',
|
||||
);
|
||||
}
|
||||
|
||||
// Keep track of the provided types, union the types if they already exist,
|
||||
// which allows for prototype subclasses to provide more types.
|
||||
if (target.hasOwnProperty(TYPES_KEY)) {
|
||||
Object.assign(target.__types, types);
|
||||
} else if (target.__types) {
|
||||
target.__types = Object.assign({}, target.__types, types);
|
||||
} else {
|
||||
target.__types = types;
|
||||
}
|
||||
Object.assign(target, EventEmitterMixin);
|
||||
}
|
||||
|
||||
const EventEmitterMixin = {
|
||||
emit: function(eventType, a, b, c, d, e, _) {
|
||||
return this.__getEventEmitter().emit(eventType, a, b, c, d, e, _);
|
||||
},
|
||||
|
||||
emitAndHold: function(eventType, a, b, c, d, e, _) {
|
||||
return this.__getEventEmitter().emitAndHold(eventType, a, b, c, d, e, _);
|
||||
},
|
||||
|
||||
addListener: function(eventType, listener, context): EmitterSubscription {
|
||||
return this.__getEventEmitter().addListener(eventType, listener, context);
|
||||
},
|
||||
|
||||
once: function(eventType, listener, context) {
|
||||
return this.__getEventEmitter().once(eventType, listener, context);
|
||||
},
|
||||
|
||||
addRetroactiveListener: function(eventType, listener, context) {
|
||||
return this.__getEventEmitter().addRetroactiveListener(
|
||||
eventType,
|
||||
listener,
|
||||
context,
|
||||
);
|
||||
},
|
||||
|
||||
addListenerMap: function(listenerMap, context) {
|
||||
return this.__getEventEmitter().addListenerMap(listenerMap, context);
|
||||
},
|
||||
|
||||
addRetroactiveListenerMap: function(listenerMap, context) {
|
||||
return this.__getEventEmitter().addListenerMap(listenerMap, context);
|
||||
},
|
||||
|
||||
removeAllListeners: function() {
|
||||
this.__getEventEmitter().removeAllListeners();
|
||||
},
|
||||
|
||||
removeCurrentListener: function() {
|
||||
this.__getEventEmitter().removeCurrentListener();
|
||||
},
|
||||
|
||||
releaseHeldEventType: function(eventType) {
|
||||
this.__getEventEmitter().releaseHeldEventType(eventType);
|
||||
},
|
||||
|
||||
__getEventEmitter: function() {
|
||||
if (!this.__eventEmitter) {
|
||||
let emitter = new EventEmitter();
|
||||
if (__DEV__) {
|
||||
const EventValidator = require('./EventValidator');
|
||||
emitter = EventValidator.addValidation(emitter, this.__types);
|
||||
}
|
||||
|
||||
const holder = new EventHolder();
|
||||
this.__eventEmitter = new EventEmitterWithHolding(emitter, holder);
|
||||
}
|
||||
return this.__eventEmitter;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = mixInEventEmitter;
|
Загрузка…
Ссылка в новой задаче