Skip to content
Snippets Groups Projects
tableView.js 3.27 KiB
Newer Older
import m from 'mithril';
import infinite from 'mithril-infinite';
import { List, ListTile, Toolbar, Search, Button } from 'polythene-mithril';
import 'polythene-css';
import { styler } from 'polythene-core-css';
import { debounce } from '../utils';
const tableStyles = [
  {
    '.tabletool': {
      display: 'grid',
      height: '100%',
Hermann's avatar
Hermann committed
      'grid-template-rows': '48px calc(100% - 48px)',
Hermann's avatar
Hermann committed
    },
    '.toolbar': {
      'grid-row': 1,
      display: 'flex',
    },
    '.scrollTable': {
      'grid-row': 2,
Hermann's avatar
Hermann committed
      'background-color': 'white',
    },
    '.tableTile': {
      padding: '10px',
Hermann's avatar
Hermann committed
      'border-bottom': '1px solid rgba(0, 0, 0, 0.12)',
    },
  },
];

styler.add('tableview', tableStyles);

export default class TableView {
  /* Shows a table of objects for a given API resource.
   *
   * Required attributes:
   *   vnode: { attrs: { controller, titles, keys } }
   *   - controller: a listcontroller for some API resource data
   *   - titles: the titles of the table
   *   - keys: Keys of this resource to display as columns, e.g. ['firstname']
   *       Works with embedded resources, i.e. if you add
   *       { embedded: { event: 1 } } to a list of eventsignups,
   *       you can display event.title_de as a table key
   */
Hermann's avatar
Hermann committed
  constructor({ attrs: { keys } }) {
    this.search = '';
    this.tableKeys = keys;
  }

  getItemData(data) {
    return this.tableKeys.map((key) => {
      // Access a nested key, indicated by dot-notation
      let nestedData = data;
      key.split('.').forEach((subKey) => { nestedData = nestedData[subKey]; });
      return m(
        'div',
Hermann's avatar
Hermann committed
        { style: { width: `${98 / this.tableKeys.length}%` } },
        nestedData,
      );
    });
  }

  item() {
    return (data, opts) => m(ListTile, {
Hermann's avatar
Hermann committed
      className: 'themed-list-tile',
      hoverable: true,
      compactFront: true,
      content: m('div', {
        onclick() { m.route.set(`/${data._links.self.href}`); },
Hermann's avatar
Hermann committed
        className: 'tableTile',
        style: { width: '100%', display: 'flex' },
      }, this.getItemData(data)),
    });
Hermann's avatar
Hermann committed
    attrs: {
Hermann's avatar
Hermann committed
      titles,
Hermann's avatar
Hermann committed
      onAdd = () => {},
Hermann's avatar
Hermann committed
    },
  }) {
    const updateList = debounce(() => {
      controller.refresh();
    }, 500);

    return m('div.tabletool', [
      m(Toolbar, {
        className: 'toolbar',
Hermann's avatar
Hermann committed
        compact: true,
        content: [
          m(Search, {
            textfield: {
              label: 'Search',
              onChange: ({ value }) => {
                controller.setSearch(value);
                updateList();
              },
            },
            fullWidth: false,
          }),
          m(Button, {
            className: 'blue-button',
            borders: true,
            label: 'Add',
            events: { onclick: () => { onAdd(); } },
          }),
        ],
      }),
      m(List, {
        className: 'scrollTable',
Hermann's avatar
Hermann committed
        tiles: [
          m(ListTile, {
            className: 'tableTile',
            content: m(
              'div',
              { style: { width: '100%', display: 'flex' } },
              titles.map(title => m('div', {
Hermann's avatar
Hermann committed
                style: { width: `${98 / this.tableKeys.length}%` },
Hermann's avatar
Hermann committed
              }, title)),
            ),
          }),
          m(infinite, controller.infiniteScrollParams(this.item())),
        ],