Merge pull request #934 from syranide/minid

Shortened generated "data-reactid"
This commit is contained in:
Pete Hunt
2014-01-20 13:26:42 -08:00
10 changed files with 101 additions and 73 deletions
@@ -36,8 +36,8 @@ describe('ReactTransitionKeySet', function() {
var component = <div>{one}{two}</div>;
expect(ReactTransitionKeySet.getChildMapping(component.props.children))
.toEqual({
'{one}': one,
'{two}': two
'.$one': one,
'.$two': two
});
});
@@ -48,8 +48,8 @@ describe('ReactTransitionKeySet', function() {
var two = <div key="two" />;
var component = <div>{one}{two}</div>;
expect(ReactTransitionKeySet.getKeySet(component.props.children)).toEqual({
'{one}': true,
'{two}': true
'.$one': true,
'.$two': true
});
});
+7 -4
View File
@@ -39,7 +39,7 @@ var MAX_TREE_DEPTH = 100;
* @internal
*/
function getReactRootIDString(index) {
return SEPARATOR + 'r[' + index.toString(36) + ']';
return SEPARATOR + index.toString(36);
}
/**
@@ -241,7 +241,7 @@ var ReactInstanceHandles = {
* @internal
*/
createReactID: function(rootID, name) {
return rootID + SEPARATOR + name;
return rootID + name;
},
/**
@@ -253,8 +253,11 @@ var ReactInstanceHandles = {
* @internal
*/
getReactRootIDFromNodeID: function(id) {
var regexResult = /\.r\[[^\]]+\]/.exec(id);
return regexResult && regexResult[0];
if (id && id.charAt(0) === SEPARATOR && id.length > 1) {
var index = id.indexOf(SEPARATOR, 1);
return index > -1 ? id.substr(0, index) : id;
}
return null;
},
/**
+2 -2
View File
@@ -193,7 +193,7 @@ var ReactMultiChild = {
var child = children[name];
if (children.hasOwnProperty(name)) {
// Inlined for performance, see `ReactInstanceHandles.createReactID`.
var rootID = this._rootNodeID + '.' + name;
var rootID = this._rootNodeID + name;
var mountImage = child.mountComponent(
rootID,
transaction,
@@ -385,7 +385,7 @@ var ReactMultiChild = {
*/
_mountChildByNameAtIndex: function(child, name, index, transaction) {
// Inlined for performance, see `ReactInstanceHandles.createReactID`.
var rootID = this._rootNodeID + '.' + name;
var rootID = this._rootNodeID + name;
var mountImage = child.mountComponent(
rootID,
transaction,
+17 -15
View File
@@ -34,7 +34,7 @@ describe('ReactIdentity', function() {
ReactMount = require('ReactMount');
});
var idExp = /^\.r\[.+?\](.*)$/;
var idExp = /^\.[^.]+(.*)$/;
function checkId(child, expectedId) {
var actual = idExp.exec(ReactMount.getID(child));
var expected = idExp.exec(expectedId);
@@ -55,8 +55,8 @@ describe('ReactIdentity', function() {
React.renderComponent(instance, document.createElement('div'));
var node = instance.getDOMNode();
reactComponentExpect(instance).toBeDOMComponentWithChildCount(2);
checkId(node.childNodes[0], '.r[0].{first}[0]');
checkId(node.childNodes[1], '.r[0].{second}[0]');
checkId(node.childNodes[0], '.0.$first:0');
checkId(node.childNodes[1], '.0.$second:0');
});
it('should allow key property to express identity', function() {
@@ -71,10 +71,10 @@ describe('ReactIdentity', function() {
React.renderComponent(instance, document.createElement('div'));
var node = instance.getDOMNode();
reactComponentExpect(instance).toBeDOMComponentWithChildCount(4);
checkId(node.childNodes[0], '.r[0].{apple}');
checkId(node.childNodes[1], '.r[0].{banana}');
checkId(node.childNodes[2], '.r[0].{0}');
checkId(node.childNodes[3], '.r[0].{123}');
checkId(node.childNodes[0], '.0.$apple');
checkId(node.childNodes[1], '.0.$banana');
checkId(node.childNodes[2], '.0.$0');
checkId(node.childNodes[3], '.0.$123');
});
it('should use instance identity', function() {
@@ -96,12 +96,12 @@ describe('ReactIdentity', function() {
var node = instance.getDOMNode();
reactComponentExpect(instance).toBeDOMComponentWithChildCount(3);
checkId(node.childNodes[0], '.r[0].{wrap1}');
checkId(node.childNodes[0].firstChild, '.r[0].{wrap1}.{squirrel}');
checkId(node.childNodes[1], '.r[0].{wrap2}');
checkId(node.childNodes[1].firstChild, '.r[0].{wrap2}.{bunny}');
checkId(node.childNodes[2], '.r[0].[2]');
checkId(node.childNodes[2].firstChild, '.r[0].[2].{chipmunk}');
checkId(node.childNodes[0], '.0.$wrap1');
checkId(node.childNodes[0].firstChild, '.0.$wrap1.$squirrel');
checkId(node.childNodes[1], '.0.$wrap2');
checkId(node.childNodes[1].firstChild, '.0.$wrap2.$bunny');
checkId(node.childNodes[2], '.0.2');
checkId(node.childNodes[2].firstChild, '.0.2.$chipmunk');
});
function renderAComponentWithKeyIntoContainer(key, container) {
@@ -116,8 +116,10 @@ describe('ReactIdentity', function() {
expect(span1.getDOMNode()).not.toBe(null);
expect(span2.getDOMNode()).not.toBe(null);
checkId(span1.getDOMNode(), '.r[0].{' + key + '}');
checkId(span2.getDOMNode(), '.r[0].[1]{' + key + '}[0]');
key = key.replace(/=/g, '=0');
checkId(span1.getDOMNode(), '.0.$' + key);
checkId(span2.getDOMNode(), '.0.1:$' + key + ':0');
}
it('should allow any character as a key, in a detached parent', function() {
@@ -154,13 +154,25 @@ describe('ReactInstanceHandles', function() {
describe('getReactRootIDFromNodeID', function() {
it('should support strings', function() {
var test = '.r[s_0_1][0]..[1]';
var expected = '.r[s_0_1]';
var test = '.s_0_1.0..1';
var expected = '.s_0_1';
var actual = ReactInstanceHandles.getReactRootIDFromNodeID(test);
expect(actual).toEqual(expected);
});
});
describe('getReactRootIDFromNodeID', function() {
it('should return null for invalid IDs', function() {
var getReactRootIDFromNodeID = (
ReactInstanceHandles.getReactRootIDFromNodeID
);
expect(getReactRootIDFromNodeID(null)).toEqual(null);
expect(getReactRootIDFromNodeID('.')).toEqual(null);
expect(getReactRootIDFromNodeID('#')).toEqual(null);
});
});
describe('traverseTwoPhase', function() {
it("should not traverse when traversing outside DOM", function() {
var targetID = '';
@@ -46,7 +46,9 @@ var stripEmptyValues = function(obj) {
* here. This relies on an implementation detail of the rendering system.
*/
var getOriginalKey = function(childName) {
return childName.slice('{'.length, childName.length - '}[0]'.length);
var match = childName.match(/^\.\$([^.]+)\:0$/);
expect(match).not.toBeNull();
return match[1];
};
/**
+11 -11
View File
@@ -92,7 +92,7 @@ describe('ReactChildren', function() {
expect(mappedKeys.length).toBe(1);
expect(mappedChildren[mappedKeys[0]]).not.toBe(simpleKid);
expect(mappedChildren[mappedKeys[0]].props.children).toBe(simpleKid);
expect(mappedKeys[0]).toBe('{simple}');
expect(mappedKeys[0]).toBe('.$simple');
});
it('should invoke callback with the right context', function() {
@@ -162,7 +162,7 @@ describe('ReactChildren', function() {
expect(mappedKeys.length).toBe(5);
// Keys default to indices.
expect(mappedKeys).toEqual(
['{keyZero}', '[1]', '{keyTwo}', '[3]', '{keyFour}']
['.$keyZero', '.1', '.$keyTwo', '.3', '.$keyFour']
);
expect(callback).toHaveBeenCalledWith(zero, 0);
@@ -235,12 +235,12 @@ describe('ReactChildren', function() {
expect(mappedKeys.length).toBe(6);
// Keys default to indices.
expect(mappedKeys).toEqual([
'[0]{firstHalfKey}[0]{keyZero}',
'[0]{firstHalfKey}[0][1]',
'[0]{firstHalfKey}[0]{keyTwo}',
'[0]{secondHalfKey}[0][0]',
'[0]{secondHalfKey}[0]{keyFour}',
'[0]{keyFive}{keyFiveInner}'
'.0:$firstHalfKey:0:$keyZero',
'.0:$firstHalfKey:0:1',
'.0:$firstHalfKey:0:$keyTwo',
'.0:$secondHalfKey:0:0',
'.0:$secondHalfKey:0:$keyFour',
'.0:$keyFive:$keyFiveInner'
]);
expect(callback).toHaveBeenCalledWith(zero, 0);
@@ -282,15 +282,15 @@ describe('ReactChildren', function() {
</div>
);
var expectedForcedKeys = ['{keyZero}', '{keyOne}'];
var expectedForcedKeys = ['.$keyZero', '.$keyOne'];
var mappedChildrenForcedKeys =
ReactChildren.map(forcedKeys.props.children, mapFn);
var mappedForcedKeys = Object.keys(mappedChildrenForcedKeys);
expect(mappedForcedKeys).toEqual(expectedForcedKeys);
var expectedRemappedForcedKeys = [
'{{keyZero^C}{giraffe}',
'{{keyOne^C}[0]'
'.$=1$keyZero:$giraffe',
'.$=1$keyOne:0'
];
var remappedChildrenForcedKeys =
ReactChildren.map(mappedChildrenForcedKeys, mapFn);
+7 -7
View File
@@ -68,9 +68,9 @@ describe('sliceChildren', function() {
];
var children = renderAndSlice(fullSet, 0);
expect(children).toEqual({
'{A}': fullSet[0],
'{B}': fullSet[1],
'{C}': fullSet[2]
'.$A': fullSet[0],
'.$B': fullSet[1],
'.$C': fullSet[2]
});
});
@@ -82,8 +82,8 @@ describe('sliceChildren', function() {
];
var children = renderAndSlice(fullSet, 1);
expect(children).toEqual({
'{B}': fullSet[1],
'{C}': fullSet[2]
'.$B': fullSet[1],
'.$C': fullSet[2]
});
});
@@ -96,7 +96,7 @@ describe('sliceChildren', function() {
];
var children = renderAndSlice(fullSet, 1, 2);
expect(children).toEqual({
'{B}': fullSet[1]
'.$B': fullSet[1]
});
});
@@ -112,7 +112,7 @@ describe('sliceChildren', function() {
.instance();
expect(rendered.props.children).toEqual({
'[1]': b
'.1': b
});
});
+16 -16
View File
@@ -43,7 +43,7 @@ describe('traverseAllChildren', function() {
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
simpleKid,
'{simple}',
'.$simple',
0
);
expect(traverseContext.length).toEqual(1);
@@ -62,7 +62,7 @@ describe('traverseAllChildren', function() {
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
simpleKid,
'[0]',
'.0',
0
);
expect(traverseContext.length).toEqual(1);
@@ -81,7 +81,7 @@ describe('traverseAllChildren', function() {
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
simpleKid,
'[0]',
'.0',
0
);
expect(traverseContext.length).toEqual(1);
@@ -114,21 +114,21 @@ describe('traverseAllChildren', function() {
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
zero,
'{keyZero}',
'.$keyZero',
0
);
expect(traverseFn).toHaveBeenCalledWith(traverseContext, one, '[1]', 1);
expect(traverseFn).toHaveBeenCalledWith(traverseContext, one, '.1', 1);
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
two,
'{keyTwo}',
'.$keyTwo',
2
);
expect(traverseFn).toHaveBeenCalledWith(traverseContext, three, '[3]', 3);
expect(traverseFn).toHaveBeenCalledWith(traverseContext, three, '.3', 3);
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
four,
'{keyFour}',
'.$keyFour',
4
);
});
@@ -171,38 +171,38 @@ describe('traverseAllChildren', function() {
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
zero,
'[0]{firstHalfKey}[0]{keyZero}',
'.0:$firstHalfKey:0:$keyZero',
0
);
expect(traverseFn)
.toHaveBeenCalledWith(traverseContext, one, '[0]{firstHalfKey}[0][1]', 1);
.toHaveBeenCalledWith(traverseContext, one, '.0:$firstHalfKey:0:1', 1);
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
two,
'[0]{firstHalfKey}[0]{keyTwo}',
'.0:$firstHalfKey:0:$keyTwo',
2
);
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
three,
'[0]{secondHalfKey}[0][0]',
'.0:$secondHalfKey:0:0',
3
);
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
four,
'[0]{secondHalfKey}[0]{keyFour}',
'.0:$secondHalfKey:0:$keyFour',
4
);
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
five,
'[0]{keyFive}{keyFiveInner}',
'.0:$keyFive:$keyFiveInner',
5
);
});
@@ -228,13 +228,13 @@ describe('traverseAllChildren', function() {
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
zeroForceKey,
'{keyZero}',
'.$keyZero',
0
);
expect(traverseFn).toHaveBeenCalledWith(
traverseContext,
oneForceKey,
'{keyOne}',
'.$keyOne',
1
);
});
+20 -11
View File
@@ -18,10 +18,14 @@
"use strict";
var ReactInstanceHandles = require('ReactInstanceHandles');
var ReactTextComponent = require('ReactTextComponent');
var invariant = require('invariant');
var SEPARATOR = ReactInstanceHandles.SEPARATOR;
var SUBSEPARATOR = ':';
/**
* TODO: Test that:
* 1. `mapChildren` transforms strings and numbers into `ReactTextComponent`.
@@ -31,12 +35,12 @@ var invariant = require('invariant');
*/
var userProvidedKeyEscaperLookup = {
'^': '^X',
'.': '^D',
'}': '^C'
'=': '=0',
'.': '=1',
':': '=2'
};
var userProvidedKeyEscapeRegex = /[.^}]/g;
var userProvidedKeyEscapeRegex = /[=.:]/g;
function userProvidedKeyEscaper(match) {
return userProvidedKeyEscaperLookup[match];
@@ -55,7 +59,7 @@ function getComponentKey(component, index) {
return wrapUserProvidedKey(component.props.key);
}
// Implicit key determined by the index in the set
return '[' + index + ']';
return index.toString(36);
}
/**
@@ -79,7 +83,7 @@ function escapeUserProvidedKey(text) {
* @return {string}
*/
function wrapUserProvidedKey(key) {
return '{' + escapeUserProvidedKey(key) + '}';
return '$' + escapeUserProvidedKey(key);
}
/**
@@ -97,7 +101,11 @@ var traverseAllChildrenImpl =
if (Array.isArray(children)) {
for (var i = 0; i < children.length; i++) {
var child = children[i];
var nextName = nameSoFar + getComponentKey(child, i);
var nextName = (
nameSoFar +
(nameSoFar ? SUBSEPARATOR : SEPARATOR) +
getComponentKey(child, i)
);
var nextIndex = indexSoFar + subtreeCount;
subtreeCount += traverseAllChildrenImpl(
child,
@@ -112,8 +120,9 @@ var traverseAllChildrenImpl =
var isOnlyChild = nameSoFar === '';
// If it's the only child, treat the name as if it was wrapped in an array
// so that it's consistent if the number of children grows
var storageName = isOnlyChild ? getComponentKey(children, 0) : nameSoFar;
if (children === null || children === undefined || type === 'boolean') {
var storageName =
isOnlyChild ? SEPARATOR + getComponentKey(children, 0) : nameSoFar;
if (children == null || type === 'boolean') {
// All of the above are perceived as null.
callback(traverseContext, null, storageName, indexSoFar);
subtreeCount = 1;
@@ -132,8 +141,8 @@ var traverseAllChildrenImpl =
subtreeCount += traverseAllChildrenImpl(
children[key],
(
nameSoFar +
wrapUserProvidedKey(key) +
nameSoFar + (nameSoFar ? SUBSEPARATOR : SEPARATOR) +
wrapUserProvidedKey(key) + SUBSEPARATOR +
getComponentKey(children[key], 0)
),
indexSoFar + subtreeCount,