From 8ecc2117db3a38961785fcaa4b49bd6de13371d4 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Wed, 30 Nov 2016 12:30:52 -0600 Subject: [PATCH] Refactor validTokenKeys --- .../filtered_search_manager.js.es6 | 51 +++------------- .../filtered_search_token_keys.js.es6 | 45 ++++++++++++++ .../filtered_search_tokenizer.es6 | 60 +++++++++---------- 3 files changed, 81 insertions(+), 75 deletions(-) create mode 100644 app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6 diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 index 8568bf78416..3899181a352 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 @@ -1,42 +1,5 @@ /* eslint-disable no-param-reassign */ ((global) => { - const validTokenKeys = [{ - key: 'author', - type: 'string', - param: 'username', - symbol: '@', - }, { - key: 'assignee', - type: 'string', - param: 'username', - symbol: '@', - conditions: [{ - keyword: 'none', - url: 'assignee_id=0', - }], - }, { - key: 'milestone', - type: 'string', - param: 'title', - symbol: '%', - conditions: [{ - keyword: 'none', - url: 'milestone_title=No+Milestone', - }, { - keyword: 'upcoming', - url: 'milestone_title=%23upcoming', - }], - }, { - key: 'label', - type: 'array', - param: 'name[]', - symbol: '~', - conditions: [{ - keyword: 'none', - url: 'label_name[]=No+Label', - }], - }]; - function clearSearch(e) { e.stopPropagation(); e.preventDefault(); @@ -66,9 +29,9 @@ const key = decodeURIComponent(split[0]); const value = split[1]; - // Check if it matches edge conditions listed in validTokenKeys + // Check if it matches edge conditions listed in gl.FilteredSearchTokenKeys.get() let conditionIndex = 0; - const validCondition = validTokenKeys + const validCondition = gl.FilteredSearchTokenKeys.get() .filter(v => v.conditions && v.conditions.filter((c, index) => { if (c.url === p) { conditionIndex = index; @@ -82,7 +45,7 @@ // 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; - const match = validTokenKeys.filter(t => key === `${t.key}_${t.param}`)[0]; + const match = gl.FilteredSearchTokenKeys.get().filter(t => key === `${t.key}_${t.param}`)[0]; if (match) { const sanitizedKey = key.slice(0, key.indexOf('_')); @@ -116,7 +79,7 @@ class FilteredSearchManager { constructor() { - this.tokenizer = new gl.FilteredSearchTokenizer(validTokenKeys); + this.tokenizer = gl.FilteredSearchTokenizer; this.bindEvents(); loadSearchParamsFromURL(); } @@ -131,6 +94,7 @@ document.querySelector('.clear-search').addEventListener('click', clearSearch); } + // TODO: This is only used for testing, remove when going to PRO processInput(e) { const input = e.target.value; this.tokenizer.processTokens(input); @@ -155,8 +119,7 @@ const defaultState = 'opened'; let currentState = defaultState; - const tokens = this.tokenizer.getTokens(); - const searchToken = this.tokenizer.getSearchToken(); + const { tokens, searchToken } = this.tokenizer.processTokens(document.querySelector('.filtered-search').value); if (stateIndex !== -1) { const remaining = currentPath.slice(stateIndex + 6); @@ -167,7 +130,7 @@ path += `&state=${currentState}`; tokens.forEach((token) => { - const match = validTokenKeys.filter(t => t.key === token.key)[0]; + const match = gl.FilteredSearchTokenKeys.get().filter(t => t.key === token.key)[0]; let tokenPath = ''; if (token.wildcard && match.conditions) { diff --git a/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6 new file mode 100644 index 00000000000..8d38a29a354 --- /dev/null +++ b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6 @@ -0,0 +1,45 @@ +/* eslint-disable no-param-reassign */ +((global) => { + class FilteredSearchTokenKeys { + static get() { + return [{ + key: 'author', + type: 'string', + param: 'username', + symbol: '@', + }, { + key: 'assignee', + type: 'string', + param: 'username', + symbol: '@', + conditions: [{ + keyword: 'none', + url: 'assignee_id=0', + }], + }, { + key: 'milestone', + type: 'string', + param: 'title', + symbol: '%', + conditions: [{ + keyword: 'none', + url: 'milestone_title=No+Milestone', + }, { + keyword: 'upcoming', + url: 'milestone_title=%23upcoming', + }], + }, { + key: 'label', + type: 'array', + param: 'name[]', + symbol: '~', + conditions: [{ + keyword: 'none', + url: 'label_name[]=No+Label', + }], + }]; + } + } + + global.FilteredSearchTokenKeys = FilteredSearchTokenKeys; +})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.es6 b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.es6 index eab805c4714..b1f37443aa1 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.es6 @@ -1,33 +1,20 @@ /* eslint-disable no-param-reassign */ ((global) => { class FilteredSearchTokenizer { - constructor(validTokenKeys) { - this.validTokenKeys = validTokenKeys; - this.resetTokens(); - } - - getTokens() { - return this.tokens; - } - - getSearchToken() { - return this.searchToken; - } - - resetTokens() { - this.tokens = []; - this.searchToken = ''; - } - - printTokens() { + // TODO: Remove when going to pro + static printTokens(tokens, searchToken, lastToken) { console.log('tokens:'); - this.tokens.forEach(token => console.log(token)); - console.log(`search: ${this.searchToken}`); + tokens.forEach(token => console.log(token)); + console.log(`search: ${searchToken}`); + console.log('last token:'); + console.log(lastToken); } - processTokens(input) { - // Re-calculate tokens - this.resetTokens(); + static processTokens(input) { + let tokens = []; + let searchToken = ''; + let lastToken = ''; + const validTokenKeys = gl.FilteredSearchTokenKeys.get(); const inputs = input.split(' '); let searchTerms = ''; @@ -36,16 +23,17 @@ inputs.forEach((i) => { if (incompleteToken) { - const prevToken = this.tokens.last(); + const prevToken = tokens.last(); prevToken.value += ` ${i}`; // Remove last quotation const lastQuotationRegex = new RegExp(lastQuotation, 'g'); prevToken.value = prevToken.value.replace(lastQuotationRegex, ''); - this.tokens[this.tokens.length - 1] = prevToken; + tokens[tokens.length - 1] = prevToken; // Check to see if this quotation completes the token value if (i.indexOf(lastQuotation)) { + lastToken = tokens.last(); incompleteToken = !incompleteToken; } @@ -59,8 +47,8 @@ const tokenValue = i.slice(colonIndex + 1); const tokenSymbol = tokenValue[0]; console.log(tokenSymbol) - const keyMatch = this.validTokenKeys.filter(v => v.key === tokenKey)[0]; - const symbolMatch = this.validTokenKeys.filter(v => v.symbol === tokenSymbol)[0]; + const keyMatch = validTokenKeys.filter(v => v.key === tokenKey)[0]; + const symbolMatch = validTokenKeys.filter(v => v.symbol === tokenSymbol)[0]; const doubleQuoteIndex = tokenValue.indexOf('"'); const singleQuoteIndex = tokenValue.indexOf('\''); @@ -81,11 +69,12 @@ } if (keyMatch && tokenValue.length > 0) { - this.tokens.push({ + tokens.push({ key: keyMatch.key, value: tokenValue, wildcard: symbolMatch ? false : true, }); + lastToken = tokens.last(); return; } @@ -93,10 +82,19 @@ // Add space for next term searchTerms += `${i} `; + lastToken = i; }, this); - this.searchToken = searchTerms.trim(); - this.printTokens(); + searchToken = searchTerms.trim(); + + // TODO: Remove when going to PRO + gl.FilteredSearchTokenizer.printTokens(tokens, searchToken, lastToken); + + return { + tokens, + searchToken, + lastToken, + }; } }