/*! * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * * 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. */ import React from 'react'; import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import i18n from 'nfvo-utils/i18n/i18n.js'; import classNames from 'classnames'; import Select from 'nfvo-components/input/SelectInput.jsx'; import Overlay from 'react-bootstrap/lib/Overlay.js'; import Tooltip from 'react-bootstrap/lib/Tooltip.js'; export const other = { OTHER: 'Other' }; class InputOptions extends React.Component { static propTypes = { values: PropTypes.arrayOf( PropTypes.shape({ enum: PropTypes.string, title: PropTypes.string }) ), isEnabledOther: PropTypes.bool, label: PropTypes.string, selectedValue: PropTypes.string, multiSelectedEnum: PropTypes.oneOfType([ PropTypes.string, PropTypes.array ]), selectedEnum: PropTypes.string, otherValue: PropTypes.string, overlayPos: PropTypes.string, onEnumChange: PropTypes.func, onOtherChange: PropTypes.func, onBlur: PropTypes.func, isRequired: PropTypes.bool, isMultiSelect: PropTypes.bool, isValid: PropTypes.bool, disabled: PropTypes.bool }; state = { otherInputDisabled: !this.props.otherValue }; oldProps = { selectedEnum: '', otherValue: '', multiSelectedEnum: [] }; render() { let { label, isRequired, values, otherValue, onOtherChange, isMultiSelect, onBlur, multiSelectedEnum, selectedEnum, isValid, children, isReadOnlyMode } = this.props; const dataTestId = this.props['data-test-id'] ? { 'data-test-id': this.props['data-test-id'] } : {}; let currentMultiSelectedEnum = []; let currentSelectedEnum = ''; let otherInputDisabled = (isMultiSelect && (multiSelectedEnum === undefined || multiSelectedEnum.length === 0 || multiSelectedEnum[0] !== other.OTHER)) || (!isMultiSelect && (selectedEnum === undefined || selectedEnum !== other.OTHER)); if (isMultiSelect) { currentMultiSelectedEnum = multiSelectedEnum; if (!otherInputDisabled) { currentSelectedEnum = multiSelectedEnum ? multiSelectedEnum.toString() : undefined; } } else if (selectedEnum) { currentSelectedEnum = selectedEnum; } if (!onBlur) { onBlur = () => {}; } return (
{label && } {isMultiSelect && otherInputDisabled ? ( (this.input = input)} label={label} className="form-control input-options-select" value={currentSelectedEnum} style={{ width: otherInputDisabled ? '100%' : '100px' }} onBlur={() => onBlur()} disabled={ isReadOnlyMode || Boolean(this.props.disabled) } onChange={value => this.enumChanged(value)} type="select"> {children || (values && values.length && values.map((val, index) => this.renderOptions(val, index) ))} {onOtherChange && ( )} {!otherInputDisabled && (
)} (this.otherValue = otherValue) } style={{ display: otherInputDisabled ? 'none' : 'block' }} disabled={ isReadOnlyMode || Boolean(this.props.disabled) } value={otherValue || ''} onBlur={() => onBlur()} onChange={() => this.changedOtherInput()} />
)}
{this.renderErrorOverlay()}
); } renderOptions(val, index) { return ( ); } renderMultiSelectOptions(values) { let { onOtherChange } = this.props; let optionsList = []; if (onOtherChange) { optionsList = values .map(option => { return { label: option.title, value: option.enum }; }) .concat([ { label: i18n(other.OTHER), value: i18n(other.OTHER) } ]); } else { optionsList = values.map(option => { return { label: option.title, value: option.enum }; }); } if (optionsList.length > 0 && optionsList[0].value === '') { optionsList.shift(); } return optionsList; } renderErrorOverlay() { let position = 'right'; const { errorText = '', isValid = true, type, overlayPos } = this.props; if (overlayPos) { position = overlayPos; } else if ( type === 'text' || type === 'email' || type === 'number' || type === 'password' ) { position = 'bottom'; } return ( { let { otherInputDisabled } = this.state; let target = otherInputDisabled ? ReactDOM.findDOMNode(this.input) : ReactDOM.findDOMNode(this.otherValue); return target.offsetParent ? target : undefined; }} container={this}> {errorText} ); } getValue() { let res = ''; let { isMultiSelect } = this.props; let { otherInputDisabled } = this.state; if (otherInputDisabled) { res = isMultiSelect ? this.input.getValue() : this.input.value; } else { res = this.otherValue.value; } return res; } enumChanged() { let enumValue = this.input.value; let { onEnumChange, onOtherChange, isMultiSelect, onChange } = this.props; this.setState({ otherInputDisabled: !Boolean(onOtherChange) || enumValue !== other.OTHER }); let value = isMultiSelect ? [enumValue] : enumValue; if (onEnumChange) { onEnumChange(value); } if (onChange) { onChange(value); } } multiSelectEnumChanged(enumValue) { let { onEnumChange, onOtherChange } = this.props; let selectedValues = enumValue.map(enumVal => { return enumVal.value; }); if (this.state.otherInputDisabled === false) { selectedValues.shift(); } else if (selectedValues.includes(i18n(other.OTHER))) { selectedValues = [i18n(other.OTHER)]; } this.setState({ otherInputDisabled: !Boolean(onOtherChange) || !selectedValues.includes(i18n(other.OTHER)) }); onEnumChange(selectedValues); } changedOtherInput() { let { onOtherChange } = this.props; onOtherChange(this.otherValue.value); } componentDidUpdate() { let { otherValue, selectedEnum, onInputChange, multiSelectedEnum } = this.props; if ( this.oldProps.otherValue !== otherValue || this.oldProps.selectedEnum !== selectedEnum || this.oldProps.multiSelectedEnum !== multiSelectedEnum ) { this.oldProps = { otherValue, selectedEnum, multiSelectedEnum }; onInputChange(); } } static getTitleByName(values, name) { for (let key of Object.keys(values)) { let option = values[key].find(option => option.enum === name); if (option) { return option.title; } } return name; } } export default InputOptions;