handleInputVisualToken()

in app/assets/javascripts/filtered_search/filtered_search_manager.js [414:515]


  handleInputVisualToken(e) {
    // If the keyCode was 8 then do not form new tokens
    if (e.keyCode === BACKSPACE_KEY_CODE) {
      return;
    }

    const input = this.filteredSearchInput;
    const { tokens, searchToken } = this.tokenizer.processTokens(
      input.value,
      this.filteredSearchTokenKeys.getKeys(),
    );
    const { isLastVisualTokenValid } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();

    if (isLastVisualTokenValid) {
      tokens.forEach(t => {
        input.value = input.value.replace(`${t.key}:${t.operator}${t.symbol}${t.value}`, '');

        FilteredSearchVisualTokens.addFilterVisualToken(
          t.key,
          t.operator,
          `${t.symbol}${t.value}`,
          {
            uppercaseTokenName: this.filteredSearchTokenKeys.shouldUppercaseTokenName(t.key),
            capitalizeTokenValue: this.filteredSearchTokenKeys.shouldCapitalizeTokenValue(t.key),
          },
        );
      });

      const fragments = searchToken.split(':');

      if (fragments.length > 1) {
        const inputValues = fragments[0].split(' ');
        const tokenKey = _.last(inputValues);

        if (inputValues.length > 1) {
          inputValues.pop();
          const searchTerms = inputValues.join(' ');

          input.value = input.value.replace(searchTerms, '');
          FilteredSearchVisualTokens.addSearchVisualToken(searchTerms);
        }

        FilteredSearchVisualTokens.addFilterVisualToken(tokenKey, null, null, {
          uppercaseTokenName: this.filteredSearchTokenKeys.shouldUppercaseTokenName(tokenKey),
          capitalizeTokenValue: this.filteredSearchTokenKeys.shouldCapitalizeTokenValue(tokenKey),
        });
        input.value = input.value.replace(`${tokenKey}:`, '');
      }

      const splitSearchToken = searchToken && searchToken.split(' ');
      let lastSearchToken = _.last(splitSearchToken);
      lastSearchToken = lastSearchToken?.toLowerCase();

      /**
       * If user writes "milestone", a known token, in the input, we should not
       * wait for leading colon to flush it as a filter token.
       */
      if (this.filteredSearchTokenKeys.getKeys().includes(lastSearchToken)) {
        if (splitSearchToken.length > 1) {
          splitSearchToken.pop();
          const searchVisualTokens = splitSearchToken.join(' ');

          input.value = input.value.replace(searchVisualTokens, '');
          FilteredSearchVisualTokens.addSearchVisualToken(searchVisualTokens);
        }
        FilteredSearchVisualTokens.addFilterVisualToken(lastSearchToken, null, null, {
          uppercaseTokenName: this.filteredSearchTokenKeys.shouldUppercaseTokenName(
            lastSearchToken,
          ),
          capitalizeTokenValue: this.filteredSearchTokenKeys.shouldCapitalizeTokenValue(
            lastSearchToken,
          ),
        });
        input.value = input.value.replace(lastSearchToken, '');
      }
    } else if (!isLastVisualTokenValid && !FilteredSearchVisualTokens.getLastTokenOperator()) {
      const tokenKey = FilteredSearchVisualTokens.getLastTokenPartial();
      const tokenOperator = searchToken && searchToken.trim();

      // Tokenize operator only if the operator token is valid
      if (FilteredSearchVisualTokens.permissibleOperatorValues.includes(tokenOperator)) {
        FilteredSearchVisualTokens.removeLastTokenPartial();
        FilteredSearchVisualTokens.addFilterVisualToken(tokenKey, tokenOperator, null, {
          capitalizeTokenValue: this.filteredSearchTokenKeys.shouldCapitalizeTokenValue(tokenKey),
        });
        input.value = input.value.replace(searchToken, '').trim();
      }
    } else {
      // Keep listening to token until we determine that the user is done typing the token value
      const valueCompletedRegex = /([~%@]{0,1}".+")|([~%@]{0,1}'.+')|^((?![~%@]')(?![~%@]")(?!')(?!")).*/g;

      if (searchToken.match(valueCompletedRegex) && input.value[input.value.length - 1] === ' ') {
        const tokenKey = FilteredSearchVisualTokens.getLastTokenPartial();
        FilteredSearchVisualTokens.addFilterVisualToken(searchToken, null, null, {
          capitalizeTokenValue: this.filteredSearchTokenKeys.shouldCapitalizeTokenValue(tokenKey),
        });

        // Trim the last space as seen in the if statement above
        input.value = input.value.replace(searchToken, '').trim();
      }
    }
  }