Created
October 3, 2013 18:10
-
-
Save zpao/6814295 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 9e2d6e904015bb1c31af23190ebc05a41cbe21c6 | |
Author: Paul O’Shannessy <[email protected]> | |
Date: Thu Oct 3 11:05:42 2013 -0700 | |
yup | |
diff --git a/src/dom/components/ReactDOMInput.js b/src/dom/components/ReactDOMInput.js | |
index a569a5e..cfd4982 100644 | |
--- a/src/dom/components/ReactDOMInput.js | |
+++ b/src/dom/components/ReactDOMInput.js | |
@@ -55,7 +55,7 @@ var ReactDOMInput = ReactCompositeComponent.createClass({ | |
var defaultValue = this.props.defaultValue; | |
return { | |
checked: this.props.defaultChecked || false, | |
- value: defaultValue != null && defaultValue !== false ? defaultValue : '' | |
+ value: defaultValue != null ? defaultValue : '' | |
}; | |
}, | |
@@ -74,9 +74,7 @@ var ReactDOMInput = ReactCompositeComponent.createClass({ | |
this.props.checked != null ? this.props.checked : this.state.checked; | |
var value = this.getValue(); | |
- props.value = value != null && value !== false ? | |
- '' + value : | |
- this.state.value; | |
+ props.value = value != null ? value : this.state.value; | |
props.onChange = this._handleChange; | |
diff --git a/src/dom/components/ReactDOMTextarea.js b/src/dom/components/ReactDOMTextarea.js | |
index 0aed044..5cd84de 100644 | |
--- a/src/dom/components/ReactDOMTextarea.js | |
+++ b/src/dom/components/ReactDOMTextarea.js | |
@@ -29,9 +29,6 @@ var merge = require('merge'); | |
// Store a reference to the <textarea> `ReactDOMComponent`. | |
var textarea = ReactDOM.textarea; | |
-// For quickly matching children type, to test if can be treated as content. | |
-var CONTENT_TYPES = {'string': true, 'number': true}; | |
- | |
/** | |
* Implements a <textarea> native component that allows setting `value`, and | |
* `defaultValue`. This differs from the traditional DOM API because value is | |
@@ -72,11 +69,6 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({ | |
); | |
children = children[0]; | |
} | |
- invariant( | |
- CONTENT_TYPES[typeof children], | |
- 'If you specify children to <textarea>, it must be a single string ' + | |
- 'or number., not an array or object.' | |
- ); | |
defaultValue = '' + children; | |
} | |
if (defaultValue == null) { | |
@@ -85,8 +77,10 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({ | |
var value = this.getValue(); | |
return { | |
// We save the initial value so that `ReactDOMComponent` doesn't update | |
- // `textContent` (unnecessary since we update value). | |
- initialValue: value != null ? value : defaultValue, | |
+ // `textContent` (unnecessary since we update value). We need to ensure | |
+ // that this value is a string since it will be used as a child of the | |
+ // <textarea>. | |
+ initialValue: '' + (value != null ? value : defaultValue), | |
value: defaultValue | |
}; | |
}, | |
@@ -121,7 +115,7 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({ | |
DOMPropertyOperations.setValueForProperty( | |
rootNode, | |
'value', | |
- value !== false ? '' + value : '' | |
+ value | |
); | |
} | |
}, | |
diff --git a/src/dom/components/__tests__/ReactDOMInput-test.js b/src/dom/components/__tests__/ReactDOMInput-test.js | |
index 61cf2f3..c6415da 100644 | |
--- a/src/dom/components/__tests__/ReactDOMInput-test.js | |
+++ b/src/dom/components/__tests__/ReactDOMInput-test.js | |
@@ -50,11 +50,11 @@ describe('ReactDOMInput', function() { | |
expect(node.value).toBe('0'); | |
}); | |
- it('should display "" for `defaultValue` of `false`', function() { | |
+ it('should display "false" for `defaultValue` of `false`', function() { | |
var stub = <input type="text" defaultValue={false} />; | |
var node = renderTextInput(stub); | |
- expect(node.value).toBe(''); | |
+ expect(node.value).toBe('false'); | |
}); | |
it('should display `value` of number 0', function() { | |
@@ -64,11 +64,11 @@ describe('ReactDOMInput', function() { | |
expect(node.value).toBe('0'); | |
}); | |
- it('should display "" for `value` of `false`', function() { | |
+ it('should display "false" for `value` of `false`', function() { | |
var stub = <input type="text" value={false} />; | |
var node = renderTextInput(stub); | |
- expect(node.value).toBe(''); | |
+ expect(node.value).toBe('false'); | |
}); | |
it('should properly control a value of number `0`', function() { | |
diff --git a/src/dom/components/__tests__/ReactDOMTextarea-test.js b/src/dom/components/__tests__/ReactDOMTextarea-test.js | |
index a0fd263..0fbc4ee 100644 | |
--- a/src/dom/components/__tests__/ReactDOMTextarea-test.js | |
+++ b/src/dom/components/__tests__/ReactDOMTextarea-test.js | |
@@ -62,11 +62,19 @@ describe('ReactDOMTextarea', function() { | |
expect(node.value).toBe('0'); | |
}); | |
- it('should display "" for `defaultValue` of `false`', function() { | |
+ it('should display "false" for `defaultValue` of `false`', function() { | |
var stub = <textarea type="text" defaultValue={false} />; | |
var node = renderTextarea(stub); | |
- expect(node.value).toBe(''); | |
+ expect(node.value).toBe('false'); | |
+ }); | |
+ | |
+ it('should display toString for `defaultValue` of object', function() { | |
+ var obj = { toString: function() { return 'hello'; } }; | |
+ var stub = <textarea type="text" defaultValue={obj} />; | |
+ var node = renderTextarea(stub); | |
+ | |
+ expect(node.value).toBe('hello'); | |
}); | |
it('should allow setting `value`', function() { | |
@@ -79,6 +87,27 @@ describe('ReactDOMTextarea', function() { | |
expect(node.value).toEqual('gorilla'); | |
}); | |
+ it('should allow setting `value` to `false`', function() { | |
+ var stub = <textarea value="giraffe" />; | |
+ var node = renderTextarea(stub); | |
+ | |
+ expect(node.value).toBe('giraffe'); | |
+ | |
+ stub.replaceProps({value: false}); | |
+ expect(node.value).toEqual('false'); | |
+ }); | |
+ | |
+ it('should allow setting `value` to object', function() { | |
+ var obj = { toString: function() { return 'hello'; } }; | |
+ var stub = <textarea value="giraffe" />; | |
+ var node = renderTextarea(stub); | |
+ | |
+ expect(node.value).toBe('giraffe'); | |
+ | |
+ stub.replaceProps({value: obj}); | |
+ expect(node.value).toBe('hello'); | |
+ }); | |
+ | |
it('should display `value` of number 0', function() { | |
var stub = <textarea value={0} />; | |
var node = renderTextarea(stub); | |
@@ -86,11 +115,11 @@ describe('ReactDOMTextarea', function() { | |
expect(node.value).toBe('0'); | |
}); | |
- it('should display "" for `value` of `false`', function() { | |
+ it('should display "false" for `value` of `false`', function() { | |
var stub = <textarea type="text" value={false} />; | |
var node = renderTextarea(stub); | |
- expect(node.value).toBe(''); | |
+ expect(node.value).toBe('false'); | |
}); | |
it('should properly control a value of number `0`', function() { | |
@@ -123,6 +152,21 @@ describe('ReactDOMTextarea', function() { | |
expect(node.value).toBe('17'); | |
}); | |
+ it('should allow booleans as children', function() { | |
+ spyOn(console, 'warn'); | |
+ var node = renderTextarea(<textarea>{false}</textarea>); | |
+ expect(console.warn.argsForCall.length).toBe(1); | |
+ expect(node.value).toBe('false'); | |
+ }); | |
+ | |
+ it('should allow objects as children', function() { | |
+ spyOn(console, 'warn'); | |
+ var obj = { toString: function() { return 'hello'; } }; | |
+ var node = renderTextarea(<textarea>{obj}</textarea>); | |
+ expect(console.warn.argsForCall.length).toBe(1); | |
+ expect(node.value).toBe('hello'); | |
+ }); | |
+ | |
it('should throw with multiple or invalid children', function() { | |
spyOn(console, 'warn'); | |
@@ -134,13 +178,16 @@ describe('ReactDOMTextarea', function() { | |
expect(console.warn.argsForCall.length).toBe(1); | |
+ var node; | |
expect(function() { | |
- ReactTestUtils.renderIntoDocument( | |
+ node = renderTextarea( | |
<textarea><strong /></textarea> | |
); | |
- }).toThrow(); | |
+ }).not.toThrow(); | |
+ // Should still warn about using defaultValue/value | |
expect(console.warn.argsForCall.length).toBe(2); | |
+ expect(node.value).toBe('[object Object]'); | |
}); | |
it('should support ReactLink', function() { | |
diff --git a/src/utils/__tests__/escapeTextForBrowser-test.js b/src/utils/__tests__/escapeTextForBrowser-test.js | |
new file mode 100644 | |
index 0000000..e6ccdfd | |
--- /dev/null | |
+++ b/src/utils/__tests__/escapeTextForBrowser-test.js | |
@@ -0,0 +1,68 @@ | |
+/** | |
+ * Copyright 2013 Facebook, Inc. | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ * | |
+ * @emails react-core | |
+ */ | |
+ | |
+"use strict"; | |
+ | |
+describe('escapeTextForBrowser', function() { | |
+ var escapeTextForBrowser; | |
+ | |
+ beforeEach(function() { | |
+ escapeTextForBrowser = require('escapeTextForBrowser'); | |
+ }); | |
+ | |
+ it('should convert numbers to strings', function() { | |
+ expect(escapeTextForBrowser(4)).toBe('4'); | |
+ expect(escapeTextForBrowser(1.01)).toBe('1.01'); | |
+ }); | |
+ | |
+ it('should convert booleans to strings', function() { | |
+ expect(escapeTextForBrowser(true)).toBe('true'); | |
+ expect(escapeTextForBrowser(false)).toBe('false'); | |
+ }); | |
+ | |
+ it('should convert Arrays to strings', function() { | |
+ var arr = [1, 2, 'foo']; | |
+ expect(escapeTextForBrowser(arr)).toBe('1,2,foo'); | |
+ }); | |
+ | |
+ it('should convert simple objects without toString to strings', function() { | |
+ var obj = {}; | |
+ expect(escapeTextForBrowser(obj)).toBe('[object Object]'); | |
+ }); | |
+ | |
+ it('should convert simple objects to strings', function() { | |
+ var obj = { toString: function() { return 'hello'; } }; | |
+ expect(escapeTextForBrowser(obj)).toBe('hello'); | |
+ }); | |
+ | |
+ it('should convert objects with inheritance to strings', function() { | |
+ var Obj = function() {}; | |
+ Obj.prototype.toString = function() { return 'goodbye'; }; | |
+ expect(escapeTextForBrowser(new Obj())).toBe('goodbye'); | |
+ }); | |
+ | |
+ it('should convert escape special characters in strings', function() { | |
+ expect(escapeTextForBrowser('harold & maude')).toBe('harold & maude'); | |
+ }); | |
+ | |
+ it('should convert escape special characters in objects', function() { | |
+ var obj = { toString: function() { return '"real" talk'; } }; | |
+ expect(escapeTextForBrowser(obj)).toBe('"real" talk'); | |
+ }); | |
+}); | |
+ | |
diff --git a/src/utils/escapeTextForBrowser.js b/src/utils/escapeTextForBrowser.js | |
index 8e49d31..4198b9f 100644 | |
--- a/src/utils/escapeTextForBrowser.js | |
+++ b/src/utils/escapeTextForBrowser.js | |
@@ -19,8 +19,6 @@ | |
"use strict"; | |
-var invariant = require('invariant'); | |
- | |
var ESCAPE_LOOKUP = { | |
"&": "&", | |
">": ">", | |
@@ -30,6 +28,8 @@ var ESCAPE_LOOKUP = { | |
"/": "/" | |
}; | |
+var ESCAPE_REGEX = /[&><"'\/]/g; | |
+ | |
function escaper(match) { | |
return ESCAPE_LOOKUP[match]; | |
} | |
@@ -37,23 +37,16 @@ function escaper(match) { | |
/** | |
* Escapes text to prevent scripting attacks. | |
* | |
- * @param {number|string} text Text value to escape. | |
+ * @param {*} text Text value to escape. | |
* @return {string} An escaped string. | |
*/ | |
function escapeTextForBrowser(text) { | |
- var type = typeof text; | |
- invariant( | |
- type !== 'object', | |
- 'escapeTextForBrowser(...): Attempted to escape an object.' | |
- ); | |
if (text === '') { | |
return ''; | |
} else { | |
- if (type === 'string') { | |
- return text.replace(/[&><"'\/]/g, escaper); | |
- } else { | |
- return (''+text).replace(/[&><"'\/]/g, escaper); | |
- } | |
+ // Make sure text is in fact a string. This will call toString on other | |
+ // types (e.g. booleans, objects). | |
+ return ('' + text).replace(ESCAPE_REGEX, escaper); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment