mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge branch 'SanderSpies-sspi-dom-attribute-process'
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -105,13 +103,9 @@ var ReactDOMInput = ReactCompositeComponent.createClass({
|
||||
|
||||
var value = this.getValue();
|
||||
if (value != null) {
|
||||
// Cast `this.props.value` to a string so falsey values that cast to
|
||||
// truthy strings are not ignored.
|
||||
DOMPropertyOperations.setValueForProperty(
|
||||
rootNode,
|
||||
'value',
|
||||
value !== false ? '' + value : ''
|
||||
);
|
||||
// Cast `value` to a string to ensure the value is set correctly. While
|
||||
// browsers typically do this as necessary, jsdom doesn't.
|
||||
DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -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,7 @@ 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) {
|
||||
@@ -86,7 +79,9 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({
|
||||
return {
|
||||
// We save the initial value so that `ReactDOMComponent` doesn't update
|
||||
// `textContent` (unnecessary since we update value).
|
||||
initialValue: value != null ? value : defaultValue,
|
||||
// The initial value can be a boolean or object so that's why it's
|
||||
// forced to be a string.
|
||||
initialValue: '' + (value != null ? value : defaultValue),
|
||||
value: defaultValue
|
||||
};
|
||||
},
|
||||
@@ -118,11 +113,9 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({
|
||||
componentDidUpdate: function(prevProps, prevState, rootNode) {
|
||||
var value = this.getValue();
|
||||
if (value != null) {
|
||||
DOMPropertyOperations.setValueForProperty(
|
||||
rootNode,
|
||||
'value',
|
||||
value !== false ? '' + value : ''
|
||||
);
|
||||
// Cast `value` to a string to ensure the value is set correctly. While
|
||||
// browsers typically do this as necessary, jsdom doesn't.
|
||||
DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -50,11 +50,31 @@ describe('ReactDOMInput', function() {
|
||||
expect(node.value).toBe('0');
|
||||
});
|
||||
|
||||
it('should display "" for `defaultValue` of `false`', function() {
|
||||
it('should display "true" for `defaultValue` of `true`', function() {
|
||||
var stub = <input type="text" defaultValue={true} />;
|
||||
var node = renderTextInput(stub);
|
||||
|
||||
expect(node.value).toBe('true');
|
||||
});
|
||||
|
||||
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 "foobar" for `defaultValue` of `objToString`', function() {
|
||||
var objToString = {
|
||||
toString: function() {
|
||||
return "foobar";
|
||||
}
|
||||
};
|
||||
|
||||
var stub = <input type="text" defaultValue={objToString} />;
|
||||
var node = renderTextInput(stub);
|
||||
|
||||
expect(node.value).toBe('foobar');
|
||||
});
|
||||
|
||||
it('should display `value` of number 0', function() {
|
||||
@@ -64,11 +84,40 @@ describe('ReactDOMInput', function() {
|
||||
expect(node.value).toBe('0');
|
||||
});
|
||||
|
||||
it('should display "" for `value` of `false`', function() {
|
||||
var stub = <input type="text" value={false} />;
|
||||
it('should allow setting `value` to `true`', function() {
|
||||
var stub = <input type="text" value="yolo" />;
|
||||
var node = renderTextInput(stub);
|
||||
|
||||
expect(node.value).toBe('');
|
||||
expect(node.value).toBe('yolo');
|
||||
|
||||
stub.replaceProps({value: true});
|
||||
expect(node.value).toEqual('true');
|
||||
});
|
||||
|
||||
it("should allow setting `value` to `false`", function() {
|
||||
var stub = <input type="text" value="yolo" />;
|
||||
var node = renderTextInput(stub);
|
||||
|
||||
expect(node.value).toBe('yolo');
|
||||
|
||||
stub.replaceProps({value: false});
|
||||
expect(node.value).toEqual('false');
|
||||
});
|
||||
|
||||
it('should allow setting `value` to `objToString`', function() {
|
||||
var stub = <input type="text" value="foo" />;
|
||||
var node = renderTextInput(stub);
|
||||
|
||||
expect(node.value).toBe('foo');
|
||||
|
||||
var objToString = {
|
||||
toString: function() {
|
||||
return "foobar";
|
||||
}
|
||||
};
|
||||
|
||||
stub.replaceProps({value: objToString});
|
||||
expect(node.value).toEqual('foobar');
|
||||
});
|
||||
|
||||
it('should properly control a value of number `0`', function() {
|
||||
|
||||
@@ -116,6 +116,35 @@ describe('ReactDOMSelect', function() {
|
||||
expect(node.options[2].selected).toBe(false); // gorilla
|
||||
});
|
||||
|
||||
it('should allow setting `value` with `objectToString`', function() {
|
||||
var objectToString = {
|
||||
animal: "giraffe",
|
||||
toString: function() {
|
||||
return this.animal;
|
||||
}
|
||||
};
|
||||
|
||||
var stub =
|
||||
<select multiple={true} value={[objectToString]}>
|
||||
<option value="monkey">A monkey!</option>
|
||||
<option value="giraffe">A giraffe!</option>
|
||||
<option value="gorilla">A gorilla!</option>
|
||||
</select>;
|
||||
var node = renderSelect(stub);
|
||||
|
||||
expect(node.options[0].selected).toBe(false); // monkey
|
||||
expect(node.options[1].selected).toBe(true); // giraffe
|
||||
expect(node.options[2].selected).toBe(false); // gorilla
|
||||
|
||||
// Changing the `value` prop should change the selected options.
|
||||
objectToString.animal = "monkey";
|
||||
stub.forceUpdate();
|
||||
|
||||
expect(node.options[0].selected).toBe(true); // monkey
|
||||
expect(node.options[1].selected).toBe(false); // giraffe
|
||||
expect(node.options[2].selected).toBe(false); // gorilla
|
||||
});
|
||||
|
||||
it('should allow switching to multiple', function() {
|
||||
var stub =
|
||||
<select defaultValue="giraffe">
|
||||
|
||||
@@ -62,21 +62,24 @@ 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 allow setting `value`', function() {
|
||||
var stub = <textarea value="giraffe" />;
|
||||
it('should display "foobar" for `defaultValue` of `objToString`', function() {
|
||||
var objToString = {
|
||||
toString: function() {
|
||||
return "foobar";
|
||||
}
|
||||
};
|
||||
|
||||
var stub = <textarea type="text" defaultValue={objToString} />;
|
||||
var node = renderTextarea(stub);
|
||||
|
||||
expect(node.value).toBe('giraffe');
|
||||
|
||||
stub.replaceProps({value: 'gorilla'});
|
||||
expect(node.value).toEqual('gorilla');
|
||||
expect(node.value).toBe('foobar');
|
||||
});
|
||||
|
||||
it('should display `value` of number 0', function() {
|
||||
@@ -86,11 +89,49 @@ describe('ReactDOMTextarea', function() {
|
||||
expect(node.value).toBe('0');
|
||||
});
|
||||
|
||||
it('should display "" for `value` of `false`', function() {
|
||||
var stub = <textarea type="text" value={false} />;
|
||||
it('should allow setting `value` to `giraffe`', function() {
|
||||
var stub = <textarea value="giraffe" />;
|
||||
var node = renderTextarea(stub);
|
||||
|
||||
expect(node.value).toBe('');
|
||||
expect(node.value).toBe('giraffe');
|
||||
|
||||
stub.replaceProps({value: 'gorilla'});
|
||||
expect(node.value).toEqual('gorilla');
|
||||
});
|
||||
|
||||
it('should allow setting `value` to `true`', function() {
|
||||
var stub = <textarea value="giraffe" />;
|
||||
var node = renderTextarea(stub);
|
||||
|
||||
expect(node.value).toBe('giraffe');
|
||||
|
||||
stub.replaceProps({value: true});
|
||||
expect(node.value).toEqual('true');
|
||||
});
|
||||
|
||||
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 `objToString`', function() {
|
||||
var stub = <textarea value="giraffe" />;
|
||||
var node = renderTextarea(stub);
|
||||
|
||||
expect(node.value).toBe('giraffe');
|
||||
|
||||
var objToString = {
|
||||
toString: function() {
|
||||
return "foo";
|
||||
}
|
||||
};
|
||||
stub.replaceProps({value: objToString});
|
||||
expect(node.value).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should properly control a value of number `0`', function() {
|
||||
@@ -123,6 +164,25 @@ 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 "sharkswithlasers";
|
||||
}
|
||||
};
|
||||
var node = renderTextarea(<textarea>{obj}</textarea>);
|
||||
expect(console.warn.argsForCall.length).toBe(1);
|
||||
expect(node.value).toBe('sharkswithlasers');
|
||||
});
|
||||
|
||||
it('should throw with multiple or invalid children', function() {
|
||||
spyOn(console, 'warn');
|
||||
|
||||
@@ -134,11 +194,12 @@ describe('ReactDOMTextarea', function() {
|
||||
|
||||
expect(console.warn.argsForCall.length).toBe(1);
|
||||
|
||||
var stub;
|
||||
expect(function() {
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<textarea><strong /></textarea>
|
||||
);
|
||||
}).toThrow();
|
||||
stub = renderTextarea(<textarea><strong /></textarea>);
|
||||
}).not.toThrow();
|
||||
|
||||
expect(stub.value).toBe('[object Object]');
|
||||
|
||||
expect(console.warn.argsForCall.length).toBe(2);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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 = require('escapeTextForBrowser');
|
||||
|
||||
it('should escape boolean to string', function() {
|
||||
expect(escapeTextForBrowser(true)).toBe('true');
|
||||
expect(escapeTextForBrowser(false)).toBe('false');
|
||||
});
|
||||
|
||||
it('should escape object to string', function() {
|
||||
var escaped = escapeTextForBrowser({
|
||||
toString: function() {
|
||||
return 'ponys';
|
||||
}
|
||||
});
|
||||
|
||||
expect(escaped).toBe('ponys');
|
||||
});
|
||||
|
||||
it('should escape number to string', function() {
|
||||
expect(escapeTextForBrowser(42)).toBe('42');
|
||||
});
|
||||
|
||||
it('should escape string', function() {
|
||||
var escaped = escapeTextForBrowser('<script type=\'\' src=""></script>');
|
||||
expect(escaped).not.toContain('<');
|
||||
expect(escaped).not.toContain('>');
|
||||
expect(escaped).not.toContain('\'');
|
||||
expect(escaped).not.toContain('/');
|
||||
expect(escaped).not.toContain('\"');
|
||||
|
||||
escaped = escapeTextForBrowser('&');
|
||||
expect(escaped).toBe('&');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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,24 +37,11 @@ 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);
|
||||
}
|
||||
}
|
||||
return ('' + text).replace(ESCAPE_REGEX, escaper);
|
||||
}
|
||||
|
||||
module.exports = escapeTextForBrowser;
|
||||
|
||||
Reference in New Issue
Block a user