filtered_search_manager.js.es6 9.0 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 95 96
    static addWordToInput(word, addSpace) {
      const hasExistingValue = document.querySelector('.filtered-search').value.length !== 0;
      document.querySelector('.filtered-search').value += hasExistingValue && addSpace ? ` ${word}` : word;
97 98
    }

99
    loadDropdown(dropdownName = '') {
100 101
      dropdownName = dropdownName.toLowerCase();

102
      const filterIconPadding = 27;
103
      const match = gl.FilteredSearchTokenKeys.get().filter(value => value.key === dropdownName)[0];
104
      const filteredSearch = document.querySelector('.filtered-search');
105

106
      if (match && this.currentDropdown !== match.key) {
107
        console.log(`🦄 load ${match.key} dropdown`);
108 109 110 111

        const dynamicDropdownPadding = 12;
        const dropdownOffset = gl.text.getTextWidth(filteredSearch.value) + filterIconPadding + dynamicDropdownPadding;

C
Clement Ho 已提交
112
        this.dismissCurrentDropdown();
113
        this.currentDropdown = match.key;
C
Clement Ho 已提交
114

C
Clement Ho 已提交
115 116
        if (match.key === 'author') {
          if (!dropdownAuthor) {
117
            dropdownAuthor = new gl.DropdownAuthor(document.querySelector('#js-dropdown-author'), filteredSearch);
C
Clement Ho 已提交
118
          }
C
Clement Ho 已提交
119

120
          dropdownAuthor.setOffset(dropdownOffset);
C
Clement Ho 已提交
121 122 123
          dropdownAuthor.render();
        } else if (match.key === 'assignee') {
          if (!dropdownAssignee) {
124
            dropdownAssignee = new gl.DropdownAssignee(document.querySelector('#js-dropdown-assignee'), filteredSearch);
C
Clement Ho 已提交
125 126
          }

127
          dropdownAssignee.setOffset(dropdownOffset);
C
Clement Ho 已提交
128
          dropdownAssignee.render();
C
Clement Ho 已提交
129 130
        } else if (match.key === 'milestone') {
          if (!dropdownMilestone) {
131
            dropdownMilestone = new gl.DropdownMilestone(document.querySelector('#js-dropdown-milestone'), filteredSearch);
C
Clement Ho 已提交
132 133
          }

134
          dropdownMilestone.setOffset(dropdownOffset);
C
Clement Ho 已提交
135 136 137
          dropdownMilestone.render();
        } else if (match.key === 'label') {
          if (!dropdownLabel) {
138
            dropdownLabel = new gl.DropdownLabel(document.querySelector('#js-dropdown-label'), filteredSearch);
C
Clement Ho 已提交
139 140
          }

141
          dropdownLabel.setOffset(dropdownOffset);
C
Clement Ho 已提交
142
          dropdownLabel.render();
C
Clement Ho 已提交
143 144
        }

145 146
      } else if (!match && this.currentDropdown !== 'hint') {
        console.log('🦄 load hint dropdown');
147 148 149

        const dropdownOffset = gl.text.getTextWidth(filteredSearch.value) + filterIconPadding;

C
Clement Ho 已提交
150
        this.dismissCurrentDropdown();
151 152 153
        this.currentDropdown = 'hint';

        if (!dropdownHint) {
154
          dropdownHint = new gl.DropdownHint(document.querySelector('#js-dropdown-hint'), filteredSearch, this.currentDropdown);
155
        }
156
        dropdownHint.setOffset(dropdownOffset);
157 158 159 160
        dropdownHint.render();
      }
    }

C
Clement Ho 已提交
161 162
    dismissCurrentDropdown() {
      if (this.currentDropdown === 'hint') {
163
        dropdownHint.destroy();
C
Clement Ho 已提交
164 165 166
      }
    }

167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
    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');
182 183 184
      }
    }

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

188
      filteredSearchInput.addEventListener('input', this.setDropdown.bind(this));
C
Clement Ho 已提交
189 190 191
      filteredSearchInput.addEventListener('input', toggleClearSearchButton);
      filteredSearchInput.addEventListener('keydown', this.checkForEnter.bind(this));
      document.querySelector('.clear-search').addEventListener('click', clearSearch);
C
Clement Ho 已提交
192 193
    }

194
    checkDropdownToken(e) {
C
Clement Ho 已提交
195
      const input = e.target.value;
196 197 198 199 200 201 202
      const { lastToken } = this.tokenizer.processTokens(input);

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

      }
C
Clement Ho 已提交
203 204
    }

C
Clement Ho 已提交
205
    checkForEnter(e) {
C
Clement Ho 已提交
206
      // Enter KeyCode
C
Clement Ho 已提交
207 208 209
      if (e.keyCode === 13) {
        e.stopPropagation();
        e.preventDefault();
C
Clement Ho 已提交
210 211 212 213 214 215
        this.search();
      }
    }

    search() {
      console.log('search');
C
Clement Ho 已提交
216 217 218 219 220 221 222 223
      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 已提交
224
      const { tokens, searchToken } = this.tokenizer.processTokens(document.querySelector('.filtered-search').value);
C
Clement Ho 已提交
225

C
Clement Ho 已提交
226 227 228 229 230 231 232
      if (stateIndex !== -1) {
        const remaining = currentPath.slice(stateIndex + 6);
        const separatorIndex = remaining.indexOf('&');

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

C
Clement Ho 已提交
233
      path += `&state=${currentState}`;
C
Clement Ho 已提交
234
      tokens.forEach((token) => {
C
Clement Ho 已提交
235
        const match = gl.FilteredSearchTokenKeys.get().filter(t => t.key === token.key)[0];
C
Clement Ho 已提交
236 237 238
        let tokenPath = '';

        if (token.wildcard && match.conditions) {
C
Clement Ho 已提交
239 240
          const condition = match.conditions
            .filter(c => c.keyword === token.value.toLowerCase())[0];
C
Clement Ho 已提交
241 242 243 244 245 246 247 248 249 250 251 252

          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 已提交
253 254
      });

C
Clement Ho 已提交
255 256
      if (searchToken) {
        path += `&search=${encodeURIComponent(searchToken)}`;
C
Clement Ho 已提交
257 258 259 260 261 262 263
      }

      window.location = path;
    }
  }

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