filtered_search_manager.js.es6 4.5 KB
Newer Older
C
Clement Ho 已提交
1
/* eslint-disable no-param-reassign */
C
Clement Ho 已提交
2 3 4 5
((global) => {
  const validTokenKeys = [{
    key: 'author',
    type: 'string',
6
    param: 'username',
C
Clement Ho 已提交
7
  }, {
C
Clement Ho 已提交
8
    key: 'assignee',
C
Clement Ho 已提交
9
    type: 'string',
10
    param: 'username',
C
Clement Ho 已提交
11
  }, {
C
Clement Ho 已提交
12
    key: 'milestone',
C
Clement Ho 已提交
13 14
    type: 'string',
    param: 'title',
C
Clement Ho 已提交
15
  }, {
C
Clement Ho 已提交
16
    key: 'label',
C
Clement Ho 已提交
17
    type: 'array',
C
Clement Ho 已提交
18
    param: 'name[]',
C
Clement Ho 已提交
19 20
  }];

C
Clement Ho 已提交
21 22 23
  function clearSearch(e) {
    e.stopPropagation();
    e.preventDefault();
C
Clement Ho 已提交
24 25 26 27 28

    document.querySelector('.filtered-search').value = '';
    document.querySelector('.clear-search').classList.add('hidden');
  }

C
Clement Ho 已提交
29
  function toggleClearSearchButton(e) {
C
Clement Ho 已提交
30
    const clearSearchButton = document.querySelector('.clear-search');
C
Clement Ho 已提交
31 32

    if (event.target.value) {
C
Clement Ho 已提交
33 34 35 36
       clearSearchButton.classList.remove('hidden');
     } else {
       clearSearchButton.classList.add('hidden');
     }
C
Clement Ho 已提交
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
  }

  function loadSearchParamsFromURL() {
    // We can trust that each param has one & since values containing & will be encoded
    // Remove the first character of search as it is always ?
    const params = window.location.search.slice(1).split('&');
    let inputValue = '';

    params.forEach((p) => {
      const split = p.split('=');
      const key = decodeURIComponent(split[0]);
      const value = split[1];

      // Sanitize value since URL converts spaces into +
      // Replace before decode so that we know what was originally + versus the encoded +
      const sanitizedValue = value ? decodeURIComponent(value.replace(/[+]/g, ' ')) : value;
C
Clement Ho 已提交
53
      const match = validTokenKeys.filter(t => key === `${t.key}_${t.param}`)[0];
C
Clement Ho 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81

      if (match) {
        const sanitizedKey = key.slice(0, key.indexOf('_'));
        const valueHasSpace = sanitizedValue.indexOf(' ') !== -1;

        const preferredQuotations = '"';
        let quotationsToUse = preferredQuotations;

        if (valueHasSpace) {
          // Prefer ", but use ' if required
          quotationsToUse = sanitizedValue.indexOf(preferredQuotations) === -1 ? preferredQuotations : '\'';
        }

        inputValue += valueHasSpace ? `${sanitizedKey}:${quotationsToUse}${sanitizedValue}${quotationsToUse}` : `${sanitizedKey}:${sanitizedValue}`;
        inputValue += ' ';
      } else if (!match && key === 'search') {
        inputValue += sanitizedValue;
        inputValue += ' ';
      }
    });

    // Trim the last space value
    document.querySelector('.filtered-search').value = inputValue.trim();

    if (inputValue.trim()) {
      document.querySelector('.clear-search').classList.remove('hidden');
    }
  }
C
Clement Ho 已提交
82 83 84

  class FilteredSearchManager {
    constructor() {
C
Clement Ho 已提交
85
      this.tokenizer = new gl.FilteredSearchTokenizer(validTokenKeys);
C
Clement Ho 已提交
86
      this.bindEvents();
C
Clement Ho 已提交
87
      loadSearchParamsFromURL();
C
Clement Ho 已提交
88 89 90
    }

    bindEvents() {
C
Clement Ho 已提交
91
      const filteredSearchInput = document.querySelector('.filtered-search');
C
Clement Ho 已提交
92

C
Clement Ho 已提交
93 94 95
      filteredSearchInput.addEventListener('input', this.processInput.bind(this));
      filteredSearchInput.addEventListener('input', toggleClearSearchButton);
      filteredSearchInput.addEventListener('keydown', this.checkForEnter.bind(this));
C
Clement Ho 已提交
96

C
Clement Ho 已提交
97
      document.querySelector('.clear-search').addEventListener('click', clearSearch);
C
Clement Ho 已提交
98 99
    }

C
Clement Ho 已提交
100 101
    processInput(e) {
      const input = e.target.value;
C
Clement Ho 已提交
102
      this.tokenizer.processTokens(input);
C
Clement Ho 已提交
103 104
    }

C
Clement Ho 已提交
105
    checkForEnter(e) {
C
Clement Ho 已提交
106
      // Enter KeyCode
C
Clement Ho 已提交
107 108 109
      if (e.keyCode === 13) {
        e.stopPropagation();
        e.preventDefault();
C
Clement Ho 已提交
110 111 112 113 114 115
        this.search();
      }
    }

    search() {
      console.log('search');
C
Clement Ho 已提交
116 117 118 119 120 121 122 123
      let path = '?scope=all&utf8=✓';

      // Check current state
      const currentPath = window.location.search;
      const stateIndex = currentPath.indexOf('state=');
      const defaultState = 'opened';
      let currentState = defaultState;

C
Clement Ho 已提交
124 125 126
      const tokens = this.tokenizer.getTokens();
      const searchToken = this.tokenizer.getSearchToken();

C
Clement Ho 已提交
127 128 129 130 131 132 133
      if (stateIndex !== -1) {
        const remaining = currentPath.slice(stateIndex + 6);
        const separatorIndex = remaining.indexOf('&');

        currentState = separatorIndex === -1 ? remaining : remaining.slice(0, separatorIndex);
      }

C
Clement Ho 已提交
134
      path += `&state=${currentState}`;
C
Clement Ho 已提交
135
      tokens.forEach((token) => {
C
Clement Ho 已提交
136
        const param = validTokenKeys.filter(t => t.key === token.key)[0].param;
C
Clement Ho 已提交
137
        path += `&${token.key}_${param}=${encodeURIComponent(token.value)}`;
C
Clement Ho 已提交
138 139
      });

C
Clement Ho 已提交
140 141
      if (searchToken) {
        path += `&search=${encodeURIComponent(searchToken)}`;
C
Clement Ho 已提交
142 143 144 145 146 147 148
      }

      window.location = path;
    }
  }

  global.FilteredSearchManager = FilteredSearchManager;
C
Clement Ho 已提交
149
})(window.gl || (window.gl = {}));