Skip to content
Snippets Groups Projects
listcontroller.js 3.41 KiB
Newer Older
import m from 'mithril';
import Stream from 'mithril/stream';
import { ResourceHandler } from './auth';
import { debounce } from './utils';

export default class DatalistController {
Hermann's avatar
Hermann committed
  constructor(resource, query = {}, searchKeys = false, onlineSearch = true) {
    this.onlineSearch = onlineSearch;
    if (onlineSearch) {
      this.handler = new ResourceHandler(resource, searchKeys);
    } else {
      this.handler = new ResourceHandler(resource, false);
Hermann's avatar
Hermann committed
      this.clientSearchKeys = searchKeys || [];
Hermann's avatar
Hermann committed
    }
    this.query = query || {};
Hermann's avatar
Hermann committed
    this.search = null;
    // state pointer that is counted up every time the table is refreshed so
    // we can tell infinite scroll that the data-version has changed.
    this.stateCounter = Stream(0);
    this.debouncedSearch = debounce((search) => {
      this.setSearch(search);
      this.refresh();
      m.redraw();
    }, 100);
  refresh() {
    this.stateCounter(this.stateCounter() + 1);
  infiniteScrollParams(item) {
    return {
      item,
      pageData: pageNum => this.getPageData(pageNum),
      pageKey: pageNum => `${pageNum}-${this.stateCounter()}`,
    };
  }

  getPageData(pageNum) {
    // for some reason this is called before the object is instantiated.
    // check this and return nothing
Hermann's avatar
Hermann committed
    const query = Object.assign({}, this.query);
Hermann's avatar
Hermann committed
    query.max_results = 10;
    query.page = pageNum;

Hermann's avatar
Hermann committed
    return new Promise((resolve) => {
      this.handler.get(query).then((data) => {
Hermann's avatar
Hermann committed
        // If onlineSearch is false, we filter the page-results at the client
        // because the API would not understand the search pattern, e.g. for
        // embedded keys like user.firstname
        if (!this.onlineSearch && this.clientSearchKeys.length > 0 && this.search) {
          const response = [];
Hermann's avatar
Hermann committed
          const searchRegex = new RegExp(this.search, 'i');
Hermann's avatar
Hermann committed
          // We go through all response items and will add them to response if
          // they match the query.
          data._items.forEach((item) => {
            // Try every search Key seperately, such that any match with any
            // key is sufficient
            this.clientSearchKeys.some((key) => {
              if (key.match(/.*\..*/)) {
                // traverse the key, this is a key pointing to a sub-object
                let intermediateObject = Object.assign({}, item);
                key.split('.').forEach((subKey) => {
                  intermediateObject = intermediateObject[subKey];
                });
                if (intermediateObject.match(searchRegex)) {
Hermann's avatar
Hermann committed
                  response.push(item);
                  // return true to end the search of this object, it is already
                  // matched
                  return true;
                }
              } else if (item[key] && item[key].match(searchRegex)) {
Hermann's avatar
Hermann committed
                response.push(item);
                // return true to end the search of this object, it is already
                // matched
                return true;
              }
              return false;
            });
          });
          resolve(response);
        } else {
          resolve(data._items);
        }
Hermann's avatar
Hermann committed
    if (this.onlineSearch) {
      this.search = search;
      this.query.search = search;
    } else if (this.clientSearchKeys.length > 0) {
      this.search = search;
    }
  }

  setQuery(query) {
    this.query = query;
Hermann's avatar
Hermann committed
    this.query.search = this.search;