You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
4.6 KiB
150 lines
4.6 KiB
10 years ago
|
/**
|
||
|
* Copyright 2013-2015, Facebook, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* This source code is licensed under the BSD-style license found in the
|
||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||
|
*
|
||
|
* @providesModule ReactChildren
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
var PooledClass = require("./PooledClass");
|
||
|
var ReactFragment = require("./ReactFragment");
|
||
|
|
||
|
var traverseAllChildren = require("./traverseAllChildren");
|
||
|
var warning = require("./warning");
|
||
|
|
||
|
var twoArgumentPooler = PooledClass.twoArgumentPooler;
|
||
|
var threeArgumentPooler = PooledClass.threeArgumentPooler;
|
||
|
|
||
|
/**
|
||
|
* PooledClass representing the bookkeeping associated with performing a child
|
||
|
* traversal. Allows avoiding binding callbacks.
|
||
|
*
|
||
|
* @constructor ForEachBookKeeping
|
||
|
* @param {!function} forEachFunction Function to perform traversal with.
|
||
|
* @param {?*} forEachContext Context to perform context with.
|
||
|
*/
|
||
|
function ForEachBookKeeping(forEachFunction, forEachContext) {
|
||
|
this.forEachFunction = forEachFunction;
|
||
|
this.forEachContext = forEachContext;
|
||
|
}
|
||
|
PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler);
|
||
|
|
||
|
function forEachSingleChild(traverseContext, child, name, i) {
|
||
|
var forEachBookKeeping = traverseContext;
|
||
|
forEachBookKeeping.forEachFunction.call(
|
||
|
forEachBookKeeping.forEachContext, child, i);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Iterates through children that are typically specified as `props.children`.
|
||
|
*
|
||
|
* The provided forEachFunc(child, index) will be called for each
|
||
|
* leaf child.
|
||
|
*
|
||
|
* @param {?*} children Children tree container.
|
||
|
* @param {function(*, int)} forEachFunc.
|
||
|
* @param {*} forEachContext Context for forEachContext.
|
||
|
*/
|
||
|
function forEachChildren(children, forEachFunc, forEachContext) {
|
||
|
if (children == null) {
|
||
|
return children;
|
||
|
}
|
||
|
|
||
|
var traverseContext =
|
||
|
ForEachBookKeeping.getPooled(forEachFunc, forEachContext);
|
||
|
traverseAllChildren(children, forEachSingleChild, traverseContext);
|
||
|
ForEachBookKeeping.release(traverseContext);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* PooledClass representing the bookkeeping associated with performing a child
|
||
|
* mapping. Allows avoiding binding callbacks.
|
||
|
*
|
||
|
* @constructor MapBookKeeping
|
||
|
* @param {!*} mapResult Object containing the ordered map of results.
|
||
|
* @param {!function} mapFunction Function to perform mapping with.
|
||
|
* @param {?*} mapContext Context to perform mapping with.
|
||
|
*/
|
||
|
function MapBookKeeping(mapResult, mapFunction, mapContext) {
|
||
|
this.mapResult = mapResult;
|
||
|
this.mapFunction = mapFunction;
|
||
|
this.mapContext = mapContext;
|
||
|
}
|
||
|
PooledClass.addPoolingTo(MapBookKeeping, threeArgumentPooler);
|
||
|
|
||
|
function mapSingleChildIntoContext(traverseContext, child, name, i) {
|
||
|
var mapBookKeeping = traverseContext;
|
||
|
var mapResult = mapBookKeeping.mapResult;
|
||
|
|
||
|
var keyUnique = !mapResult.hasOwnProperty(name);
|
||
|
if ("production" !== process.env.NODE_ENV) {
|
||
|
("production" !== process.env.NODE_ENV ? warning(
|
||
|
keyUnique,
|
||
|
'ReactChildren.map(...): Encountered two children with the same key, ' +
|
||
|
'`%s`. Child keys must be unique; when two children share a key, only ' +
|
||
|
'the first child will be used.',
|
||
|
name
|
||
|
) : null);
|
||
|
}
|
||
|
|
||
|
if (keyUnique) {
|
||
|
var mappedChild =
|
||
|
mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i);
|
||
|
mapResult[name] = mappedChild;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Maps children that are typically specified as `props.children`.
|
||
|
*
|
||
|
* The provided mapFunction(child, key, index) will be called for each
|
||
|
* leaf child.
|
||
|
*
|
||
|
* TODO: This may likely break any calls to `ReactChildren.map` that were
|
||
|
* previously relying on the fact that we guarded against null children.
|
||
|
*
|
||
|
* @param {?*} children Children tree container.
|
||
|
* @param {function(*, int)} mapFunction.
|
||
|
* @param {*} mapContext Context for mapFunction.
|
||
|
* @return {object} Object containing the ordered map of results.
|
||
|
*/
|
||
|
function mapChildren(children, func, context) {
|
||
|
if (children == null) {
|
||
|
return children;
|
||
|
}
|
||
|
|
||
|
var mapResult = {};
|
||
|
var traverseContext = MapBookKeeping.getPooled(mapResult, func, context);
|
||
|
traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
|
||
|
MapBookKeeping.release(traverseContext);
|
||
|
return ReactFragment.create(mapResult);
|
||
|
}
|
||
|
|
||
|
function forEachSingleChildDummy(traverseContext, child, name, i) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Count the number of children that are typically specified as
|
||
|
* `props.children`.
|
||
|
*
|
||
|
* @param {?*} children Children tree container.
|
||
|
* @return {number} The number of children.
|
||
|
*/
|
||
|
function countChildren(children, context) {
|
||
|
return traverseAllChildren(children, forEachSingleChildDummy, null);
|
||
|
}
|
||
|
|
||
|
var ReactChildren = {
|
||
|
forEach: forEachChildren,
|
||
|
map: mapChildren,
|
||
|
count: countChildren
|
||
|
};
|
||
|
|
||
|
module.exports = ReactChildren;
|