text: 
  import React, { Component } from 'react';
  import PropTypes from 'prop-types';
  import clazz from 'classname';
  
  import classes from './style.css';
  import UserInfo from '../../../wfc/model/userInfo';
  
  // TODO for forward
  export default class ConversationList extends Component {
      static propTypes = {
          max: PropTypes.number.isRequired,
          searching: PropTypes.string.isRequired,
          search: PropTypes.func.isRequired,
          getList: PropTypes.func.isRequired,
          onChange: PropTypes.func.isRequired,
      };
  
      static defaultProps = {
          max: 20,
      };
  
      state = {
          selected: [],
          active: '',
      };
  
      highlight(offset) {
          var scroller = this.refs.list;
          var users = Array.from(scroller.querySelectorAll('li[data-userid]'));
          var index = users.findIndex(e => e.classList.contains(classes.active));
  
          if (index > -1) {
              users[index].classList.remove(classes.active);
          }
  
          index += offset;
  
          if (index < 0) {
              // Fallback to the last element
              index = users.length - 1;
          } else if (index > users.length - 1) {
              // Fallback to the 1th element
              index = 0;
          }
  
          var active = users[index];
  
          if (active) {
              // Keep active item always in the viewport
              active.classList.add(classes.active);
              scroller.scrollTop = active.offsetTop + active.offsetHeight - scroller.offsetHeight;
          }
      }
  
      navigation(e) {
          var keyCode = e.keyCode;
          var offset = {
              // Up
              '38': -1,
              '40': 1,
          }[keyCode];
  
          if (offset) {
              this.highlight(offset);
          }
  
          if (keyCode !== 13) {
              return;
          }
  
          var active = this.refs.list.querySelector(`.${classes.active}`);
  
          if (active) {
              let userid = active.dataset.userid;
  
              if (!this.state.selected.includes(userid)) {
                  // Add
                  this.addSelected(userid, userid);
              } else {
                  // Remove
                  this.removeSelected(userid, userid);
              }
              setTimeout(() => this.props.onChange(this.state.selected));
          }
      }
  
      timer;
  
      search(text) {
          clearTimeout(this.timer);
  
          this.timer = setTimeout(() => {
              this.props.search(text);
          }, 300);
      }
  
      addSelected(userid, active = this.state.active) {
          var selected = [
              userid,
              ...this.state.selected,
          ];
          var max = this.props.max;
  
          if (max > 0) {
              selected = selected.slice(0, this.props.max);
          }
  
          this.setState({
              active,
              selected,
          });
          setTimeout(() => this.props.onChange(this.state.selected));
      }
  
      removeSelected(userid, active = this.state.active) {
          var selected = this.state.selected;
          var index = selected.indexOf(userid);
  
          this.setState({
              active,
              selected: [
                  ...selected.slice(0, index),
                  ...selected.slice(index + 1, selected.length)
              ]
          });
          setTimeout(() => this.props.onChange(this.state.selected));
      }
  
      toggleSelected(userid) {
          if (!this.state.selected.includes(userid)) {
              // Add
              this.addSelected(userid);
          } else {
              // Remove
              this.removeSelected(userid);
          }
  
          setTimeout(() => this.refs.input.focus());
      }
  
      renderList() {
          var { searching, getList } = this.props;
          var list = getList();
  
          if (searching && list.length === 0) {
              return (
                  <li className={classes.notfound}>
                      <img src="assets/images/crash.png" />
                      <h3>Can't find any people matching '{searching}'</h3>
                  </li>
              );
          }
          list = list.filter(e => e instanceof UserInfo);
  
          return list.map((e, index) => {
              return (
                  <li
                      className={clazz({
                          [classes.selected]: this.state.selected.includes(e.UserName),
                          [classes.active]: this.state.active === e.UserName,
                      })}
                      data-userid={e.uid}
                      key={index}
                      onClick={ev => this.toggleSelected(e.uid)}>
                      <img
                          className={classes.avatar}
                          src={e.portrait} />
                      <span
                          className={classes.username}
                          dangerouslySetInnerHTML={{ __html: e.displayName }} />
  
                      <i className="icon-ion-android-done-all" />
                  </li>
              );
          });
      }
  
      render() {
          return (
              <div className={classes.container}>
                  <input
                      autoFocus={true}
                      onKeyUp={e => this.navigation(e)}
                      onInput={e => this.search(e.target.value)}
                      placeholder="Type to Search..."
                      ref="input"
                      type="text" />
  
                  <ul
                      className={classes.list}
                      ref="list">
                      {this.renderList()}
                  </ul>
              </div>
          );
      }
  }
  