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();
}
}
}