Browse Source

Global search development

* search input
* parse query with operators
John R. Supplee 4 years ago
parent
commit
5913a4af1b

+ 37 - 0
client/components/main/globalSearch.jade

@@ -0,0 +1,37 @@
+template(name="globalSearchHeaderBar")
+  h1
+    i.fa.fa-search
+    | {{_ 'globalSearch-title'}}
+
+template(name="globalSearchModalTitle")
+  h2
+    i.fa.fa-keyboard-o
+    | {{_ 'globalSearch-title'}}
+
+template(name="globalSearch")
+  if isPageReady.get
+    .wrapper
+      form.js-search-query-form
+        input(type="text" name="searchQuery" placeholder="{{_ 'search-example'}}" autofocus dir="auto")
+  else
+    +spinner
+
+template(name="globalSearchViewChangePopup")
+  ul.pop-over-list
+    li
+      with "globalSearchViewChange-choice-me"
+        a.js-due-cards-view-me
+          i.fa.fa-user.colorful
+          | {{_ 'globalSearchViewChange-choice-me'}}
+          if $eq Utils.globalSearchView "me"
+            i.fa.fa-check
+    li
+      with "globalSearchViewChange-choice-all"
+        a.js-due-cards-view-all
+          i.fa.fa-users.colorful
+          | {{_ 'globalSearchViewChange-choice-all'}}
+          span.sub-name
+            +viewer
+              | {{_ 'globalSearchViewChange-choice-all-description' }}
+          if $eq Utils.globalSearchView "all"
+            i.fa.fa-check

+ 148 - 0
client/components/main/globalSearch.js

@@ -0,0 +1,148 @@
+const subManager = new SubsManager();
+
+BlazeComponent.extendComponent({
+  events() {
+    return [
+      {
+        'click .js-due-cards-view-change': Popup.open('globalSearchViewChange'),
+      },
+    ];
+  },
+}).register('globalSearchHeaderBar');
+
+Template.globalSearch.helpers({
+  userId() {
+    return Meteor.userId();
+  },
+});
+
+BlazeComponent.extendComponent({
+  events() {
+    return [
+      {
+        'click .js-due-cards-view-me'() {
+          Utils.setDueCardsView('me');
+          Popup.close();
+        },
+
+        'click .js-due-cards-view-all'() {
+          Utils.setDueCardsView('all');
+          Popup.close();
+        },
+      },
+    ];
+  },
+}).register('globalSearchViewChangePopup');
+
+BlazeComponent.extendComponent({
+  onCreated() {
+    this.isPageReady = new ReactiveVar(true);
+    this.query = new ReactiveVar('');
+
+    // this.autorun(() => {
+    //   const handle = subManager.subscribe('globalSearch');
+    //   Tracker.nonreactive(() => {
+    //     Tracker.autorun(() => {
+    //       this.isPageReady.set(handle.ready());
+    //     });
+    //   });
+    // });
+    Meteor.subscribe('setting');
+  },
+
+  events() {
+    return [
+      {
+        'submit .js-search-query-form'(evt) {
+          evt.preventDefault();
+          this.query.set(evt.target.searchQuery.value);
+          // eslint-disable-next-line no-console
+          console.log('query:', this.query.get());
+
+          let query = this.query.get();
+          const reUser = /^@(?<user>\w+)(\s+|$)/;
+          const reLabel = /^#(?<label>\w+)(\s+|$)/;
+          const reOperator1 = /^(?<operator>\w+):(?<value>\w+)(\s+|$)/;
+          const reOperator2 = /^(?<operator>\w+):(?<quote>["']*)(?<value>.*?)\k<quote>(\s+|$)/;
+          const reText = /^(?<text>[^:@#\s]+)(\s+|$)/;
+          const reQuotedText = /^(?<quote>["'])(?<text>\w+)\k<quote>(\s+|$)/;
+          const operatorMap = {
+            board: 'boards',
+            b: 'boards',
+            label: 'labels',
+            lable: 'labels',
+            user: 'users',
+            u: 'users',
+            swimlane: 'swimlanes',
+            swim: 'swimlanes',
+            s: 'swimlanes',
+            list: 'lists',
+            l: 'lists',
+          };
+          const selector = {
+            boards: [],
+            swimlanes: [],
+            lists: [],
+            users: [],
+            labels: [],
+          };
+          let text = '';
+          while (query) {
+            // eslint-disable-next-line no-console
+            console.log('query:', query);
+            let m = query.match(reUser);
+            if (m) {
+              query = query.replace(reUser, '');
+              selector.users.push(m.groups.user);
+              continue;
+            }
+
+            m = query.match(reLabel);
+            if (m) {
+              query = query.replace(reLabel, '');
+              selector.labels.push(m.groups.label);
+              continue;
+            }
+
+            m = query.match(reOperator1);
+            if (!m) {
+              m = query.match(reOperator2);
+              if (m) {
+                query = query.replace(reOperator2, '');
+              }
+            } else {
+              query = query.replace(reOperator1, '');
+            }
+            if (m) {
+              const op = m.groups.operator.toLowerCase();
+              if (op in operatorMap) {
+                selector[operatorMap[op]].push(m.groups.value);
+              }
+              continue;
+            }
+
+            m = query.match(reQuotedText);
+            if (!m) {
+              m = query.match(reText);
+              if (m) {
+                query = query.replace(reText, '');
+              }
+            } else {
+              query = query.replace(reQuotedText, '');
+            }
+            if (m) {
+              text += (text ? ' ' : '') + m.groups.text;
+            }
+          }
+
+          // eslint-disable-next-line no-console
+          console.log('selector:', selector);
+          // eslint-disable-next-line no-console
+          console.log('text:', text);
+        },
+      },
+    ];
+  },
+
+  globalSearchList() {},
+}).register('globalSearch');

+ 69 - 0
client/components/main/globalSearch.styl

@@ -0,0 +1,69 @@
+.due-cards-board-wrapper
+  border-radius: 8px
+  //padding: 0.5rem
+  min-width: 400px
+  border-width: 8px
+  border-color: grey
+  border-style: solid
+  margin-bottom: 2rem
+  margin-right: auto
+  margin-left: auto
+
+.due-cards-board-title
+  font-size: 1.4rem
+  font-weight: bold
+  padding: 0.5rem
+  background-color: grey
+  color: white
+
+.due-cards-swimlane-title
+  font-size: 1.1rem
+  font-weight: bold
+  padding: 0.5rem
+  padding-bottom: 0.4rem
+  margin-top: 0
+  margin-bottom: 0.5rem
+  //border-top: black 1px solid
+  //border-bottom: black 1px solid
+  text-align: center
+
+.swimlane-default-color
+  background-color: lightgrey
+
+.due-cards-list-title
+  font-weight: bold
+  font-size: 1.1rem
+  //padding-bottom: 0
+  //margin-bottom: 0
+  text-align: center
+  margin-bottom: 0.7rem
+
+.due-cards-list-wrapper
+  margin: 1rem
+  border-radius: 5px
+  padding: 1.5rem
+  padding-top: 0.75rem
+  display: inline-block
+  min-width: 250px
+  max-width: 350px
+
+.due-cards-card-wrapper
+  margin-top: 0
+  margin-bottom: 10px
+
+.due-cards-dueat-list-wrapper
+  max-width: 500px
+  margin-right: auto
+  margin-left: auto
+
+.due-cards-field-name
+  font-weight: bold
+
+.due-cards-context
+  display: inline-block
+
+.due-cards-context-separator
+  font-weight: bold
+
+.due-cards-context-list
+  margin-bottom: 0.7rem

+ 18 - 0
config/router.js

@@ -149,6 +149,24 @@ FlowRouter.route('/due-cards', {
   },
   },
 });
 });
 
 
+FlowRouter.route('/global-search', {
+  name: 'global-search',
+  action() {
+    Filter.reset();
+    // EscapeActions.executeAll();
+    EscapeActions.executeUpTo('popup-close');
+
+    Utils.manageCustomUI();
+    Utils.manageMatomo();
+
+    BlazeLayout.render('defaultLayout', {
+      headerBar: 'globalSearchHeaderBar',
+      content: 'globalSearch',
+    });
+    // }
+  },
+});
+
 FlowRouter.route('/import/:source', {
 FlowRouter.route('/import/:source', {
   name: 'import',
   name: 'import',
   triggersEnter: [AccountsTemplates.ensureSignedIn],
   triggersEnter: [AccountsTemplates.ensureSignedIn],