From 13f9e6453a4605fd8023d5657580f64d3b916cd6 Mon Sep 17 00:00:00 2001
From: Hermann Blum <hermannsblum@yahoo.de>
Date: Sun, 18 Mar 2018 10:52:37 +0100
Subject: [PATCH] client side search

---
 src/config.json         |  4 +--
 src/events/viewEvent.js | 16 ++++++++---
 src/listcontroller.js   | 63 +++++++++++++++++++++++++++++++++++------
 3 files changed, 68 insertions(+), 15 deletions(-)

diff --git a/src/config.json b/src/config.json
index 5115107..0c6dc1d 100644
--- a/src/config.json
+++ b/src/config.json
@@ -90,8 +90,6 @@
             "user.firstname",
             "email"
         ],
-        "searchKeys": [
-            "email"
-        ]
+        "searchKeys": []
     }
 }
diff --git a/src/events/viewEvent.js b/src/events/viewEvent.js
index a7758e9..3d73d3a 100644
--- a/src/events/viewEvent.js
+++ b/src/events/viewEvent.js
@@ -40,10 +40,18 @@ styler.add('eventView', viewLayout);
 
 class ParticipantsTable {
   constructor({ attrs: { where } }) {
-    this.ctrl = new DatalistController('eventsignups', {
-      embedded: { user: 1 },
-      where,
-    }, signupConfig.tableKeys);
+    this.ctrl = new DatalistController(
+      'eventsignups', {
+        embedded: { user: 1 },
+        where,
+      },
+      [
+        'email',
+        'user.firstname',
+        'user.lastname',
+      ],
+      false,
+    );
   }
 
   getItemData(data) {
diff --git a/src/listcontroller.js b/src/listcontroller.js
index bc759b3..1d87195 100644
--- a/src/listcontroller.js
+++ b/src/listcontroller.js
@@ -2,10 +2,16 @@ import Stream from 'mithril/stream';
 import { ResourceHandler } from './auth';
 
 export default class DatalistController {
-  constructor(resource, query = {}, searchKeys = false) {
-    this.handler = new ResourceHandler(resource, searchKeys);
+  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);
+      this.clientSearchKeys = searchKeys || [];
+    }
     this.query = query || {};
-    this.items = [];
+    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);
@@ -27,25 +33,66 @@ export default class DatalistController {
   getPageData(pageNum) {
     // for some reason this is called before the object is instantiated.
     // check this and return nothing
-    const query = {};
-    Object.keys(this.query).forEach((key) => { query[key] = this.query[key]; });
+    const query = Object.assign({}, this.query);
     query.max_results = 10;
     query.page = pageNum;
 
     return new Promise((resolve, reject) => {
       this.handler.get(query).then((data) => {
-        resolve(data._items);
+        // 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 = [];
+          // 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.includes(this.search)) {
+                  response.push(item);
+                  // return true to end the search of this object, it is already
+                  // matched
+                  return true;
+                }
+              } else if (item[key] && item[key].includes(this.search)) {
+                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);
+        }
       });
     });
   }
 
   setSearch(search) {
-    this.query.search = search;
-    this.refresh();
+    if (this.onlineSearch) {
+      this.search = search;
+      this.query.search = search;
+      this.refresh();
+    } else if (this.clientSearchKeys.length > 0) {
+      this.search = search;
+      this.refresh();
+    }
   }
 
   setQuery(query) {
     this.query = query;
+    this.query.search = this.search;
     this.refresh();
   }
 }
-- 
GitLab