Skip to content
Snippets Groups Projects
selectList.js 4.28 KiB
Newer Older
import m from 'mithril';
import Stream from 'mithril/stream';
import {
  List, ListTile, Search, IconButton, Button, Shadow, Toolbar,
  ToolbarTitle,
} from 'polythene-mithril';
import infinite from 'mithril-infinite';
import { debounce } from '../utils';
import { icons, BackButton, ClearButton, SearchIcon } from './elements';

const createSearchField = () => {
  return {
    oninit: vnode => {
      const value = Stream("");
      const setInputState = Stream();

      //const clear = () => setInputState()({ value: '', focus: false});
      const clear = () => value('');
      const leave = () => value('');

      vnode.state = {
        value,
        setInputState,
        clear,
        leave
      };
    },
    view: ({ state, attrs }) => {
      // incoming value and focus added for result list example:
      const value = attrs.value !== undefined ? attrs.value : state.value();
      return m(Search, Object.assign(
        {},
        {
          textfield: {
            label: "Search",
            onChange: (newState) => {
              state.value(newState.value);
              state.setInputState(newState.setInputState);
              // onChange callback added for result list example:
              attrs.onChange && attrs.onChange(newState, state.setInputState);
            },
            value,
            // incoming label and defaultValue added for result list example:
            label: attrs.label || "Search",
            defaultValue: attrs.defaultValue,
          },
          buttons: {
            none: {
              before: m(SearchIcon),
            },
            focus: {
              before: m(BackButton, { leave: state.leave }),
            },
            focus_dirty: {
              before: m(BackButton, { leave: state.leave }),
              after: m(ClearButton, { clear: state.clear }),
            },
            dirty: {
              before: m(BackButton, { leave: state.leave }),
              after: m(ClearButton, { clear: state.clear }),
            },
          },
          before: m(Shadow),
        },
        attrs,
      ));
    },
  };
};

const SearchField = createSearchField();

Hermann's avatar
Hermann committed

export default class SelectList {
  constructor({ attrs: { listTileAttrs } }) {
Hermann's avatar
Hermann committed
    this.selected = null;
    this.showList = false;
    this.searchValue = '';
    this.listTileAttrs = listTileAttrs;
Hermann's avatar
Hermann committed
  }

  item() {
    return (data) => {
      const attrs = {
        compactFront: true,
        hoverable: true,
        className: 'themed-list-tile',
        events: {
          onclick: () => { this.selected = data; this.showList = false; },
        },
      };
      // Overwrite default attrs
      Object.assign(attrs, this.listTileAttrs(data));
      return m(ListTile, attrs);
    };
  }
Hermann's avatar
Hermann committed

  view({ attrs: { controller, onSubmit = () => {} } }) {
    return m('div', [
      this.selected ? m(Toolbar, { compact: true }, [
        m(IconButton, {
          icon: { svg: m.trust(icons.iconClearSVG) },
          ink: false,
          events: { onclick: () => { this.selected = null; } },
        }),
        m(ToolbarTitle, { text: this.selected.name }),
        m(Button, {
          label: 'Submit',
          className: 'blue-button',
          events: {
            onclick: () => {
              onSubmit(this.selected);
              this.selected = null;
              controller.setSearch('');
              controller.refresh();
Hermann's avatar
Hermann committed
            },
          },
        }),
      ]) : m(SearchField, Object.assign({}, {
        label: 'type here',
        onChange: ({ value, focus }) => {
          if (focus) {
            this.showList = true;
          }
          if (value !== this.searchValue) {
            // if we always update the search value, this would also happen
            // immidiately in the moment where we click on the listitem.
            // Then, the list get's updated before the click is registered.
            // So, we make sure this state change is due to value change and
            // not due to focus change.
            this.searchValue = value;
            controller.setSearch(value);
            debounce(() => { controller.refresh(); }, 500);
          }
        },
        defaultValue: '',
      })),
      this.showList ? m(List, {
        className: 'scrollTable',
        tiles: m(infinite, controller.infiniteScrollParams(this.item())),
      }) : null,
Hermann's avatar
Hermann committed
    ]);
  }
}