From 64d46a3e80001c2dc13f6fd04e2abac40ee9d093 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Wed, 30 Nov 2016 15:18:17 -0600 Subject: [PATCH] Add logic for dynamically selecting which dropdown to load [skip ci] --- .../filtered_search_manager.js.es6 | 55 +++++++++++++++---- .../filtered_search_tokenizer.es6 | 35 +++++++++--- .../shared/issuable/_search_bar.html.haml | 2 +- 3 files changed, 72 insertions(+), 20 deletions(-) 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 09a7779635f..8903f382c18 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 @@ -77,42 +77,77 @@ } } + let dropdownHint; + class FilteredSearchManager { constructor() { this.tokenizer = gl.FilteredSearchTokenizer; this.bindEvents(); loadSearchParamsFromURL(); + this.setDropdown(); } - static fillInWord(word) { - const originalValue = document.querySelector('.filtered-search').value; - document.querySelector('.filtered-search').value = `${originalValue} ${word.trim()}`; + static addWordToInput(word, addSpace) { + const hasExistingValue = document.querySelector('.filtered-search').value.length !== 0; + document.querySelector('.filtered-search').value += hasExistingValue && addSpace ? ` ${word}` : word; } - static loadDropdown(dropdownName) { + loadDropdown(dropdownName = '') { dropdownName = dropdownName.toLowerCase(); const match = gl.FilteredSearchTokenKeys.get().filter(value => value.key === dropdownName)[0]; - if (match) { + if (match && this.currentDropdown !== match.key) { console.log(`🦄 load ${match.key} dropdown`); + this.currentDropdown = match.key; + } else if (!match && this.currentDropdown !== 'hint') { + console.log('🦄 load hint dropdown'); + this.currentDropdown = 'hint'; + + if (!dropdownHint) { + dropdownHint = new gl.DropdownHint(document.querySelector('#js-dropdown-hint'), document.querySelector('.filtered-search')) + } + + dropdownHint.render(); + } + } + + setDropdown() { + const { lastToken } = this.tokenizer.processTokens(document.querySelector('.filtered-search').value); + + if (typeof lastToken === 'string') { + // Token is not fully initialized yet + // because it has no value + // Eg. token = 'label:' + const { tokenKey } = this.tokenizer.parseToken(lastToken); + this.loadDropdown(tokenKey); + } else if (lastToken.hasOwnProperty('key')) { + // Token has been initialized into an object + // because it has a value + this.loadDropdown(lastToken.key); + } else { + this.loadDropdown('hint'); } } bindEvents() { const filteredSearchInput = document.querySelector('.filtered-search'); - filteredSearchInput.addEventListener('input', this.processInput.bind(this)); + filteredSearchInput.addEventListener('input', this.setDropdown.bind(this)); filteredSearchInput.addEventListener('input', toggleClearSearchButton); filteredSearchInput.addEventListener('keydown', this.checkForEnter.bind(this)); - document.querySelector('.clear-search').addEventListener('click', clearSearch); } - // TODO: This is only used for testing, remove when going to PRO - processInput(e) { + checkDropdownToken(e) { const input = e.target.value; - this.tokenizer.processTokens(input); + const { lastToken } = this.tokenizer.processTokens(input); + + // Check for dropdown token + if (lastToken[lastToken.length - 1] === ':') { + const token = lastToken.slice(0, -1); + + } } checkForEnter(e) { diff --git a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.es6 b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.es6 index b1f37443aa1..b686a43cf32 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.es6 @@ -3,11 +3,30 @@ class FilteredSearchTokenizer { // TODO: Remove when going to pro static printTokens(tokens, searchToken, lastToken) { - console.log('tokens:'); - tokens.forEach(token => console.log(token)); - console.log(`search: ${searchToken}`); - console.log('last token:'); - console.log(lastToken); + // console.log('tokens:'); + // tokens.forEach(token => console.log(token)); + // console.log(`search: ${searchToken}`); + // console.log('last token:'); + // console.log(lastToken); + } + + static parseToken(input) { + const colonIndex = input.indexOf(':'); + let tokenKey; + let tokenValue; + let tokenSymbol; + + if (colonIndex !== -1) { + tokenKey = input.slice(0, colonIndex).toLowerCase(); + tokenValue = input.slice(colonIndex + 1); + tokenSymbol = tokenValue[0]; + } + + return { + tokenKey, + tokenValue, + tokenSymbol, + } } static processTokens(input) { @@ -43,10 +62,8 @@ const colonIndex = i.indexOf(':'); if (colonIndex !== -1) { - const tokenKey = i.slice(0, colonIndex).toLowerCase(); - const tokenValue = i.slice(colonIndex + 1); - const tokenSymbol = tokenValue[0]; - console.log(tokenSymbol) + const { tokenKey, tokenValue, tokenSymbol } = gl.FilteredSearchTokenizer.parseToken(i); + const keyMatch = validTokenKeys.filter(v => v.key === tokenKey)[0]; const symbolMatch = validTokenKeys.filter(v => v.symbol === tokenSymbol)[0]; diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml index 4c27c835bee..a45af053f5c 100644 --- a/app/views/shared/issuable/_search_bar.html.haml +++ b/app/views/shared/issuable/_search_bar.html.haml @@ -12,7 +12,7 @@ class: "check_all_issues left" .issues-other-filters.filtered-search-container .filtered-search-input-container - %input.form-control.filtered-search{ placeholder: 'Search or filter results...' } + %input.form-control.filtered-search{ placeholder: 'Search or filter results...', 'data-id' => 'filtered-search' } = icon('filter') %button.clear-search.hidden{ type: 'button' } = icon('times')