react / react-0.13.3 / examples / basic-commonjs / node_modules / reactify / node_modules / react-tools / src / browser / ui / dom / components / ReactDOMInput.js
81165 views/**1* Copyright 2013-2014, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under the BSD-style license found in the5* LICENSE file in the root directory of this source tree. An additional grant6* of patent rights can be found in the PATENTS file in the same directory.7*8* @providesModule ReactDOMInput9*/1011"use strict";1213var AutoFocusMixin = require('AutoFocusMixin');14var DOMPropertyOperations = require('DOMPropertyOperations');15var LinkedValueUtils = require('LinkedValueUtils');16var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');17var ReactCompositeComponent = require('ReactCompositeComponent');18var ReactElement = require('ReactElement');19var ReactDOM = require('ReactDOM');20var ReactMount = require('ReactMount');21var ReactUpdates = require('ReactUpdates');2223var assign = require('Object.assign');24var invariant = require('invariant');2526// Store a reference to the <input> `ReactDOMComponent`. TODO: use string27var input = ReactElement.createFactory(ReactDOM.input.type);2829var instancesByReactID = {};3031function forceUpdateIfMounted() {32/*jshint validthis:true */33if (this.isMounted()) {34this.forceUpdate();35}36}3738/**39* Implements an <input> native component that allows setting these optional40* props: `checked`, `value`, `defaultChecked`, and `defaultValue`.41*42* If `checked` or `value` are not supplied (or null/undefined), user actions43* that affect the checked state or value will trigger updates to the element.44*45* If they are supplied (and not null/undefined), the rendered element will not46* trigger updates to the element. Instead, the props must change in order for47* the rendered element to be updated.48*49* The rendered element will be initialized as unchecked (or `defaultChecked`)50* with an empty value (or `defaultValue`).51*52* @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html53*/54var ReactDOMInput = ReactCompositeComponent.createClass({55displayName: 'ReactDOMInput',5657mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],5859getInitialState: function() {60var defaultValue = this.props.defaultValue;61return {62initialChecked: this.props.defaultChecked || false,63initialValue: defaultValue != null ? defaultValue : null64};65},6667render: function() {68// Clone `this.props` so we don't mutate the input.69var props = assign({}, this.props);7071props.defaultChecked = null;72props.defaultValue = null;7374var value = LinkedValueUtils.getValue(this);75props.value = value != null ? value : this.state.initialValue;7677var checked = LinkedValueUtils.getChecked(this);78props.checked = checked != null ? checked : this.state.initialChecked;7980props.onChange = this._handleChange;8182return input(props, this.props.children);83},8485componentDidMount: function() {86var id = ReactMount.getID(this.getDOMNode());87instancesByReactID[id] = this;88},8990componentWillUnmount: function() {91var rootNode = this.getDOMNode();92var id = ReactMount.getID(rootNode);93delete instancesByReactID[id];94},9596componentDidUpdate: function(prevProps, prevState, prevContext) {97var rootNode = this.getDOMNode();98if (this.props.checked != null) {99DOMPropertyOperations.setValueForProperty(100rootNode,101'checked',102this.props.checked || false103);104}105106var value = LinkedValueUtils.getValue(this);107if (value != null) {108// Cast `value` to a string to ensure the value is set correctly. While109// browsers typically do this as necessary, jsdom doesn't.110DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);111}112},113114_handleChange: function(event) {115var returnValue;116var onChange = LinkedValueUtils.getOnChange(this);117if (onChange) {118returnValue = onChange.call(this, event);119}120// Here we use asap to wait until all updates have propagated, which121// is important when using controlled components within layers:122// https://github.com/facebook/react/issues/1698123ReactUpdates.asap(forceUpdateIfMounted, this);124125var name = this.props.name;126if (this.props.type === 'radio' && name != null) {127var rootNode = this.getDOMNode();128var queryRoot = rootNode;129130while (queryRoot.parentNode) {131queryRoot = queryRoot.parentNode;132}133134// If `rootNode.form` was non-null, then we could try `form.elements`,135// but that sometimes behaves strangely in IE8. We could also try using136// `form.getElementsByName`, but that will only return direct children137// and won't include inputs that use the HTML5 `form=` attribute. Since138// the input might not even be in a form, let's just use the global139// `querySelectorAll` to ensure we don't miss anything.140var group = queryRoot.querySelectorAll(141'input[name=' + JSON.stringify('' + name) + '][type="radio"]');142143for (var i = 0, groupLen = group.length; i < groupLen; i++) {144var otherNode = group[i];145if (otherNode === rootNode ||146otherNode.form !== rootNode.form) {147continue;148}149var otherID = ReactMount.getID(otherNode);150invariant(151otherID,152'ReactDOMInput: Mixing React and non-React radio inputs with the ' +153'same `name` is not supported.'154);155var otherInstance = instancesByReactID[otherID];156invariant(157otherInstance,158'ReactDOMInput: Unknown radio button ID %s.',159otherID160);161// If this is a controlled radio button group, forcing the input that162// was previously checked to update will cause it to be come re-checked163// as appropriate.164ReactUpdates.asap(forceUpdateIfMounted, otherInstance);165}166}167168return returnValue;169}170171});172173module.exports = ReactDOMInput;174175176