summaryrefslogtreecommitdiffstats
path: root/webapp/components/multiselect/multiselect_list.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/components/multiselect/multiselect_list.jsx')
-rw-r--r--webapp/components/multiselect/multiselect_list.jsx169
1 files changed, 169 insertions, 0 deletions
diff --git a/webapp/components/multiselect/multiselect_list.jsx b/webapp/components/multiselect/multiselect_list.jsx
new file mode 100644
index 000000000..ff9f68bf8
--- /dev/null
+++ b/webapp/components/multiselect/multiselect_list.jsx
@@ -0,0 +1,169 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {cmdOrCtrlPressed} from 'utils/utils.jsx';
+import Constants from 'utils/constants.jsx';
+const KeyCodes = Constants.KeyCodes;
+
+import React from 'react';
+import {FormattedMessage} from 'react-intl';
+
+export default class MultiSelectList extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.defaultOptionRenderer = this.defaultOptionRenderer.bind(this);
+ this.handleArrowPress = this.handleArrowPress.bind(this);
+ this.setSelected = this.setSelected.bind(this);
+
+ this.toSelect = -1;
+
+ this.state = {
+ selected: -1
+ };
+ }
+
+ componentDidMount() {
+ document.addEventListener('keydown', this.handleArrowPress);
+ }
+
+ componentWillUnmount() {
+ document.removeEventListener('keydown', this.handleArrowPress);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState({selected: this.toSelect});
+
+ const options = nextProps.options;
+
+ if (options && options.length > 0 && this.toSelect >= 0) {
+ this.props.onSelect(options[this.toSelect]);
+ }
+ }
+
+ componentDidUpdate() {
+ if (this.refs.list && this.refs.selected) {
+ const elemTop = this.refs.selected.getBoundingClientRect().top;
+ const elemBottom = this.refs.selected.getBoundingClientRect().bottom;
+ const listTop = this.refs.list.getBoundingClientRect().top;
+ const listBottom = this.refs.list.getBoundingClientRect().bottom;
+ if (elemBottom > listBottom) {
+ this.refs.selected.scrollIntoView(false);
+ } else if (elemTop < listTop) {
+ this.refs.selected.scrollIntoView(true);
+ }
+ }
+ }
+
+ setSelected(selected) {
+ this.toSelect = selected;
+ }
+
+ handleArrowPress(e) {
+ if (cmdOrCtrlPressed(e) && e.shiftKey) {
+ return;
+ }
+
+ const options = this.props.options;
+ if (options.length === 0) {
+ return;
+ }
+
+ let selected;
+ switch (e.keyCode) {
+ case KeyCodes.DOWN:
+ if (this.state.selected === -1) {
+ selected = 0;
+ break;
+ }
+ selected = Math.min(this.state.selected + 1, options.length - 1);
+ break;
+ case KeyCodes.UP:
+ if (this.state.selected === -1) {
+ selected = 0;
+ break;
+ }
+ selected = Math.max(this.state.selected - 1, 0);
+ break;
+ default:
+ return;
+ }
+
+ e.preventDefault();
+ this.setState({selected});
+ this.props.onSelect(options[selected]);
+ }
+
+ defaultOptionRenderer(option, isSelected, onAdd) {
+ var rowSelected = '';
+ if (isSelected) {
+ rowSelected = 'more-modal__row--selected';
+ }
+
+ return (
+ <div
+ ref={isSelected ? 'selected' : option.value}
+ className={rowSelected}
+ key={'multiselectoption' + option.value}
+ onClick={() => onAdd(option)}
+ >
+ {option.label}
+ </div>
+ );
+ }
+
+ render() {
+ const options = this.props.options;
+
+ if (options == null || options.length === 0) {
+ return (
+ <div
+ key='no-users-found'
+ className='no-channel-message'
+ >
+ <p className='primary-message'>
+ <FormattedMessage
+ id='multiselect.list.notFound'
+ defaultMessage='No items found'
+ />
+ </p>
+ </div>
+ );
+ }
+
+ let renderer;
+ if (this.props.optionRenderer) {
+ renderer = this.props.optionRenderer;
+ } else {
+ renderer = this.defaultOptionRenderer;
+ }
+
+ const optionControls = options.map((o, i) => renderer(o, this.state.selected === i, this.props.onAdd));
+
+ return (
+ <div className='more-modal__list'>
+ <div
+ ref='list'
+ >
+ {optionControls}
+ </div>
+ </div>
+ );
+ }
+}
+
+MultiSelectList.defaultProps = {
+ options: [],
+ perPage: 50,
+ onAction: () => null
+};
+
+MultiSelectList.propTypes = {
+ options: React.PropTypes.arrayOf(React.PropTypes.object),
+ optionRenderer: React.PropTypes.func,
+ page: React.PropTypes.number,
+ perPage: React.PropTypes.number,
+ onPageChange: React.PropTypes.func,
+ onAdd: React.PropTypes.func,
+ onSelect: React.PropTypes.func
+};