summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/filtered_search/dropdown_utils.js.es6
blob: eeab10fba17d4b25056fe4bf610bfa57f6a6e49b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
(() => {
  class DropdownUtils {
    static getEscapedText(text) {
      let escapedText = text;
      const hasSpace = text.indexOf(' ') !== -1;
      const hasDoubleQuote = text.indexOf('"') !== -1;

      // Encapsulate value with quotes if it has spaces
      // Known side effect: values's with both single and double quotes
      // won't escape properly
      if (hasSpace) {
        if (hasDoubleQuote) {
          escapedText = `'${text}'`;
        } else {
          // Encapsulate singleQuotes or if it hasSpace
          escapedText = `"${text}"`;
        }
      }

      return escapedText;
    }

    static filterWithSymbol(filterSymbol, input, item) {
      const updatedItem = item;
      const query = gl.DropdownUtils.getSearchInput(input);
      const { lastToken, searchToken } = gl.FilteredSearchTokenizer.processTokens(query);

      if (lastToken !== searchToken) {
        const title = updatedItem.title.toLowerCase();
        let value = lastToken.value.toLowerCase();
        value = value.replace(/"(.*?)"/g, str => str.slice(1).slice(0, -1));

        // Eg. filterSymbol = ~ for labels
        const matchWithoutSymbol = lastToken.symbol === filterSymbol && title.indexOf(value) !== -1;
        const match = title.indexOf(`${lastToken.symbol}${value}`) !== -1;

        updatedItem.droplab_hidden = !match && !matchWithoutSymbol;
      } else {
        updatedItem.droplab_hidden = false;
      }

      return updatedItem;
    }

    static filterHint(input, item) {
      const updatedItem = item;
      const query = gl.DropdownUtils.getSearchInput(input);
      let { lastToken } = gl.FilteredSearchTokenizer.processTokens(query);
      lastToken = lastToken.key || lastToken || '';

      if (!lastToken || query.split('').last() === ' ') {
        updatedItem.droplab_hidden = false;
      } else if (lastToken) {
        const split = lastToken.split(':');
        const tokenName = split[0].split(' ').last();

        const match = updatedItem.hint.indexOf(tokenName.toLowerCase()) === -1;
        updatedItem.droplab_hidden = tokenName ? match : false;
      }

      return updatedItem;
    }

    static setDataValueIfSelected(filter, selected) {
      const dataValue = selected.getAttribute('data-value');

      if (dataValue) {
        gl.FilteredSearchDropdownManager.addWordToInput(filter, dataValue);
      }

      // Return boolean based on whether it was set
      return dataValue !== null;
    }

    static getSearchInput(filteredSearchInput) {
      const inputValue = filteredSearchInput.value;
      const { right } = gl.DropdownUtils.getInputSelectionPosition(filteredSearchInput);

      return inputValue.slice(0, right);
    }

    static getInputSelectionPosition(input) {
      const selectionStart = input.selectionStart;
      let inputValue = input.value;
      // Replace all spaces inside quote marks with underscores
      // This helps with matching the beginning & end of a token:key
      inputValue = inputValue.replace(/("(.*?)"|:\s+)/g, str => str.replace(/\s/g, '_'));

      // Get the right position for the word selected
      // Regex matches first space
      let right = inputValue.slice(selectionStart).search(/\s/);

      if (right >= 0) {
        right += selectionStart;
      } else if (right < 0) {
        right = inputValue.length;
      }

      // Get the left position for the word selected
      // Regex matches last non-whitespace character
      let left = inputValue.slice(0, right).search(/\S+$/);

      if (selectionStart === 0) {
        left = 0;
      } else if (selectionStart === inputValue.length && left < 0) {
        left = inputValue.length;
      } else if (left < 0) {
        left = selectionStart;
      }

      return {
        left,
        right,
      };
    }
  }

  window.gl = window.gl || {};
  gl.DropdownUtils = DropdownUtils;
})();