filtered_search_manager.js.es6 6.9 KB
Newer Older
C
Clement Ho 已提交
1
/* eslint-disable no-param-reassign */
C
Clement Ho 已提交
2
((global) => {
C
Clement Ho 已提交
3
  // TODO: Encapsulate inside class?
C
Clement Ho 已提交
4
  function toggleClearSearchButton(e) {
C
Clement Ho 已提交
5
    const clearSearchButton = document.querySelector('.clear-search');
C
Clement Ho 已提交
6

C
Clement Ho 已提交
7 8 9 10 11
    if (e.target.value) {
      clearSearchButton.classList.remove('hidden');
    } else {
      clearSearchButton.classList.add('hidden');
    }
C
Clement Ho 已提交
12 13 14 15 16 17 18 19 20 21 22 23 24
  }

  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 已提交
25
      // Check if it matches edge conditions listed in gl.FilteredSearchTokenKeys.get()
C
Clement Ho 已提交
26
      let conditionIndex = 0;
C
Clement Ho 已提交
27
      const validCondition = gl.FilteredSearchTokenKeys.get()
C
Clement Ho 已提交
28
        .filter(v => v.conditions && v.conditions.filter((c, index) => {
C
Clement Ho 已提交
29
          // Return TokenKeys that have conditions that much the URL
C
Clement Ho 已提交
30 31 32 33 34
          if (c.url === p) {
            conditionIndex = index;
          }
          return c.url === p;
        })[0])[0];
C
Clement Ho 已提交
35 36

      if (validCondition) {
C
Clement Ho 已提交
37
        // Parse params based on rules provided in the conditions key of gl.FilteredSearchTokenKeys.get()
C
Clement Ho 已提交
38
        inputValue += `${validCondition.key}:${validCondition.conditions[conditionIndex].keyword}`;
39
        inputValue += ' ';
C
Clement Ho 已提交
40 41 42
      } else {
        // Sanitize value since URL converts spaces into +
        // Replace before decode so that we know what was originally + versus the encoded +
C
Clement Ho 已提交
43
        const sanitizedValue = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : value;
C
Clement Ho 已提交
44
        const match = gl.FilteredSearchTokenKeys.get().filter(t => key === `${t.key}_${t.param}`)[0];
C
Clement Ho 已提交
45 46 47 48 49

        if (match) {
          const sanitizedKey = key.slice(0, key.indexOf('_'));
          const valueHasSpace = sanitizedValue.indexOf(' ') !== -1;
          const symbol = match.symbol;
C
Clement Ho 已提交
50
          let quotationsToUse;
C
Clement Ho 已提交
51 52 53

          if (valueHasSpace) {
            // Prefer ", but use ' if required
C
Clement Ho 已提交
54
            quotationsToUse = sanitizedValue.indexOf('"') === -1 ? '"' : '\'';
C
Clement Ho 已提交
55 56 57 58 59 60 61
          }

          inputValue += valueHasSpace ? `${sanitizedKey}:${symbol}${quotationsToUse}${sanitizedValue}${quotationsToUse}` : `${sanitizedKey}:${symbol}${sanitizedValue}`;
          inputValue += ' ';
        } else if (!match && key === 'search') {
          inputValue += sanitizedValue;
          inputValue += ' ';
C
Clement Ho 已提交
62 63 64 65 66 67 68 69 70 71 72
        }
      }
    });

    // 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 已提交
73 74 75

  class FilteredSearchManager {
    constructor() {
C
Clement Ho 已提交
76
      this.tokenizer = gl.FilteredSearchTokenizer;
C
Clement Ho 已提交
77 78
      this.filteredSearchInput = document.querySelector('.filtered-search');
      this.clearSearchButton = document.querySelector('.clear-search');
C
Clement Ho 已提交
79
      this.dropdownManager = new gl.FilteredSearchDropdownManager();
C
Clement Ho 已提交
80

C
Clement Ho 已提交
81
      this.bindEvents();
C
Clement Ho 已提交
82
      loadSearchParamsFromURL();
C
Clement Ho 已提交
83
      this.dropdownManager.setDropdown();
84

C
Clement Ho 已提交
85 86
      this.cleanupWrapper = this.cleanup.bind(this);
      document.addEventListener('page:fetch', this.cleanupWrapper);
87 88 89
    }

    cleanup() {
90
      this.unbindEvents();
C
Clement Ho 已提交
91 92
      document.removeEventListener('page:fetch', this.cleanupWrapper);
    }
93

C
Clement Ho 已提交
94
    bindEvents() {
C
Clement Ho 已提交
95
      this.setDropdownWrapper = this.dropdownManager.setDropdown.bind(this.dropdownManager);
96 97 98 99 100
      this.checkForEnterWrapper = this.checkForEnter.bind(this);
      this.clearSearchWrapper = this.clearSearch.bind(this);
      this.checkForBackspaceWrapper = this.checkForBackspace.bind(this);

      this.filteredSearchInput.addEventListener('input', this.setDropdownWrapper);
C
Clement Ho 已提交
101
      this.filteredSearchInput.addEventListener('input', toggleClearSearchButton);
102 103 104 105 106 107 108 109 110 111 112
      this.filteredSearchInput.addEventListener('keydown', this.checkForEnterWrapper);
      this.filteredSearchInput.addEventListener('keyup', this.checkForBackspaceWrapper);
      this.clearSearchButton.addEventListener('click', this.clearSearchWrapper);
    }

    unbindEvents() {
      this.filteredSearchInput.removeEventListener('input', this.setDropdownWrapper);
      this.filteredSearchInput.removeEventListener('input', toggleClearSearchButton);
      this.filteredSearchInput.removeEventListener('keydown', this.checkForEnterWrapper);
      this.filteredSearchInput.removeEventListener('keyup', this.checkForBackspaceWrapper);
      this.clearSearchButton.removeEventListener('click', this.clearSearchWrapper);
C
Clement Ho 已提交
113 114 115 116 117
    }

    clearSearch(e) {
      e.preventDefault();

C
Clement Ho 已提交
118 119
      this.filteredSearchInput.value = '';
      this.clearSearchButton.classList.add('hidden');
120

C
Clement Ho 已提交
121
      this.dropdownManager.resetDropdowns();
C
Clement Ho 已提交
122 123
    }

124
    checkForBackspace(e) {
C
Clement Ho 已提交
125 126 127
      // 8 = Backspace Key
      // 46 = Delete Key
      if (e.keyCode === 8 || e.keyCode === 46) {
128
        // Reposition dropdown so that it is aligned with cursor
C
Clement Ho 已提交
129
        this.dropdownManager.updateCurrentDropdownOffset();
130 131 132
      }
    }

C
Clement Ho 已提交
133 134 135
    checkForEnter(e) {
      if (e.keyCode === 13) {
        e.preventDefault();
136 137

        // Prevent droplab from opening dropdown
C
Clement Ho 已提交
138
        this.dropdownManager.destroyDroplab();
139

C
Clement Ho 已提交
140 141 142 143 144
        this.search();
      }
    }

    search() {
C
Clement Ho 已提交
145 146 147 148 149 150 151 152
      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 已提交
153
      const { tokens, searchToken } = this.tokenizer.processTokens(this.filteredSearchInput.value);
C
Clement Ho 已提交
154

C
Clement Ho 已提交
155
      if (stateIndex !== -1) {
C
Clement Ho 已提交
156 157
        // Get currentState from url params if available
        const remaining = currentPath.slice(stateIndex + 'state='.length);
C
Clement Ho 已提交
158 159 160 161 162
        const separatorIndex = remaining.indexOf('&');

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

C
Clement Ho 已提交
163
      path += `&state=${currentState}`;
C
Clement Ho 已提交
164
      tokens.forEach((token) => {
C
Clement Ho 已提交
165
        const match = gl.FilteredSearchTokenKeys.get().filter(t => t.key === token.key)[0];
C
Clement Ho 已提交
166 167 168
        let tokenPath = '';

        if (token.wildcard && match.conditions) {
C
Clement Ho 已提交
169 170
          const condition = match.conditions
            .filter(c => c.keyword === token.value.toLowerCase())[0];
C
Clement Ho 已提交
171 172 173 174 175 176 177 178 179 180 181 182

          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 已提交
183 184
      });

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

      window.location = path;
    }
  }

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