1 import React from 'react';
2 import FontAwesome from 'react-fontawesome';
3 import Input from 'react-bootstrap/lib/Input.js';
5 class DualListboxView extends React.Component {
9 availableList: React.PropTypes.arrayOf(React.PropTypes.shape({
10 id: React.PropTypes.string.isRequired,
11 name: React.PropTypes.string.isRequired
13 filterTitle: React.PropTypes.shape({
14 left: React.PropTypes.string,
15 right: React.PropTypes.string
17 selectedValuesList: React.PropTypes.arrayOf(React.PropTypes.string),
19 onChange: React.PropTypes.func.isRequired
22 static defaultProps = {
23 selectedValuesList: [],
32 availableListFilter: '',
33 selectedValuesListFilter: ''
36 static contextTypes = {
37 isReadOnlyMode: React.PropTypes.bool
41 let {availableList, selectedValuesList, filterTitle} = this.props;
42 let {availableListFilter, selectedValuesListFilter} = this.state;
43 let isReadOnlyMode = this.context.isReadOnlyMode;
45 let unselectedList = availableList.filter(availableItem => !selectedValuesList.find(value => value === availableItem.id));
46 let selectedList = availableList.filter(availableItem => selectedValuesList.find(value => value === availableItem.id));
47 selectedList = selectedList.sort((a, b) => selectedValuesList.indexOf(a.id) - selectedValuesList.indexOf(b.id));
50 <div className='dual-list-box'>
51 {this.renderListbox(filterTitle.left, unselectedList, {
52 value: availableListFilter,
53 ref: 'availableListFilter',
54 disabled: isReadOnlyMode,
55 onChange: () => this.setState({availableListFilter: this.refs.availableListFilter.getValue()})
56 }, {ref: 'availableValues', disabled: isReadOnlyMode})}
57 {this.renderOperationsBar(isReadOnlyMode)}
58 {this.renderListbox(filterTitle.right, selectedList, {
59 value: selectedValuesListFilter,
60 ref: 'selectedValuesListFilter',
61 disabled: isReadOnlyMode,
62 onChange: () => this.setState({selectedValuesListFilter: this.refs.selectedValuesListFilter.getValue()})
63 }, {ref: 'selectedValues', disabled: isReadOnlyMode})}
68 renderListbox(filterTitle, list, filterProps, props) {
69 let regExFilter = new RegExp(escape(filterProps.value), 'i');
70 let matchedItems = list.filter(item => item.name.match(regExFilter));
71 let unMatchedItems = list.filter(item => !item.name.match(regExFilter));
75 <div className='dual-search-multi-select-section'>
77 <div className='dual-text-box-search search-wrapper'>
78 <Input name='search-input-control' type='text' groupClassName='search-input-control' {...filterProps}/>
79 <FontAwesome name='search' className='search-icon'/>
83 groupClassName='dual-list-box-multi-select'
85 name='dual-list-box-multi-select'
87 {matchedItems.map(item => this.renderOption(item.id, item.name))}
88 {matchedItems.length && unMatchedItems.length && <option style={{pointerEvents: 'none'}}>--------------------</option>}
89 {unMatchedItems.map(item => this.renderOption(item.id, item.name))}
95 renderOption(value, name) {
96 return (<option className='dual-list-box-multi-select-text' key={value} value={value}>{name}</option>);
99 renderOperationsBar(isReadOnlyMode) {
101 <div className={`dual-list-options-bar${isReadOnlyMode ? ' disabled' : ''}`}>
102 {this.renderOperationBarButton(() => this.addToSelectedList(), 'angle-right')}
103 {this.renderOperationBarButton(() => this.removeFromSelectedList(), 'angle-left')}
104 {this.renderOperationBarButton(() => this.addAllToSelectedList(), 'angle-double-right')}
105 {this.renderOperationBarButton(() => this.removeAllFromSelectedList(), 'angle-double-left')}
110 renderOperationBarButton(onClick, fontAwesomeIconName){
111 return (<div className='dual-list-option' onClick={onClick}><FontAwesome name={fontAwesomeIconName}/></div>);
114 addToSelectedList() {
115 this.props.onChange(this.props.selectedValuesList.concat(this.refs.availableValues.getValue()));
118 removeFromSelectedList() {
119 const selectedValues = this.refs.selectedValues.getValue();
120 this.props.onChange(this.props.selectedValuesList.filter(value => !selectedValues.find(selectedValue => selectedValue === value)));
123 addAllToSelectedList() {
124 this.props.onChange(this.props.availableList.map(item => item.id));
127 removeAllFromSelectedList() {
128 this.props.onChange([]);
132 export default DualListboxView;