mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-03-26 07:04:05 +08:00
Initial commit
This commit is contained in:
45
Libraries/Utilities/Dimensions.js
Normal file
45
Libraries/Utilities/Dimensions.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule Dimensions
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var NativeModules = require('NativeModules');
|
||||
|
||||
var invariant = require('invariant');
|
||||
var mergeInto = require('mergeInto');
|
||||
|
||||
var dimensions = NativeModules.RKUIManager.Dimensions;
|
||||
|
||||
class Dimensions {
|
||||
/**
|
||||
* This should only be called from native code.
|
||||
*
|
||||
* @param {object} dims Simple string-keyed object of dimensions to set
|
||||
*/
|
||||
static set(dims) {
|
||||
mergeInto(dimensions, dims);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial dimensions are set before `runApplication` is called so they should
|
||||
* be available before any other require's are run, but may be updated later.
|
||||
*
|
||||
* Note: Although dimensions are available immediately, they may change (e.g
|
||||
* due to device rotation) so any rendering logic or styles that depend on
|
||||
* these constants should try to call this function on every render, rather
|
||||
* than caching the value (for example, using inline styles rather than
|
||||
* setting a value in a `StyleSheet`).
|
||||
*
|
||||
* @param {string} dim Name of dimension as defined when calling `set`.
|
||||
* @returns {Object?} Value for the dimension.
|
||||
*/
|
||||
static get(dim) {
|
||||
invariant(dimensions[dim], 'No dimension set for key ' + dim);
|
||||
return dimensions[dim];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Dimensions;
|
||||
21
Libraries/Utilities/ErrorUtils.js
Normal file
21
Libraries/Utilities/ErrorUtils.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule ErrorUtils
|
||||
*/
|
||||
|
||||
var GLOBAL = this;
|
||||
|
||||
/**
|
||||
* The particular require runtime that we are using looks for a global
|
||||
* `ErrorUtils` object and if it exists, then it requires modules with the
|
||||
* error handler specified via ErrorUtils.setGlobalHandler by calling the
|
||||
* require function with applyWithGuard. Since the require module is loaded
|
||||
* before any of the modules, this ErrorUtils must be defined (and the handler
|
||||
* set) globally before requiring anything.
|
||||
*
|
||||
* However, we still want to treat ErrorUtils as a module so that other modules
|
||||
* that use it aren't just using a global variable, so simply export the global
|
||||
* variable here. ErrorUtils is original defined in a file named error-guard.js.
|
||||
*/
|
||||
module.exports = GLOBAL.ErrorUtils;
|
||||
476
Libraries/Utilities/MessageQueue.js
Normal file
476
Libraries/Utilities/MessageQueue.js
Normal file
@@ -0,0 +1,476 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule MessageQueue
|
||||
*/
|
||||
'use strict';
|
||||
var ErrorUtils = require('ErrorUtils');
|
||||
|
||||
var invariant = require('invariant');
|
||||
var warning = require('warning');
|
||||
|
||||
var JSTimersExecution = require('JSTimersExecution');
|
||||
|
||||
var INTERNAL_ERROR = 'Error in MessageQueue implementation';
|
||||
|
||||
/**
|
||||
* So as not to confuse static build system.
|
||||
*/
|
||||
var requireFunc = require;
|
||||
|
||||
/**
|
||||
* @param {Object!} module Module instance, must be loaded.
|
||||
* @param {string} methodName Name of method in `module`.
|
||||
* @param {array<*>} params Arguments to method.
|
||||
* @returns {*} Return value of method invocation.
|
||||
*/
|
||||
var jsCall = function(module, methodName, params) {
|
||||
return module[methodName].apply(module, params);
|
||||
};
|
||||
|
||||
/**
|
||||
* A utility for aggregating "work" to be done, and potentially transferring
|
||||
* that work to another thread. Each instance of `MessageQueue` has the notion
|
||||
* of a "target" thread - the thread that the work will be sent to.
|
||||
*
|
||||
* TODO: Long running callback results, and streaming callback results (ability
|
||||
* for a callback to be invoked multiple times).
|
||||
*
|
||||
* @param {object} moduleNameToID Used to translate module/method names into
|
||||
* efficient numeric IDs.
|
||||
* @class MessageQueue
|
||||
*/
|
||||
var MessageQueue = function(remoteModulesConfig, localModulesConfig, customRequire) {
|
||||
this._requireFunc = customRequire || requireFunc;
|
||||
this._initBookeeping();
|
||||
this._initNamingMap(remoteModulesConfig, localModulesConfig);
|
||||
};
|
||||
|
||||
// REQUEST: Parallell arrays:
|
||||
var REQUEST_MODULE_IDS = 0;
|
||||
var REQUEST_METHOD_IDS = 1;
|
||||
var REQUEST_PARAMSS = 2;
|
||||
// RESPONSE: Parallell arrays:
|
||||
var RESPONSE_CBIDS = 3;
|
||||
var RESPONSE_RETURN_VALUES = 4;
|
||||
|
||||
/**
|
||||
* Utility to catch errors and prevent having to bind, or execute a bound
|
||||
* function, while catching errors in a process and returning a resulting
|
||||
* return value. This ensures that even if a process fails, we can still return
|
||||
* *some* values (from `_flushedQueueUnguarded` for example). Glorified
|
||||
* try/catch/finally that invokes the global `onerror`.
|
||||
*
|
||||
* @param {function} operation Function to execute, likely populates the
|
||||
* message buffer.
|
||||
* @param {Array<*>} operationArguments Arguments passed to `operation`.
|
||||
* @param {function} getReturnValue Returns a return value - will be invoked
|
||||
* even if the `operation` fails half way through completing its task.
|
||||
* @return {object} Return value returned from `getReturnValue`.
|
||||
*/
|
||||
var guardReturn = function(operation, operationArguments, getReturnValue, context) {
|
||||
if (operation) {
|
||||
ErrorUtils.applyWithGuard(operation, context, operationArguments);
|
||||
}
|
||||
if (getReturnValue) {
|
||||
return ErrorUtils.applyWithGuard(getReturnValue, context, null);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Bookkeeping logic for callbackIDs. We ensure that success and error
|
||||
* callbacks are numerically adjacent.
|
||||
*
|
||||
* We could have also stored the association between success cbID and errorCBID
|
||||
* in a map without relying on this adjacency, but the bookkeeping here avoids
|
||||
* an additional two maps to associate in each direction, and avoids growing
|
||||
* dictionaries (new fields). Instead, we compute pairs of callback IDs, by
|
||||
* populating the `res` argument to `allocateCallbackIDs` (in conjunction with
|
||||
* pooling). Behind this bookeeping API, we ensure that error and success
|
||||
* callback IDs are always adjacent so that when one is invoked, we always know
|
||||
* how to free the memory of the other. By using this API, it is impossible to
|
||||
* create malformed callbackIDs that are not adjacent.
|
||||
*/
|
||||
var createBookkeeping = function() {
|
||||
return {
|
||||
/**
|
||||
* Incrementing callback ID. Must start at 1 - otherwise converted null
|
||||
* values which become zero are not distinguishable from a GUID of zero.
|
||||
*/
|
||||
GUID: 1,
|
||||
errorCallbackIDForSuccessCallbackID: function(successID) {
|
||||
return successID + 1;
|
||||
},
|
||||
successCallbackIDForErrorCallbackID: function(errorID) {
|
||||
return errorID - 1;
|
||||
},
|
||||
allocateCallbackIDs: function(res) {
|
||||
res.successCallbackID = this.GUID++;
|
||||
res.errorCallbackID = this.GUID++;
|
||||
},
|
||||
isSuccessCallback: function(id) {
|
||||
return id % 2 === 1;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var MessageQueueMixin = {
|
||||
/**
|
||||
* Creates an efficient wire protocol for communicating across a bridge.
|
||||
* Avoids allocating strings.
|
||||
*
|
||||
* @param {object} remoteModulesConfig Configuration of modules and their
|
||||
* methods.
|
||||
*/
|
||||
_initNamingMap: function(remoteModulesConfig, localModulesConfig) {
|
||||
this._remoteModuleNameToModuleID = {};
|
||||
this._remoteModuleIDToModuleName = {}; // Reverse
|
||||
|
||||
this._remoteModuleNameToMethodNameToID = {};
|
||||
this._remoteModuleNameToMethodIDToName = {}; // Reverse
|
||||
|
||||
this._localModuleNameToModuleID = {};
|
||||
this._localModuleIDToModuleName = {}; // Reverse
|
||||
|
||||
this._localModuleNameToMethodNameToID = {};
|
||||
this._localModuleNameToMethodIDToName = {}; // Reverse
|
||||
|
||||
function fillMappings(
|
||||
modulesConfig,
|
||||
moduleNameToModuleID,
|
||||
moduleIDToModuleName,
|
||||
moduleNameToMethodNameToID,
|
||||
moduleNameToMethodIDToName
|
||||
) {
|
||||
for (var moduleName in modulesConfig) {
|
||||
var moduleConfig = modulesConfig[moduleName];
|
||||
var moduleID = moduleConfig.moduleID;
|
||||
moduleNameToModuleID[moduleName] = moduleID;
|
||||
moduleIDToModuleName[moduleID] = moduleName; // Reverse
|
||||
|
||||
moduleNameToMethodNameToID[moduleName] = {};
|
||||
moduleNameToMethodIDToName[moduleName] = {}; // Reverse
|
||||
var methods = moduleConfig.methods;
|
||||
for (var methodName in methods) {
|
||||
var methodID = methods[methodName].methodID;
|
||||
moduleNameToMethodNameToID[moduleName][methodName] =
|
||||
methodID;
|
||||
moduleNameToMethodIDToName[moduleName][methodID] =
|
||||
methodName; // Reverse
|
||||
}
|
||||
}
|
||||
}
|
||||
fillMappings(
|
||||
remoteModulesConfig,
|
||||
this._remoteModuleNameToModuleID,
|
||||
this._remoteModuleIDToModuleName,
|
||||
this._remoteModuleNameToMethodNameToID,
|
||||
this._remoteModuleNameToMethodIDToName
|
||||
);
|
||||
|
||||
fillMappings(
|
||||
localModulesConfig,
|
||||
this._localModuleNameToModuleID,
|
||||
this._localModuleIDToModuleName,
|
||||
this._localModuleNameToMethodNameToID,
|
||||
this._localModuleNameToMethodIDToName
|
||||
);
|
||||
|
||||
},
|
||||
|
||||
_initBookeeping: function() {
|
||||
this._POOLED_CBIDS = {errorCallbackID: null, successCallbackID: null};
|
||||
this._bookkeeping = createBookkeeping();
|
||||
|
||||
/**
|
||||
* Stores callbacks so that we may simulate asynchronous return values from
|
||||
* other threads. Remote invocations in other threads can pass return values
|
||||
* back asynchronously to the requesting thread.
|
||||
*/
|
||||
this._threadLocalCallbacksByID = [];
|
||||
this._threadLocalScopesByID = [];
|
||||
|
||||
/**
|
||||
* Memory efficient parallel arrays. Each index cuts through the three
|
||||
* arrays and forms a remote invocation of methodName(params) whos return
|
||||
* value will be reported back to the other thread by way of the
|
||||
* corresponding id in cbIDs. Each entry (A-D in the graphic below),
|
||||
* represents a work item of the following form:
|
||||
* - moduleID: ID of module to invoke method from.
|
||||
* - methodID: ID of method in module to invoke.
|
||||
* - params: List of params to pass to method.
|
||||
* - cbID: ID to respond back to originating thread with.
|
||||
*
|
||||
* TODO: We can make this even more efficient (memory) by creating a single
|
||||
* array, that is always pushed `n` elements as a time.
|
||||
*/
|
||||
this._outgoingItems = [
|
||||
/*REQUEST_MODULE_IDS: */ [/* +-+ +-+ +-+ +-+ */],
|
||||
/*REQUEST_METHOD_IDS: */ [/* |A| |B| |C| |D| */],
|
||||
/*REQUEST_PARAMSS: */ [/* |-| |-| |-| |-| */],
|
||||
|
||||
/*RESPONSE_CBIDS: */ [/* +-+ +-+ +-+ +-+ */],
|
||||
/* |E| |F| |G| |H| */
|
||||
/*RESPONSE_RETURN_VALUES: */ [/* +-+ +-+ +-+ +-+ */]
|
||||
];
|
||||
|
||||
/**
|
||||
* Used to allow returning the buffer, while at the same time clearing it in
|
||||
* a memory efficient manner.
|
||||
*/
|
||||
this._outgoingItemsSwap = [[], [], [], [], []];
|
||||
},
|
||||
|
||||
invokeCallback: function(cbID, args) {
|
||||
return guardReturn(this._invokeCallback, [cbID, args], null, this);
|
||||
},
|
||||
|
||||
_invokeCallback: function(cbID, args) {
|
||||
try {
|
||||
var cb = this._threadLocalCallbacksByID[cbID];
|
||||
var scope = this._threadLocalScopesByID[cbID];
|
||||
warning(
|
||||
cb,
|
||||
'Cannot find callback with CBID %s. Native module may have invoked ' +
|
||||
'both the success callback and the error callback.',
|
||||
cbID
|
||||
);
|
||||
cb.apply(scope, args);
|
||||
} catch(ie_requires_catch) {
|
||||
throw ie_requires_catch;
|
||||
} finally {
|
||||
// Clear out the memory regardless of success or failure.
|
||||
this._freeResourcesForCallbackID(cbID);
|
||||
}
|
||||
},
|
||||
|
||||
invokeCallbackAndReturnFlushedQueue: function(cbID, args) {
|
||||
if (this._enableLogging) {
|
||||
this._loggedIncomingItems.push([new Date().getTime(), cbID, args]);
|
||||
}
|
||||
return guardReturn(
|
||||
this._invokeCallback,
|
||||
[cbID, args],
|
||||
this._flushedQueueUnguarded,
|
||||
this
|
||||
);
|
||||
},
|
||||
|
||||
callFunction: function(moduleID, methodID, params) {
|
||||
return guardReturn(this._callFunction, [moduleID, methodID, params], null, this);
|
||||
},
|
||||
|
||||
_callFunction: function(moduleID, methodID, params) {
|
||||
var moduleName = this._localModuleIDToModuleName[moduleID];
|
||||
|
||||
var methodName = this._localModuleNameToMethodIDToName[moduleName][methodID];
|
||||
var ret = jsCall(this._requireFunc(moduleName), methodName, params);
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
callFunctionReturnFlushedQueue: function(moduleID, methodID, params) {
|
||||
if (this._enableLogging) {
|
||||
this._loggedIncomingItems.push([new Date().getTime(), moduleID, methodID, params]);
|
||||
}
|
||||
return guardReturn(
|
||||
this._callFunction,
|
||||
[moduleID, methodID, params],
|
||||
this._flushedQueueUnguarded,
|
||||
this
|
||||
);
|
||||
},
|
||||
|
||||
setLoggingEnabled: function(enabled) {
|
||||
this._enableLogging = enabled;
|
||||
this._loggedIncomingItems = [];
|
||||
this._loggedOutgoingItems = [[], [], [], [], []];
|
||||
},
|
||||
|
||||
getLoggedIncomingItems: function() {
|
||||
return this._loggedIncomingItems;
|
||||
},
|
||||
|
||||
getLoggedOutgoingItems: function() {
|
||||
return this._loggedOutgoingItems;
|
||||
},
|
||||
|
||||
replayPreviousLog: function(previousLog) {
|
||||
this._outgoingItems = previousLog;
|
||||
},
|
||||
|
||||
/**
|
||||
* Simple helpers for clearing the queues. This doesn't handle the fact that
|
||||
* memory in the current buffer is leaked until the next frame or update - but
|
||||
* that will typically be on the order of < 500ms.
|
||||
*/
|
||||
_swapAndReinitializeBuffer: function() {
|
||||
// Outgoing requests
|
||||
var currentOutgoingItems = this._outgoingItems;
|
||||
var nextOutgoingItems = this._outgoingItemsSwap;
|
||||
|
||||
nextOutgoingItems[REQUEST_MODULE_IDS].length = 0;
|
||||
nextOutgoingItems[REQUEST_METHOD_IDS].length = 0;
|
||||
nextOutgoingItems[REQUEST_PARAMSS].length = 0;
|
||||
|
||||
// Outgoing responses
|
||||
nextOutgoingItems[RESPONSE_CBIDS].length = 0;
|
||||
nextOutgoingItems[RESPONSE_RETURN_VALUES].length = 0;
|
||||
|
||||
this._outgoingItemsSwap = currentOutgoingItems;
|
||||
this._outgoingItems = nextOutgoingItems;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} moduleID JS module name.
|
||||
* @param {methodName} methodName Method in module to invoke.
|
||||
* @param {array<*>?} params Array representing arguments to method.
|
||||
* @param {string} cbID Unique ID to pass back in potential response.
|
||||
*/
|
||||
_pushRequestToOutgoingItems: function(moduleID, methodName, params) {
|
||||
this._outgoingItems[REQUEST_MODULE_IDS].push(moduleID);
|
||||
this._outgoingItems[REQUEST_METHOD_IDS].push(methodName);
|
||||
this._outgoingItems[REQUEST_PARAMSS].push(params);
|
||||
|
||||
if (this._enableLogging) {
|
||||
this._loggedOutgoingItems[REQUEST_MODULE_IDS].push(moduleID);
|
||||
this._loggedOutgoingItems[REQUEST_METHOD_IDS].push(methodName);
|
||||
this._loggedOutgoingItems[REQUEST_PARAMSS].push(params);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} cbID Unique ID that other side of bridge has remembered.
|
||||
* @param {*} returnValue Return value to pass to callback on other side of
|
||||
* bridge.
|
||||
*/
|
||||
_pushResponseToOutgoingItems: function(cbID, returnValue) {
|
||||
this._outgoingItems[RESPONSE_CBIDS].push(cbID);
|
||||
this._outgoingItems[RESPONSE_RETURN_VALUES].push(returnValue);
|
||||
},
|
||||
|
||||
_freeResourcesForCallbackID: function(cbID) {
|
||||
var correspondingCBID = this._bookkeeping.isSuccessCallback(cbID) ?
|
||||
this._bookkeeping.errorCallbackIDForSuccessCallbackID(cbID) :
|
||||
this._bookkeeping.successCallbackIDForErrorCallbackID(cbID);
|
||||
this._threadLocalCallbacksByID[cbID] = null;
|
||||
this._threadLocalScopesByID[cbID] = null;
|
||||
if (this._threadLocalCallbacksByID[correspondingCBID]) {
|
||||
this._threadLocalCallbacksByID[correspondingCBID] = null;
|
||||
this._threadLocalScopesByID[correspondingCBID] = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Function} onFail Function to store in current thread for later
|
||||
* lookup, when request fails.
|
||||
* @param {Function} onSucc Function to store in current thread for later
|
||||
* lookup, when request succeeds.
|
||||
* @param {Object?=} scope Scope to invoke `cb` with.
|
||||
* @param {Object?=} res Resulting callback ids. Use `this._POOLED_CBIDS`.
|
||||
*/
|
||||
_storeCallbacksInCurrentThread: function(onFail, onSucc, scope) {
|
||||
invariant(onFail || onSucc, INTERNAL_ERROR);
|
||||
this._bookkeeping.allocateCallbackIDs(this._POOLED_CBIDS);
|
||||
var succCBID = this._POOLED_CBIDS.successCallbackID;
|
||||
var errorCBID = this._POOLED_CBIDS.errorCallbackID;
|
||||
this._threadLocalCallbacksByID[errorCBID] = onFail;
|
||||
this._threadLocalCallbacksByID[succCBID] = onSucc;
|
||||
this._threadLocalScopesByID[errorCBID] = scope;
|
||||
this._threadLocalScopesByID[succCBID] = scope;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* IMPORTANT: There is possibly a timing issue with this form of flushing. We
|
||||
* are currently not seeing any problems but the potential issue to look out
|
||||
* for is:
|
||||
* - While flushing this._outgoingItems contains the work for the other thread
|
||||
* to perform.
|
||||
* - To mitigate this, we never allow enqueueing messages if the queue is
|
||||
* already reserved - as long as it is reserved, it could be in the midst of
|
||||
* a flush.
|
||||
*
|
||||
* If this ever occurs we can easily eliminate the race condition. We can
|
||||
* completely solve any ambiguity by sending messages such that we'll never
|
||||
* try to reserve the queue when already reserved. Here's the pseudocode:
|
||||
*
|
||||
* var defensiveCopy = efficientDefensiveCopy(this._outgoingItems);
|
||||
* this._swapAndReinitializeBuffer();
|
||||
*/
|
||||
flushedQueue: function() {
|
||||
return guardReturn(null, null, this._flushedQueueUnguarded, this);
|
||||
},
|
||||
|
||||
_flushedQueueUnguarded: function() {
|
||||
// Call the functions registred via setImmediate
|
||||
JSTimersExecution.callImmediates();
|
||||
|
||||
var currentOutgoingItems = this._outgoingItems;
|
||||
this._swapAndReinitializeBuffer();
|
||||
var ret = currentOutgoingItems[REQUEST_MODULE_IDS].length ||
|
||||
currentOutgoingItems[RESPONSE_RETURN_VALUES].length ? currentOutgoingItems : null;
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
callDeprecated: function(moduleName, methodName, params, cb, scope) {
|
||||
invariant(
|
||||
!cb || typeof cb === 'function',
|
||||
'Last argument (callback) must be function'
|
||||
);
|
||||
// Store callback _before_ sending the request, just in case the MailBox
|
||||
// returns the response in a blocking manner
|
||||
if (cb) {
|
||||
this._storeCallbacksInCurrentThread(null, cb, scope, this._POOLED_CBIDS);
|
||||
params.push(this._POOLED_CBIDS.successCallbackID);
|
||||
}
|
||||
var moduleID = this._remoteModuleNameToModuleID[moduleName];
|
||||
if (moduleID === undefined || moduleID === null) {
|
||||
throw new Error('Unrecognized module name:' + moduleName);
|
||||
}
|
||||
var methodID = this._remoteModuleNameToMethodNameToID[moduleName][methodName];
|
||||
if (methodID === undefined || moduleID === null) {
|
||||
throw new Error('Unrecognized method name:' + methodName);
|
||||
}
|
||||
this._pushRequestToOutgoingItems(moduleID, methodID, params);
|
||||
},
|
||||
|
||||
call: function(moduleName, methodName, params, onFail, onSucc, scope) {
|
||||
invariant(
|
||||
(!onFail || typeof onFail === 'function') &&
|
||||
(!onSucc || typeof onSucc === 'function'),
|
||||
'Callbacks must be functions'
|
||||
);
|
||||
// Store callback _before_ sending the request, just in case the MailBox
|
||||
// returns the response in a blocking manner.
|
||||
if (onFail || onSucc) {
|
||||
this._storeCallbacksInCurrentThread(onFail, onSucc, scope, this._POOLED_CBIDS);
|
||||
params.push(this._POOLED_CBIDS.errorCallbackID);
|
||||
params.push(this._POOLED_CBIDS.successCallbackID);
|
||||
}
|
||||
var moduleID = this._remoteModuleNameToModuleID[moduleName];
|
||||
if (moduleID === undefined || moduleID === null) {
|
||||
throw new Error('Unrecognized module name:' + moduleName);
|
||||
}
|
||||
var methodID = this._remoteModuleNameToMethodNameToID[moduleName][methodName];
|
||||
if (methodID === undefined || moduleID === null) {
|
||||
throw new Error('Unrecognized method name:' + methodName);
|
||||
}
|
||||
this._pushRequestToOutgoingItems(moduleID, methodID, params);
|
||||
},
|
||||
__numPendingCallbacksOnlyUseMeInTestCases: function() {
|
||||
var callbacks = this._threadLocalCallbacksByID;
|
||||
var total = 0;
|
||||
for (var i = 0; i < callbacks.length; i++) {
|
||||
if (callbacks[i]) {
|
||||
total++;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
};
|
||||
|
||||
Object.assign(MessageQueue.prototype, MessageQueueMixin);
|
||||
module.exports = MessageQueue;
|
||||
54
Libraries/Utilities/PixelRatio.js
Normal file
54
Libraries/Utilities/PixelRatio.js
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule PixelRatio
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var Dimensions = require('Dimensions');
|
||||
|
||||
/**
|
||||
* PixelRatio class gives access to the device pixel density.
|
||||
*
|
||||
* Some examples:
|
||||
* - PixelRatio.get() === 2
|
||||
* - iPhone 4, 4S
|
||||
* - iPhone 5, 5c, 5s
|
||||
* - iPhone 6
|
||||
*
|
||||
* - PixelRatio.get() === 3
|
||||
* - iPhone 6 plus
|
||||
*
|
||||
* There are a few use cases for using PixelRatio:
|
||||
*
|
||||
* == Displaying a line that's as thin as the device permits
|
||||
*
|
||||
* A width of 1 is actually pretty thick on an iPhone 4+, we can do one that's
|
||||
* thinner using a width of 1 / PixelRatio.get(). It's a technique that works
|
||||
* on all the devices independent of their pixel density.
|
||||
*
|
||||
* style={{ borderWidth: 1 / PixelRatio.get() }}
|
||||
*
|
||||
* == Fetching a correctly sized image
|
||||
*
|
||||
* You should get a higher resolution image if you are on a high pixel density
|
||||
* device. A good rule of thumb is to multiply the size of the image you display
|
||||
* by the pixel ratio.
|
||||
*
|
||||
* var image = getImage({
|
||||
* width: 200 * PixelRatio.get(),
|
||||
* height: 100 * PixelRatio.get()
|
||||
* });
|
||||
* <Image source={image} style={{width: 200, height: 100}} />
|
||||
*/
|
||||
class PixelRatio {
|
||||
static get() {
|
||||
return Dimensions.get('window').scale;
|
||||
}
|
||||
|
||||
static startDetecting() {
|
||||
// no-op for iOS, but this is useful for other platforms
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = PixelRatio;
|
||||
11
Libraries/Utilities/Platform.ios.js
Normal file
11
Libraries/Utilities/Platform.ios.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @providesModule Platform
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var Platform = {
|
||||
OS: 'ios',
|
||||
};
|
||||
|
||||
module.exports = Platform;
|
||||
37
Libraries/Utilities/RCTLog.js
Normal file
37
Libraries/Utilities/RCTLog.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule RCTLog
|
||||
*/
|
||||
/* globals nativeLoggingHook */
|
||||
'use strict';
|
||||
|
||||
var invariant = require('invariant');
|
||||
|
||||
var levelsMap = {
|
||||
log: 'log',
|
||||
info: 'info',
|
||||
warn: 'warn',
|
||||
error: 'error',
|
||||
mustfix: 'error',
|
||||
};
|
||||
|
||||
class RCTLog {
|
||||
// level one of log, info, warn, error, mustfix
|
||||
static logIfNoNativeHook() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var level = args.shift();
|
||||
var logFn = levelsMap[level];
|
||||
invariant(
|
||||
logFn,
|
||||
'Level "' + level + '" not one of ' + Object.keys(levelsMap)
|
||||
);
|
||||
if (typeof nativeLoggingHook === 'undefined') {
|
||||
// We already printed in xcode, so only log here if using a js debugger
|
||||
console[logFn].apply(console, args);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RCTLog;
|
||||
41
Libraries/Utilities/RCTRenderingPerf.js
Normal file
41
Libraries/Utilities/RCTRenderingPerf.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule RCTRenderingPerf
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ReactDefaultPerf = require('ReactDefaultPerf');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
|
||||
var invariant = require('invariant');
|
||||
var perfModules = [];
|
||||
|
||||
var RCTRenderingPerf = {
|
||||
toggle: function() {
|
||||
if (ReactPerf.enableMeasure) {
|
||||
ReactDefaultPerf.stop();
|
||||
ReactDefaultPerf.printInclusive();
|
||||
ReactDefaultPerf.printWasted();
|
||||
perfModules.forEach((module) => module.stop());
|
||||
} else {
|
||||
ReactDefaultPerf.start();
|
||||
console.log('Render perfomance measurements started');
|
||||
perfModules.forEach((module) => module.start());
|
||||
}
|
||||
},
|
||||
|
||||
register: function(module) {
|
||||
invariant(
|
||||
typeof module.start === 'function',
|
||||
'Perf module should have start() function'
|
||||
);
|
||||
invariant(
|
||||
typeof module.stop === 'function',
|
||||
'Perf module should have stop() function'
|
||||
);
|
||||
perfModules.push(module);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = RCTRenderingPerf;
|
||||
97
Libraries/Utilities/TimerMixin.js
Normal file
97
Libraries/Utilities/TimerMixin.js
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule TimerMixin
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Using bare setTimeout, setInterval, setImmediate and
|
||||
* requestAnimationFrame calls is very dangerous because if you forget to cancel
|
||||
* the request before the component is unmounted, you risk the callback throwing
|
||||
* an exception.
|
||||
*
|
||||
* If you include TimerMixin, then you can replace your calls
|
||||
* to `setTimeout(fn, 500)`
|
||||
* with `this.setTimeout(fn, 500)` (just prepend `this.`)
|
||||
* and everything will be properly cleaned up for you.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* var Component = React.createClass({
|
||||
* mixins: [TimerMixin],
|
||||
* componentDidMount: function() {
|
||||
* this.setTimeout(
|
||||
* () => { console.log('I do not leak!'); },
|
||||
* 500
|
||||
* );
|
||||
* }
|
||||
* });
|
||||
*/
|
||||
|
||||
var setter = function(setter, clearer, array) {
|
||||
return function(callback, delta) {
|
||||
var id = setter(() => {
|
||||
clearer.call(this, id);
|
||||
callback.apply(this, arguments);
|
||||
}, delta);
|
||||
|
||||
if (!this[array]) {
|
||||
this[array] = [id];
|
||||
} else {
|
||||
this[array].push(id);
|
||||
}
|
||||
return id;
|
||||
};
|
||||
};
|
||||
|
||||
var clearer = function(clearer, array) {
|
||||
return function(id) {
|
||||
if (this[array]) {
|
||||
var index = this[array].indexOf(id);
|
||||
if (index !== -1) {
|
||||
this[array].splice(index, 1);
|
||||
}
|
||||
}
|
||||
clearer(id);
|
||||
};
|
||||
};
|
||||
|
||||
var _timeouts = 'TimerMixin_timeouts';
|
||||
var _clearTimeout = clearer(clearTimeout, _timeouts);
|
||||
var _setTimeout = setter(setTimeout, _clearTimeout, _timeouts);
|
||||
|
||||
var _intervals = 'TimerMixin_intervals';
|
||||
var _clearInterval = clearer(clearInterval, _intervals);
|
||||
var _setInterval = setter(setInterval, () => {/* noop */}, _intervals);
|
||||
|
||||
var _immediates = 'TimerMixin_immediates';
|
||||
var _clearImmediate = clearer(clearImmediate, _immediates);
|
||||
var _setImmediate = setter(setImmediate, _clearImmediate, _immediates);
|
||||
|
||||
var _rafs = 'TimerMixin_rafs';
|
||||
var _cancelAnimationFrame = clearer(cancelAnimationFrame, _rafs);
|
||||
var _requestAnimationFrame = setter(requestAnimationFrame, _cancelAnimationFrame, _rafs);
|
||||
|
||||
var TimerMixin = {
|
||||
componentWillUnmount: function() {
|
||||
this[_timeouts] && this[_timeouts].forEach(this.clearTimeout);
|
||||
this[_intervals] && this[_intervals].forEach(this.clearInterval);
|
||||
this[_immediates] && this[_immediates].forEach(this.clearImmediate);
|
||||
this[_rafs] && this[_rafs].forEach(this.cancelAnimationFrame);
|
||||
},
|
||||
|
||||
setTimeout: _setTimeout,
|
||||
clearTimeout: _clearTimeout,
|
||||
|
||||
setInterval: _setInterval,
|
||||
clearInterval: _clearInterval,
|
||||
|
||||
setImmediate: _setImmediate,
|
||||
clearImmediate: _clearImmediate,
|
||||
|
||||
requestAnimationFrame: _requestAnimationFrame,
|
||||
cancelAnimationFrame: _cancelAnimationFrame,
|
||||
};
|
||||
|
||||
module.exports = TimerMixin;
|
||||
62
Libraries/Utilities/createStrictShapeTypeChecker.js
Normal file
62
Libraries/Utilities/createStrictShapeTypeChecker.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule createStrictShapeTypeChecker
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
|
||||
|
||||
var invariant = require('invariant');
|
||||
var merge = require('merge');
|
||||
|
||||
function createStrictShapeTypeChecker(shapeTypes) {
|
||||
function checkType(isRequired, props, propName, componentName, location) {
|
||||
if (!props[propName]) {
|
||||
if (isRequired) {
|
||||
invariant(
|
||||
false,
|
||||
`Required object \`${propName}\` was not specified in `+
|
||||
`\`${componentName}\`.`
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var propValue = props[propName];
|
||||
var propType = typeof propValue;
|
||||
var locationName = ReactPropTypeLocationNames[location];
|
||||
if (propType !== 'object') {
|
||||
invariant(
|
||||
false,
|
||||
`Invalid ${locationName} \`${propName}\` of type \`${propType}\` ` +
|
||||
`supplied to \`${componentName}\`, expected \`object\`.`
|
||||
);
|
||||
}
|
||||
// We need to check all keys in case some are required but missing from
|
||||
// props.
|
||||
var allKeys = merge(props[propName], shapeTypes);
|
||||
for (var key in allKeys) {
|
||||
var checker = shapeTypes[key];
|
||||
invariant(
|
||||
checker,
|
||||
`Invalid props.${propName} key \`${key}\` supplied to \`${componentName}\`.` +
|
||||
`\nBad object: ` + JSON.stringify(props[propName], null, ' ') +
|
||||
`\nValid keys: ` + JSON.stringify(Object.keys(shapeTypes), null, ' ')
|
||||
);
|
||||
var error = checker(propValue, key, componentName, location);
|
||||
if (error) {
|
||||
invariant(
|
||||
false,
|
||||
error.message +
|
||||
`\nBad object: ` + JSON.stringify(props[propName], null, ' ')
|
||||
);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
var chainedCheckType = checkType.bind(null, false);
|
||||
chainedCheckType.isRequired = checkType.bind(null, true);
|
||||
return chainedCheckType;
|
||||
}
|
||||
|
||||
module.exports = createStrictShapeTypeChecker;
|
||||
57
Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js
Normal file
57
Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule deepFreezeAndThrowOnMutationInDev
|
||||
*/
|
||||
|
||||
/**
|
||||
* If your application is accepting different values for the same field over
|
||||
* time and is doing a diff on them, you can either (1) create a copy or
|
||||
* (2) ensure that those values are not mutated behind two passes.
|
||||
* This function helps you with (2) by freezing the object and throwing if
|
||||
* the user subsequently modifies the value.
|
||||
*
|
||||
* There are two caveats with this function:
|
||||
* - If the call site is not in strict mode, it will only throw when
|
||||
* mutating existing fields, adding a new one
|
||||
* will unfortunately fail silently :(
|
||||
* - If the object is already frozen or sealed, it will not continue the
|
||||
* deep traversal and will leave leaf nodes unfrozen.
|
||||
*
|
||||
* Freezing the object and adding the throw mechanism is expensive and will
|
||||
* only be used in DEV.
|
||||
*/
|
||||
function deepFreezeAndThrowOnMutationInDev(object) {
|
||||
if (__DEV__) {
|
||||
if (typeof object !== 'object' ||
|
||||
object === null ||
|
||||
Object.isFrozen(object) ||
|
||||
Object.isSealed(object)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var key in object) {
|
||||
if (object.hasOwnProperty(key)) {
|
||||
object.__defineGetter__(key, identity.bind(null, object[key]));
|
||||
object.__defineSetter__(key, throwOnImmutableMutation.bind(null, key));
|
||||
deepFreezeAndThrowOnMutationInDev(object[key]);
|
||||
}
|
||||
}
|
||||
Object.freeze(object);
|
||||
Object.seal(object);
|
||||
}
|
||||
}
|
||||
|
||||
function throwOnImmutableMutation(key, value) {
|
||||
throw Error(
|
||||
'You attempted to set the key `' + key + '` with the value `' +
|
||||
JSON.stringify(value) + '` on an object that is meant to be immutable ' +
|
||||
'and has been frozen.'
|
||||
);
|
||||
}
|
||||
|
||||
function identity(value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
module.exports = deepFreezeAndThrowOnMutationInDev;
|
||||
48
Libraries/Utilities/differ/deepDiffer.js
Normal file
48
Libraries/Utilities/differ/deepDiffer.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule deepDiffer
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* @returns {bool} true if different, false if equal
|
||||
*/
|
||||
var deepDiffer = function(one: any, two: any): bool {
|
||||
if (one === two) {
|
||||
// Short circuit on identical object references instead of traversing them.
|
||||
return false;
|
||||
}
|
||||
if ((typeof one === 'function') && (typeof two === 'function')) {
|
||||
// We consider all functions equal
|
||||
return false;
|
||||
}
|
||||
if ((typeof one !== 'object') || (one === null)) {
|
||||
// Primitives can be directly compared
|
||||
return one !== two;
|
||||
}
|
||||
if ((typeof two !== 'object') || (two === null)) {
|
||||
// We know they are different because the previous case would have triggered
|
||||
// otherwise.
|
||||
return true;
|
||||
}
|
||||
if (one.constructor !== two.constructor) {
|
||||
return true;
|
||||
}
|
||||
for (var key in one) {
|
||||
if (deepDiffer(one[key], two[key])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (var twoKey in two) {
|
||||
// The only case we haven't checked yet is keys that are in two but aren't
|
||||
// in one, which means they are different.
|
||||
if (one[twoKey] === undefined) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
module.exports = deepDiffer;
|
||||
26
Libraries/Utilities/differ/insetsDiffer.js
Normal file
26
Libraries/Utilities/differ/insetsDiffer.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule insetsDiffer
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var dummyInsets = {
|
||||
top: undefined,
|
||||
left: undefined,
|
||||
right: undefined,
|
||||
bottom: undefined,
|
||||
};
|
||||
|
||||
var insetsDiffer = function(one, two) {
|
||||
one = one || dummyInsets;
|
||||
two = two || dummyInsets;
|
||||
return one !== two && (
|
||||
one.top !== two.top ||
|
||||
one.left !== two.left ||
|
||||
one.right !== two.right ||
|
||||
one.bottom !== two.bottom
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = insetsDiffer;
|
||||
39
Libraries/Utilities/differ/matricesDiffer.js
Normal file
39
Libraries/Utilities/differ/matricesDiffer.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule matricesDiffer
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Unrolls an array comparison specially for matrices. Prioritizes
|
||||
* checking of indices that are most likely to change so that the comparison
|
||||
* bails as early as possible.
|
||||
*
|
||||
* @param {MatrixMath.Matrix} one First matrix.
|
||||
* @param {MatrixMath.Matrix} two Second matrix.
|
||||
* @return {boolean} Whether or not the two matrices differ.
|
||||
*/
|
||||
var matricesDiffer = function(one, two) {
|
||||
if (one === two) {
|
||||
return false;
|
||||
}
|
||||
return !one || !two ||
|
||||
one[12] !== two[12] ||
|
||||
one[13] !== two[13] ||
|
||||
one[14] !== two[14] ||
|
||||
one[5] !== two[5] ||
|
||||
one[10] !== two[10] ||
|
||||
one[1] !== two[1] ||
|
||||
one[2] !== two[2] ||
|
||||
one[3] !== two[3] ||
|
||||
one[4] !== two[4] ||
|
||||
one[6] !== two[6] ||
|
||||
one[7] !== two[7] ||
|
||||
one[8] !== two[8] ||
|
||||
one[9] !== two[9] ||
|
||||
one[11] !== two[11] ||
|
||||
one[15] !== two[15];
|
||||
};
|
||||
|
||||
module.exports = matricesDiffer;
|
||||
19
Libraries/Utilities/differ/pointsDiffer.js
Normal file
19
Libraries/Utilities/differ/pointsDiffer.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule pointsDiffer
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var dummyPoint = {x: undefined, y: undefined};
|
||||
|
||||
var pointsDiffer = function(one, two) {
|
||||
one = one || dummyPoint;
|
||||
two = two || dummyPoint;
|
||||
return one !== two && (
|
||||
one.x !== two.x ||
|
||||
one.y !== two.y
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = pointsDiffer;
|
||||
22
Libraries/Utilities/logError.js
Normal file
22
Libraries/Utilities/logError.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule logError
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Small utility that can be used as an error handler. You cannot just pass
|
||||
* `console.error` as a failure callback - it's not properly bound. If passes an
|
||||
* `Error` object, it will print the message and stack.
|
||||
*/
|
||||
var logError = function() {
|
||||
if (arguments.length === 1 && arguments[0] instanceof Error) {
|
||||
var err = arguments[0];
|
||||
console.error('Error: "' + err.message + '". Stack:\n' + err.stack);
|
||||
} else {
|
||||
console.error.apply(console, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = logError;
|
||||
28
Libraries/Utilities/mergeFast.js
Normal file
28
Libraries/Utilities/mergeFast.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule mergeFast
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Faster version of `merge` that doesn't check its arguments and
|
||||
* also merges prototye inherited properties.
|
||||
*
|
||||
* @param {object} one Any non-null object.
|
||||
* @param {object} two Any non-null object.
|
||||
* @return {object} Merging of two objects, including prototype
|
||||
* inherited properties.
|
||||
*/
|
||||
var mergeFast = function(one, two) {
|
||||
var ret = {};
|
||||
for (var keyOne in one) {
|
||||
ret[keyOne] = one[keyOne];
|
||||
}
|
||||
for (var keyTwo in two) {
|
||||
ret[keyTwo] = two[keyTwo];
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
module.exports = mergeFast;
|
||||
21
Libraries/Utilities/mergeIntoFast.js
Normal file
21
Libraries/Utilities/mergeIntoFast.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule mergeIntoFast
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Faster version of `mergeInto` that doesn't check its arguments and
|
||||
* also copies over prototye inherited properties.
|
||||
*
|
||||
* @param {object} one Object to assign to.
|
||||
* @param {object} two Object to assign from.
|
||||
*/
|
||||
var mergeIntoFast = function(one, two) {
|
||||
for (var keyTwo in two) {
|
||||
one[keyTwo] = two[keyTwo];
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = mergeIntoFast;
|
||||
32
Libraries/Utilities/truncate.js
Normal file
32
Libraries/Utilities/truncate.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule truncate
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var merge = require('merge');
|
||||
|
||||
var defaultOptions = {
|
||||
breakOnWords: true,
|
||||
minDelta: 10, // Prevents truncating a tiny bit off the end
|
||||
elipsis: '...',
|
||||
};
|
||||
|
||||
// maxChars (including elipsis)
|
||||
var truncate = function(str, maxChars, options) {
|
||||
options = merge(defaultOptions, options);
|
||||
if (str && str.length &&
|
||||
str.length - options.minDelta + options.elipsis.length >= maxChars) {
|
||||
str = str.slice(0, maxChars - options.elipsis.length + 1);
|
||||
if (options.breakOnWords) {
|
||||
var ii = Math.max(str.lastIndexOf(' '), str.lastIndexOf('\n'));
|
||||
str = str.slice(0, ii);
|
||||
}
|
||||
str = str.trim() + options.elipsis;
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
module.exports = truncate;
|
||||
|
||||
20
Libraries/Utilities/validAttributesFromPropTypes.js
Normal file
20
Libraries/Utilities/validAttributesFromPropTypes.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule validAttributesFromPropTypes
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
function validAttributesFromPropTypes(propTypes) {
|
||||
var validAttributes = {};
|
||||
for (var key in propTypes) {
|
||||
var propType = propTypes[key];
|
||||
if (propType && propType.isNative) {
|
||||
var diff = propType.differ;
|
||||
validAttributes[key] = diff ? {diff} : true;
|
||||
}
|
||||
}
|
||||
return validAttributes;
|
||||
}
|
||||
|
||||
module.exports = validAttributesFromPropTypes;
|
||||
Reference in New Issue
Block a user