filtered_search_manager.js.es6 9.6 KB
Newer Older
C
Clement Ho 已提交
1
/* eslint-disable no-param-reassign */
C
Clement Ho 已提交
2
((global) => {
C
Clement Ho 已提交
3 4 5
  function clearSearch(e) {
    e.stopPropagation();
    e.preventDefault();
C
Clement Ho 已提交
6 7 8 9 10

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

C
Clement Ho 已提交
11
  function toggleClearSearchButton(e) {
C
Clement Ho 已提交
12
    const clearSearchButton = document.querySelector('.clear-search');
C
Clement Ho 已提交
13

C
Clement Ho 已提交
14 15 16 17 18
    if (e.target.value) {
      clearSearchButton.classList.remove('hidden');
    } else {
      clearSearchButton.classList.add('hidden');
    }
C
Clement Ho 已提交
19 20 21 22 23 24 25 26 27 28 29 30 31
  }

  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 已提交
32
      // Check if it matches edge conditions listed in gl.FilteredSearchTokenKeys.get()
C
Clement Ho 已提交
33
      let conditionIndex = 0;
C
Clement Ho 已提交
34
      const validCondition = gl.FilteredSearchTokenKeys.get()
C
Clement Ho 已提交
35 36 37 38 39 40
        .filter(v => v.conditions && v.conditions.filter((c, index) => {
          if (c.url === p) {
            conditionIndex = index;
          }
          return c.url === p;
        })[0])[0];
C
Clement Ho 已提交
41 42 43 44 45 46 47

      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;
C
Clement Ho 已提交
48
        const match = gl.FilteredSearchTokenKeys.get().filter(t => key === `${t.key}_${t.param}`)[0];
C
Clement Ho 已提交
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67

        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 已提交
68 69 70 71 72 73 74 75 76 77 78
        }
      }
    });

    // 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 已提交
79

80
  let dropdownHint;
C
Clement Ho 已提交
81
  let dropdownAuthor;
C
Clement Ho 已提交
82
  let dropdownAssignee;
C
Clement Ho 已提交
83 84
  let dropdownMilestone;
  let dropdownLabel;
85

C
Clement Ho 已提交
86 87
  class FilteredSearchManager {
    constructor() {
C
Clement Ho 已提交
88
      this.tokenizer = gl.FilteredSearchTokenizer;
C
Clement Ho 已提交
89
      this.bindEvents();
C
Clement Ho 已提交
90
      loadSearchParamsFromURL();
91
      this.setDropdown();
C
Clement Ho 已提交
92 93
    }

94
    static addWordToInput(word, addSpace) {
95 96 97 98 99
      const filteredSearchValue = document.querySelector('.filtered-search').value;
      const hasExistingValue = filteredSearchValue.length !== 0;

      const { lastToken } = gl.FilteredSearchTokenizer.processTokens(filteredSearchValue);
      if (lastToken.hasOwnProperty('key')) {
100 101 102 103 104 105
        console.log(lastToken);
        // Spaces inside the token means that the token value will be escaped by quotes
        const hasQuotes = lastToken.value.indexOf(' ') !== -1;

        const lengthToRemove = hasQuotes ? lastToken.value.length + 2 : lastToken.value.length;
        document.querySelector('.filtered-search').value = filteredSearchValue.slice(0, -1 * (lengthToRemove));
106 107
      }

108
      document.querySelector('.filtered-search').value += hasExistingValue && addSpace ? ` ${word}` : word;
109 110
    }

111
    loadDropdown(dropdownName = '', hideDropdown) {
112 113
      dropdownName = dropdownName.toLowerCase();

114
      const filterIconPadding = 27;
115
      const match = gl.FilteredSearchTokenKeys.get().filter(value => value.key === dropdownName)[0];
116
      const filteredSearch = document.querySelector('.filtered-search');
117

118 119 120 121
      if (!this.font) {
        this.font = window.getComputedStyle(filteredSearch).font;
      }

122
      if (match && this.currentDropdown !== match.key) {
123
        console.log(`🦄 load ${match.key} dropdown`);
124 125

        const dynamicDropdownPadding = 12;
126
        const dropdownOffset = gl.text.getTextWidth(filteredSearch.value, this.font) + filterIconPadding + dynamicDropdownPadding;
127

C
Clement Ho 已提交
128
        this.dismissCurrentDropdown();
129
        this.currentDropdown = match.key;
C
Clement Ho 已提交
130

C
Clement Ho 已提交
131 132
        if (match.key === 'author') {
          if (!dropdownAuthor) {
133
            dropdownAuthor = new gl.DropdownAuthor(document.querySelector('#js-dropdown-author'), filteredSearch);
C
Clement Ho 已提交
134
          }
C
Clement Ho 已提交
135

136
          dropdownAuthor.setOffset(dropdownOffset);
C
Clement Ho 已提交
137 138 139
          dropdownAuthor.render();
        } else if (match.key === 'assignee') {
          if (!dropdownAssignee) {
140
            dropdownAssignee = new gl.DropdownAssignee(document.querySelector('#js-dropdown-assignee'), filteredSearch);
C
Clement Ho 已提交
141 142
          }

143
          dropdownAssignee.setOffset(dropdownOffset);
C
Clement Ho 已提交
144
          dropdownAssignee.render();
C
Clement Ho 已提交
145 146
        } else if (match.key === 'milestone') {
          if (!dropdownMilestone) {
147
            dropdownMilestone = new gl.DropdownMilestone(document.querySelector('#js-dropdown-milestone'), filteredSearch);
C
Clement Ho 已提交
148 149
          }

150
          dropdownMilestone.setOffset(dropdownOffset);
C
Clement Ho 已提交
151 152 153
          dropdownMilestone.render();
        } else if (match.key === 'label') {
          if (!dropdownLabel) {
154
            dropdownLabel = new gl.DropdownLabel(document.querySelector('#js-dropdown-label'), filteredSearch);
C
Clement Ho 已提交
155 156
          }

157
          dropdownLabel.setOffset(dropdownOffset);
C
Clement Ho 已提交
158
          dropdownLabel.render();
C
Clement Ho 已提交
159 160
        }

161 162
      } else if (!match && this.currentDropdown !== 'hint') {
        console.log('🦄 load hint dropdown');
163

164 165 166
        const dropdownOffset = gl.text.getTextWidth(filteredSearch.value, this.font) + filterIconPadding;
        console.log(dropdownOffset)
        this.dismissCurrentDropdown();
167 168 169
        this.currentDropdown = 'hint';

        if (!dropdownHint) {
170
          dropdownHint = new gl.DropdownHint(document.querySelector('#js-dropdown-hint'), filteredSearch, this.currentDropdown);
171
        }
172
        dropdownHint.setOffset(dropdownOffset);
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
        dropdownHint.render();
      }
    }

    setDropdown() {
      const { lastToken } = this.tokenizer.processTokens(document.querySelector('.filtered-search').value);

      if (typeof lastToken === 'string') {
        // Token is not fully initialized yet
        // because it has no value
        // Eg. token = 'label:'
        const { tokenKey } = this.tokenizer.parseToken(lastToken);
        this.loadDropdown(tokenKey);
      } else if (lastToken.hasOwnProperty('key')) {
        // Token has been initialized into an object
        // because it has a value
        this.loadDropdown(lastToken.key);
      } else {
        this.loadDropdown('hint');
192 193 194
      }
    }

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

198
      filteredSearchInput.addEventListener('input', this.setDropdown.bind(this));
C
Clement Ho 已提交
199 200 201
      filteredSearchInput.addEventListener('input', toggleClearSearchButton);
      filteredSearchInput.addEventListener('keydown', this.checkForEnter.bind(this));
      document.querySelector('.clear-search').addEventListener('click', clearSearch);
C
Clement Ho 已提交
202 203
    }

204
    checkDropdownToken(e) {
C
Clement Ho 已提交
205
      const input = e.target.value;
206 207 208 209 210 211 212
      const { lastToken } = this.tokenizer.processTokens(input);

      // Check for dropdown token
      if (lastToken[lastToken.length - 1] === ':') {
        const token = lastToken.slice(0, -1);

      }
C
Clement Ho 已提交
213 214
    }

C
Clement Ho 已提交
215
    checkForEnter(e) {
C
Clement Ho 已提交
216
      // Enter KeyCode
C
Clement Ho 已提交
217 218 219
      if (e.keyCode === 13) {
        e.stopPropagation();
        e.preventDefault();
C
Clement Ho 已提交
220 221 222 223 224 225
        this.search();
      }
    }

    search() {
      console.log('search');
C
Clement Ho 已提交
226 227 228 229 230 231 232 233
      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 已提交
234
      const { tokens, searchToken } = this.tokenizer.processTokens(document.querySelector('.filtered-search').value);
C
Clement Ho 已提交
235

C
Clement Ho 已提交
236 237 238 239 240 241 242
      if (stateIndex !== -1) {
        const remaining = currentPath.slice(stateIndex + 6);
        const separatorIndex = remaining.indexOf('&');

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

C
Clement Ho 已提交
243
      path += `&state=${currentState}`;
C
Clement Ho 已提交
244
      tokens.forEach((token) => {
C
Clement Ho 已提交
245
        const match = gl.FilteredSearchTokenKeys.get().filter(t => t.key === token.key)[0];
C
Clement Ho 已提交
246 247 248
        let tokenPath = '';

        if (token.wildcard && match.conditions) {
C
Clement Ho 已提交
249 250
          const condition = match.conditions
            .filter(c => c.keyword === token.value.toLowerCase())[0];
C
Clement Ho 已提交
251 252 253 254 255 256 257 258 259 260 261 262

          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 已提交
263 264
      });

C
Clement Ho 已提交
265 266
      if (searchToken) {
        path += `&search=${encodeURIComponent(searchToken)}`;
C
Clement Ho 已提交
267 268 269 270 271 272 273
      }

      window.location = path;
    }
  }

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