filtered_search_manager.js.es6 5.9 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
    symbol: '@',
C
Clement Ho 已提交
8
  }, {
C
Clement Ho 已提交
9
    key: 'assignee',
C
Clement Ho 已提交
10
    type: 'string',
11
    param: 'username',
C
Clement Ho 已提交
12 13 14 15 16
    symbol: '@',
    conditions: [{
      keyword: 'none',
      url: 'assignee_id=0',
    }]
C
Clement Ho 已提交
17
  }, {
C
Clement Ho 已提交
18
    key: 'milestone',
C
Clement Ho 已提交
19 20
    type: 'string',
    param: 'title',
C
Clement Ho 已提交
21 22 23 24 25 26 27 28
    symbol: '%',
    conditions: [{
      keyword: 'none',
      url: 'milestone_title=No+Milestone',
    }, {
      keyword: 'upcoming',
      url: 'milestone_title=%23upcoming',
    }]
C
Clement Ho 已提交
29
  }, {
C
Clement Ho 已提交
30
    key: 'label',
C
Clement Ho 已提交
31
    type: 'array',
C
Clement Ho 已提交
32
    param: 'name[]',
C
Clement Ho 已提交
33 34 35 36 37
    symbol: '~',
    conditions: [{
      keyword: 'none',
      url: 'label_name[]=No+Label',
    }]
C
Clement Ho 已提交
38 39
  }];

C
Clement Ho 已提交
40 41 42
  function clearSearch(e) {
    e.stopPropagation();
    e.preventDefault();
C
Clement Ho 已提交
43 44 45 46 47

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

C
Clement Ho 已提交
48
  function toggleClearSearchButton(e) {
C
Clement Ho 已提交
49
    const clearSearchButton = document.querySelector('.clear-search');
C
Clement Ho 已提交
50 51

    if (event.target.value) {
C
Clement Ho 已提交
52 53 54 55
       clearSearchButton.classList.remove('hidden');
     } else {
       clearSearchButton.classList.add('hidden');
     }
C
Clement Ho 已提交
56 57 58 59 60 61 62 63 64 65 66 67 68
  }

  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];

C
Clement Ho 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
      // Check if it matches edge conditions listed in validTokenKeys
      let conditionIndex = 0;
      const validCondition = validTokenKeys.filter(v => v.conditions && v.conditions.filter((c, index) => {
        if (c.url === p) {
          conditionIndex = index;
        }
        return c.url === p;
      })[0])[0];

      if (validCondition) {
        inputValue += `${validCondition.key}:${validCondition.conditions[conditionIndex].keyword}`;
      } else {
        // 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;
        const match = validTokenKeys.filter(t => key === `${t.key}_${t.param}`)[0];

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

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

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

          inputValue += valueHasSpace ? `${sanitizedKey}:${symbol}${quotationsToUse}${sanitizedValue}${quotationsToUse}` : `${sanitizedKey}:${symbol}${sanitizedValue}`;
          inputValue += ' ';
        } else if (!match && key === 'search') {
          inputValue += sanitizedValue;
          inputValue += ' ';
C
Clement Ho 已提交
104 105 106 107 108 109 110 111 112 113 114
        }
      }
    });

    // 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 已提交
115 116 117

  class FilteredSearchManager {
    constructor() {
C
Clement Ho 已提交
118
      this.tokenizer = new gl.FilteredSearchTokenizer(validTokenKeys);
C
Clement Ho 已提交
119
      this.bindEvents();
C
Clement Ho 已提交
120
      loadSearchParamsFromURL();
C
Clement Ho 已提交
121 122 123
    }

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

C
Clement Ho 已提交
126 127 128
      filteredSearchInput.addEventListener('input', this.processInput.bind(this));
      filteredSearchInput.addEventListener('input', toggleClearSearchButton);
      filteredSearchInput.addEventListener('keydown', this.checkForEnter.bind(this));
C
Clement Ho 已提交
129

C
Clement Ho 已提交
130
      document.querySelector('.clear-search').addEventListener('click', clearSearch);
C
Clement Ho 已提交
131 132
    }

C
Clement Ho 已提交
133 134
    processInput(e) {
      const input = e.target.value;
C
Clement Ho 已提交
135
      this.tokenizer.processTokens(input);
C
Clement Ho 已提交
136 137
    }

C
Clement Ho 已提交
138
    checkForEnter(e) {
C
Clement Ho 已提交
139
      // Enter KeyCode
C
Clement Ho 已提交
140 141 142
      if (e.keyCode === 13) {
        e.stopPropagation();
        e.preventDefault();
C
Clement Ho 已提交
143 144 145 146 147 148
        this.search();
      }
    }

    search() {
      console.log('search');
C
Clement Ho 已提交
149 150 151 152 153 154 155 156
      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 已提交
157 158 159
      const tokens = this.tokenizer.getTokens();
      const searchToken = this.tokenizer.getSearchToken();

C
Clement Ho 已提交
160 161 162 163 164 165 166
      if (stateIndex !== -1) {
        const remaining = currentPath.slice(stateIndex + 6);
        const separatorIndex = remaining.indexOf('&');

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

C
Clement Ho 已提交
167
      path += `&state=${currentState}`;
C
Clement Ho 已提交
168
      tokens.forEach((token) => {
C
Clement Ho 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
        const match = validTokenKeys.filter(t => t.key === token.key)[0];
        let tokenPath = '';

        if (token.wildcard && match.conditions) {
          const condition = match.conditions.filter(c => c.keyword === token.value.toLowerCase())[0];

          if (condition) {
            tokenPath = `${condition.url}`;
          }
        } else if (!token.wildcard) {
          // Remove the wildcard token
          tokenPath = `${token.key}_${match.param}=${encodeURIComponent(token.value.slice(1))}`;
        } else {
          tokenPath = `${token.key}_${match.param}=${encodeURIComponent(token.value)}`;
        }

        path += `&${tokenPath}`;
C
Clement Ho 已提交
186 187
      });

C
Clement Ho 已提交
188 189
      if (searchToken) {
        path += `&search=${encodeURIComponent(searchToken)}`;
C
Clement Ho 已提交
190 191 192 193 194 195 196
      }

      window.location = path;
    }
  }

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