diff --git a/src/addons/link/ReactLink.js b/src/addons/link/ReactLink.js index 297baad345b4b..9611a21674827 100644 --- a/src/addons/link/ReactLink.js +++ b/src/addons/link/ReactLink.js @@ -39,7 +39,7 @@ * }); * * We have provided some sugary mixins to make the creation and - * consumption of ReactLink easier; see LinkedValueMixin and LinkedStateMixin. + * consumption of ReactLink easier; see LinkedValueUtils and LinkedStateMixin. */ /** diff --git a/src/dom/components/LinkedValueMixin.js b/src/dom/components/LinkedValueMixin.js deleted file mode 100644 index c054a38288297..0000000000000 --- a/src/dom/components/LinkedValueMixin.js +++ /dev/null @@ -1,93 +0,0 @@ -/** - * 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 LinkedValueMixin - * @typechecks static-only - */ - -"use strict"; - -var invariant = require('invariant'); - -var hasReadOnlyValue = { - 'checkbox': true, - 'hidden': true, - 'radio': true -}; - -/** - * Provide a linked `value` attribute for controlled forms. You should not use - * this outside of the ReactDOM controlled form components. - */ -var LinkedValueMixin = { - propTypes: { - value: function(props, propName, componentName) { - if (__DEV__) { - if (props[propName] && - !hasReadOnlyValue[props.type] && - !props.onChange && - !props.readOnly && - !props.disabled) { - console.warn( - 'You provided a `value` prop to a form field without an ' + - '`onChange` handler. This will render a read-only field. If ' + - 'the field should be mutable use `defaultValue`. Otherwise, set ' + - 'either `onChange` or `readOnly`.' - ); - } - } - } - }, - - _assertLink: function() { - invariant( - this.props.value == null && this.props.onChange == null, - 'Cannot provide a valueLink and a value or onChange event. If you ' + - 'want to use value or onChange, you probably don\'t want to use ' + - 'valueLink' - ); - }, - - /** - * @return {*} current value of the input either from value prop or link. - */ - getValue: function() { - if (this.props.valueLink) { - this._assertLink(); - return this.props.valueLink.value; - } - return this.props.value; - }, - - /** - * @return {function} change callback either from onChange prop or link. - */ - getOnChange: function() { - if (this.props.valueLink) { - this._assertLink(); - return this._handleLinkedValueChange; - } - return this.props.onChange; - }, - - /** - * @param {SyntheticEvent} e change event to handle - */ - _handleLinkedValueChange: function(e) { - this.props.valueLink.requestChange(e.target.value); - } -}; - -module.exports = LinkedValueMixin; diff --git a/src/dom/components/LinkedValueUtils.js b/src/dom/components/LinkedValueUtils.js new file mode 100644 index 0000000000000..e0fc356e865d8 --- /dev/null +++ b/src/dom/components/LinkedValueUtils.js @@ -0,0 +1,97 @@ +/** + * 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 LinkedValueUtils + * @typechecks static-only + */ + +"use strict"; + +var invariant = require('invariant'); + +var hasReadOnlyValue = { + 'checkbox': true, + 'hidden': true, + 'radio': true +}; + +function _assertLink(input) { + invariant( + input.props.value == null && input.props.onChange == null, + 'Cannot provide a valueLink and a value or onChange event. If you want ' + + 'to use value or onChange, you probably don\'t want to use valueLink.' + ); +} + +/** + * @param {SyntheticEvent} e change event to handle + */ +function _handleLinkedValueChange(e) { + /*jshint validthis:true */ + this.props.valueLink.requestChange(e.target.value); +} + +/** + * Provide a linked `value` attribute for controlled forms. You should not use + * this outside of the ReactDOM controlled form components. + */ +var LinkedValueUtils = { + Mixin: { + propTypes: { + value: function(props, propName, componentName) { + if (__DEV__) { + if (props[propName] && + !hasReadOnlyValue[props.type] && + !props.onChange && + !props.readOnly && + !props.disabled) { + console.warn( + 'You provided a `value` prop to a form field without an ' + + '`onChange` handler. This will render a read-only field. If ' + + 'the field should be mutable use `defaultValue`. Otherwise, ' + + 'set either `onChange` or `readOnly`.' + ); + } + } + } + } + }, + + /** + * @param {ReactComponent} input Form component + * @return {*} current value of the input either from value prop or link. + */ + getValue: function(input) { + if (input.props.valueLink) { + _assertLink(input); + return input.props.valueLink.value; + } + return input.props.value; + }, + + /** + * @param {ReactComponent} input Form component + * @return {function} change callback either from onChange prop or link. + */ + getOnChange: function(input) { + if (input.props.valueLink) { + _assertLink(input); + return _handleLinkedValueChange; + } + return input.props.onChange; + } +}; + +module.exports = LinkedValueUtils; diff --git a/src/dom/components/ReactDOMInput.js b/src/dom/components/ReactDOMInput.js index 125b0aab471c5..58febb6372c17 100644 --- a/src/dom/components/ReactDOMInput.js +++ b/src/dom/components/ReactDOMInput.js @@ -18,9 +18,9 @@ "use strict"; -var DOMPropertyOperations = require('DOMPropertyOperations'); -var LinkedValueMixin = require('LinkedValueMixin'); var AutoFocusMixin = require('AutoFocusMixin'); +var DOMPropertyOperations = require('DOMPropertyOperations'); +var LinkedValueUtils = require('LinkedValueUtils'); var ReactCompositeComponent = require('ReactCompositeComponent'); var ReactDOM = require('ReactDOM'); var ReactMount = require('ReactMount'); @@ -52,7 +52,7 @@ var instancesByReactID = {}; var ReactDOMInput = ReactCompositeComponent.createClass({ displayName: 'ReactDOMInput', - mixins: [LinkedValueMixin, AutoFocusMixin], + mixins: [AutoFocusMixin, LinkedValueUtils.Mixin], getInitialState: function() { var defaultValue = this.props.defaultValue; @@ -76,7 +76,7 @@ var ReactDOMInput = ReactCompositeComponent.createClass({ props.checked = this.props.checked != null ? this.props.checked : this.state.checked; - var value = this.getValue(); + var value = LinkedValueUtils.getValue(this); props.value = value != null ? value : this.state.value; props.onChange = this._handleChange; @@ -105,7 +105,7 @@ var ReactDOMInput = ReactCompositeComponent.createClass({ ); } - var value = this.getValue(); + var value = LinkedValueUtils.getValue(this); if (value != null) { // Cast `value` to a string to ensure the value is set correctly. While // browsers typically do this as necessary, jsdom doesn't. @@ -115,10 +115,10 @@ var ReactDOMInput = ReactCompositeComponent.createClass({ _handleChange: function(event) { var returnValue; - var onChange = this.getOnChange(); + var onChange = LinkedValueUtils.getOnChange(this); if (onChange) { this._isChanging = true; - returnValue = onChange(event); + returnValue = onChange.call(this, event); this._isChanging = false; } this.setState({ diff --git a/src/dom/components/ReactDOMSelect.js b/src/dom/components/ReactDOMSelect.js index 140596ca6c986..4e625aad8be51 100644 --- a/src/dom/components/ReactDOMSelect.js +++ b/src/dom/components/ReactDOMSelect.js @@ -18,8 +18,8 @@ "use strict"; -var LinkedValueMixin = require('LinkedValueMixin'); var AutoFocusMixin = require('AutoFocusMixin'); +var LinkedValueUtils = require('LinkedValueUtils'); var ReactCompositeComponent = require('ReactCompositeComponent'); var ReactDOM = require('ReactDOM'); @@ -61,7 +61,7 @@ function selectValueType(props, propName, componentName) { function updateOptions() { /*jshint validthis:true */ var multiple = this.props.multiple; - var propValue = this.getValue(); + var propValue = LinkedValueUtils.getValue(this); var value = propValue != null ? propValue : this.state.value; var options = this.getDOMNode().options; var selectedValue, i, l; @@ -102,7 +102,7 @@ function updateOptions() { var ReactDOMSelect = ReactCompositeComponent.createClass({ displayName: 'ReactDOMSelect', - mixins: [LinkedValueMixin, AutoFocusMixin], + mixins: [AutoFocusMixin, LinkedValueUtils.Mixin], propTypes: { defaultValue: selectValueType, @@ -142,10 +142,10 @@ var ReactDOMSelect = ReactCompositeComponent.createClass({ _handleChange: function(event) { var returnValue; - var onChange = this.getOnChange(); + var onChange = LinkedValueUtils.getOnChange(this); if (onChange) { this._isChanging = true; - returnValue = onChange(event); + returnValue = onChange.call(this, event); this._isChanging = false; } diff --git a/src/dom/components/ReactDOMTextarea.js b/src/dom/components/ReactDOMTextarea.js index 2dd599b7246a4..83e1a95392790 100644 --- a/src/dom/components/ReactDOMTextarea.js +++ b/src/dom/components/ReactDOMTextarea.js @@ -18,9 +18,9 @@ "use strict"; -var DOMPropertyOperations = require('DOMPropertyOperations'); -var LinkedValueMixin = require('LinkedValueMixin'); var AutoFocusMixin = require('AutoFocusMixin'); +var DOMPropertyOperations = require('DOMPropertyOperations'); +var LinkedValueUtils = require('LinkedValueUtils'); var ReactCompositeComponent = require('ReactCompositeComponent'); var ReactDOM = require('ReactDOM'); @@ -48,7 +48,7 @@ var textarea = ReactDOM.textarea; var ReactDOMTextarea = ReactCompositeComponent.createClass({ displayName: 'ReactDOMTextarea', - mixins: [LinkedValueMixin, AutoFocusMixin], + mixins: [AutoFocusMixin, LinkedValueUtils.Mixin], getInitialState: function() { var defaultValue = this.props.defaultValue; @@ -78,7 +78,7 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({ if (defaultValue == null) { defaultValue = ''; } - var value = this.getValue(); + var value = LinkedValueUtils.getValue(this); return { // We save the initial value so that `ReactDOMComponent` doesn't update // `textContent` (unnecessary since we update value). @@ -97,7 +97,7 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({ render: function() { // Clone `this.props` so we don't mutate the input. var props = merge(this.props); - var value = this.getValue(); + var value = LinkedValueUtils.getValue(this); invariant( props.dangerouslySetInnerHTML == null, @@ -114,7 +114,7 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({ }, componentDidUpdate: function(prevProps, prevState, prevContext) { - var value = this.getValue(); + var value = LinkedValueUtils.getValue(this); if (value != null) { var rootNode = this.getDOMNode(); // Cast `value` to a string to ensure the value is set correctly. While @@ -125,10 +125,10 @@ var ReactDOMTextarea = ReactCompositeComponent.createClass({ _handleChange: function(event) { var returnValue; - var onChange = this.getOnChange(); + var onChange = LinkedValueUtils.getOnChange(this); if (onChange) { this._isChanging = true; - returnValue = onChange(event); + returnValue = onChange.call(this, event); this._isChanging = false; } this.setState({value: event.target.value});