diff --git a/src/core/ReactDefaultInjection.js b/src/core/ReactDefaultInjection.js index 27fb2afba0..d67203aef8 100644 --- a/src/core/ReactDefaultInjection.js +++ b/src/core/ReactDefaultInjection.js @@ -45,14 +45,15 @@ function inject() { 'TextChangeEventPlugin': TextChangeEventPlugin }); - /* - * This is a bit of a hack. We need to override the
element - * to be a composite component because IE8 does not bubble or capture - * submit to the top level. In order to make this work with our - * dependency graph we need to inject it here. + /** + * This is a bit of a hack. We need to override the element to be a + * composite component because IE8 does not bubble or capture submit to the + * top level. In order to make this work with our dependency graph we need to + * inject it here. */ ReactDOM.injection.injectComponentClasses({ form: ReactDOMForm + // TODO: Inject `ReactDOMInput`. }); } diff --git a/src/core/ReactDOMForm.js b/src/dom/components/ReactDOMForm.js similarity index 100% rename from src/core/ReactDOMForm.js rename to src/dom/components/ReactDOMForm.js diff --git a/src/dom/components/ReactDOMInput.js b/src/dom/components/ReactDOMInput.js new file mode 100644 index 0000000000..9a0ca10160 --- /dev/null +++ b/src/dom/components/ReactDOMInput.js @@ -0,0 +1,123 @@ +/** + * 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. + * + * @providesModule ReactDOMInput + */ + +"use strict"; + +var DOMPropertyOperations = require('DOMPropertyOperations'); +var ReactCompositeComponent = require('ReactCompositeComponent'); +var ReactDOM = require('ReactDOM'); + +var merge = require('merge'); + +// Store a reference to the `ReactNativeComponent`. +var input = ReactDOM.input; + +/** + * Implements an native component that allows setting these optional + * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. + * + * If `checked` or `value` are not supplied (or null/undefined), user actions + * that affect the checked state or value will trigger updates to the element. + * + * If they are supplied (and not null/undefined), the rendered element will not + * trigger updates to the element. Instead, the props must change in order for + * the rendered element to be updated. + * + * The rendered element will be initialized as unchecked (or `defaultChecked`) + * with an empty value (or `defaultValue`). + * + * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html + */ +var ReactDOMInput = ReactCompositeComponent.createClass({ + + getInitialState: function() { + return { + checked: this.props.defaultChecked || false, + value: this.props.defaultValue || '' + }; + }, + + getChecked: function() { + return this.props.checked != null ? this.props.checked : this.state.checked; + }, + + getValue: function() { + return this.props.value != null ? this.props.value : this.state.value; + }, + + render: function() { + // Clone `this.props` so we don't mutate the input. + var props = merge(this.props); + + props.checked = this.getChecked(); + props.value = this.getValue(); + + // TODO: Re-implement `onChange` with the implementation of `onTextChange`. + if (props.type === 'text' || props.type === 'password') { + props.onTextChange = this.handleTextChange; + } else { + props.onChange = this.handleChange; + } + + return input(props, this.props.children); + }, + + componentDidUpdate: function(prevProps, prevState, rootNode) { + if (this.props.checked != null) { + DOMPropertyOperations.setValueForProperty( + rootNode, + 'checked', + this.props.checked || false + ); + } + if (this.props.value != null) { + DOMPropertyOperations.setValueForProperty( + rootNode, + 'value', + this.props.value || '' + ); + } + }, + + handleTextChange: ReactCompositeComponent.autoBind(function(event) { + var returnValue; + if (this.props.onTextChange) { + returnValue = this.props.onTextChange(event); + } + this.setState({ + checked: event.target.checked, + value: event.target.value + }); + return returnValue; + }), + + handleChange: ReactCompositeComponent.autoBind(function(event) { + var returnValue; + if (this.props.onChange) { + returnValue = this.props.onChange(event); + } + this.setState({ + checked: event.target.checked, + value: event.target.value + }); + return returnValue; + }) + +}); + +module.exports = ReactDOMInput;