diff options
author | Alfredo Sumaran <alfredo@gitlab.com> | 2017-06-07 14:45:57 -0500 |
---|---|---|
committer | Alfredo Sumaran <alfredo@gitlab.com> | 2017-06-07 14:45:57 -0500 |
commit | 3ec37e2622f6729300a988c8f58dfb6c2aecb996 (patch) | |
tree | d060b5acf30093cbe1d3642ea6dd11e79ccbf6c5 /app/assets/javascripts/filtered_search | |
parent | a65f07a256b95ce1c38342518f9469cbf3abf609 (diff) | |
parent | fc1090d9f39231e31f929e37b9703db9738b457c (diff) | |
download | gitlab-ce-3ec37e2622f6729300a988c8f58dfb6c2aecb996.tar.gz |
Merge branch 'master' into 25426-group-dashboard-ui
Diffstat (limited to 'app/assets/javascripts/filtered_search')
3 files changed, 124 insertions, 34 deletions
diff --git a/app/assets/javascripts/filtered_search/dropdown_utils.js b/app/assets/javascripts/filtered_search/dropdown_utils.js index 5c02a7a53d3..ef8fe071012 100644 --- a/app/assets/javascripts/filtered_search/dropdown_utils.js +++ b/app/assets/javascripts/filtered_search/dropdown_utils.js @@ -102,10 +102,13 @@ class DropdownUtils { if (token.classList.contains('js-visual-token')) { const name = token.querySelector('.name'); const value = token.querySelector('.value'); + const valueContainer = token.querySelector('.value-container'); const symbol = value && value.dataset.symbol ? value.dataset.symbol : ''; let valueText = ''; - if (value && value.innerText) { + if (valueContainer && valueContainer.dataset.originalValue) { + valueText = valueContainer.dataset.originalValue; + } else if (value && value.innerText) { valueText = value.innerText; } diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js index 3be889c684b..8f547bd8f1f 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js @@ -77,6 +77,41 @@ class FilteredSearchManager { } } + bindStateEvents() { + this.stateFilters = document.querySelector('.container-fluid .issues-state-filters'); + + if (this.stateFilters) { + this.searchStateWrapper = this.searchState.bind(this); + + this.stateFilters.querySelector('[data-state="opened"]') + .addEventListener('click', this.searchStateWrapper); + this.stateFilters.querySelector('[data-state="closed"]') + .addEventListener('click', this.searchStateWrapper); + this.stateFilters.querySelector('[data-state="all"]') + .addEventListener('click', this.searchStateWrapper); + + this.mergedState = this.stateFilters.querySelector('[data-state="merged"]'); + if (this.mergedState) { + this.mergedState.addEventListener('click', this.searchStateWrapper); + } + } + } + + unbindStateEvents() { + if (this.stateFilters) { + this.stateFilters.querySelector('[data-state="opened"]') + .removeEventListener('click', this.searchStateWrapper); + this.stateFilters.querySelector('[data-state="closed"]') + .removeEventListener('click', this.searchStateWrapper); + this.stateFilters.querySelector('[data-state="all"]') + .removeEventListener('click', this.searchStateWrapper); + + if (this.mergedState) { + this.mergedState.removeEventListener('click', this.searchStateWrapper); + } + } + } + bindEvents() { this.handleFormSubmit = this.handleFormSubmit.bind(this); this.setDropdownWrapper = this.dropdownManager.setDropdown.bind(this.dropdownManager); @@ -105,15 +140,15 @@ class FilteredSearchManager { this.filteredSearchInput.addEventListener('click', this.tokenChange); this.filteredSearchInput.addEventListener('keyup', this.tokenChange); this.filteredSearchInput.addEventListener('focus', this.addInputContainerFocusWrapper); - this.tokensContainer.addEventListener('click', FilteredSearchManager.selectToken); this.tokensContainer.addEventListener('click', this.removeTokenWrapper); - this.tokensContainer.addEventListener('dblclick', this.editTokenWrapper); + this.tokensContainer.addEventListener('click', this.editTokenWrapper); this.clearSearchButton.addEventListener('click', this.onClearSearchWrapper); - document.addEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens); document.addEventListener('click', this.unselectEditTokensWrapper); document.addEventListener('click', this.removeInputContainerFocusWrapper); document.addEventListener('keydown', this.removeSelectedTokenKeydownWrapper); eventHub.$on('recentSearchesItemSelected', this.onrecentSearchesItemSelectedWrapper); + + this.bindStateEvents(); } unbindEvents() { @@ -127,15 +162,15 @@ class FilteredSearchManager { this.filteredSearchInput.removeEventListener('click', this.tokenChange); this.filteredSearchInput.removeEventListener('keyup', this.tokenChange); this.filteredSearchInput.removeEventListener('focus', this.addInputContainerFocusWrapper); - this.tokensContainer.removeEventListener('click', FilteredSearchManager.selectToken); this.tokensContainer.removeEventListener('click', this.removeTokenWrapper); - this.tokensContainer.removeEventListener('dblclick', this.editTokenWrapper); + this.tokensContainer.removeEventListener('click', this.editTokenWrapper); this.clearSearchButton.removeEventListener('click', this.onClearSearchWrapper); - document.removeEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens); document.removeEventListener('click', this.unselectEditTokensWrapper); document.removeEventListener('click', this.removeInputContainerFocusWrapper); document.removeEventListener('keydown', this.removeSelectedTokenKeydownWrapper); eventHub.$off('recentSearchesItemSelected', this.onrecentSearchesItemSelectedWrapper); + + this.unbindStateEvents(); } checkForBackspace(e) { @@ -207,23 +242,13 @@ class FilteredSearchManager { } } - static selectToken(e) { - const button = e.target.closest('.selectable'); - const removeButtonSelected = e.target.closest('.remove-token'); - - if (!removeButtonSelected && button) { - e.preventDefault(); - e.stopPropagation(); - gl.FilteredSearchVisualTokens.selectToken(button); - } - } - removeToken(e) { const removeButtonSelected = e.target.closest('.remove-token'); if (removeButtonSelected) { e.preventDefault(); - e.stopPropagation(); + // Prevent editToken from being triggered after token is removed + e.stopImmediatePropagation(); const button = e.target.closest('.selectable'); gl.FilteredSearchVisualTokens.selectToken(button, true); @@ -245,10 +270,12 @@ class FilteredSearchManager { editToken(e) { const token = e.target.closest('.js-visual-token'); - const sanitizedTokenName = token.querySelector('.name').textContent.trim(); + const sanitizedTokenName = token && token.querySelector('.name').textContent.trim(); const canEdit = this.canEdit && this.canEdit(sanitizedTokenName); if (token && canEdit) { + e.preventDefault(); + e.stopPropagation(); gl.FilteredSearchVisualTokens.editToken(token); this.tokenChange(); } @@ -459,7 +486,19 @@ class FilteredSearchManager { } } - search() { + searchState(e) { + const target = e.currentTarget; + // remove focus outline after click + target.blur(); + + const state = target.dataset && target.dataset.state; + + if (state) { + this.search(state); + } + } + + search(state = null) { const paths = []; const searchQuery = gl.DropdownUtils.getSearchQuery(); @@ -467,7 +506,7 @@ class FilteredSearchManager { const { tokens, searchToken } = this.tokenizer.processTokens(searchQuery, this.filteredSearchTokenKeys.getKeys()); - const currentState = gl.utils.getParameterByName('state') || 'opened'; + const currentState = state || gl.utils.getParameterByName('state') || 'opened'; paths.push(`state=${currentState}`); tokens.forEach((token) => { diff --git a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js index bc1226f5879..e9278140af0 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js +++ b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js @@ -1,6 +1,7 @@ -import AjaxCache from '~/lib/utils/ajax_cache'; -import '~/flash'; /* global Flash */ +import AjaxCache from '../lib/utils/ajax_cache'; +import '../flash'; /* global Flash */ import FilteredSearchContainer from './container'; +import UsersCache from '../lib/utils/users_cache'; class FilteredSearchVisualTokens { static getLastVisualTokenBeforeInput() { @@ -82,12 +83,42 @@ class FilteredSearchVisualTokens { .catch(() => new Flash('An error occurred while fetching label colors.')); } + static updateUserTokenAppearance(tokenValueContainer, tokenValueElement, tokenValue) { + if (tokenValue === 'none') { + return Promise.resolve(); + } + + const username = tokenValue.replace(/^@/, ''); + return UsersCache.retrieve(username) + .then((user) => { + if (!user) { + return; + } + + /* eslint-disable no-param-reassign */ + tokenValueContainer.dataset.originalValue = tokenValue; + tokenValueElement.innerHTML = ` + <img class="avatar s20" src="${user.avatar_url}" alt="${user.name}'s avatar"> + ${user.name} + `; + /* eslint-enable no-param-reassign */ + }) + // ignore error and leave username in the search bar + .catch(() => { }); + } + static renderVisualTokenValue(parentElement, tokenName, tokenValue) { const tokenValueContainer = parentElement.querySelector('.value-container'); - tokenValueContainer.querySelector('.value').innerText = tokenValue; + const tokenValueElement = tokenValueContainer.querySelector('.value'); + tokenValueElement.innerText = tokenValue; - if (tokenName.toLowerCase() === 'label') { + const tokenType = tokenName.toLowerCase(); + if (tokenType === 'label') { FilteredSearchVisualTokens.updateLabelTokenColor(tokenValueContainer, tokenValue); + } else if ((tokenType === 'author') || (tokenType === 'assignee')) { + FilteredSearchVisualTokens.updateUserTokenAppearance( + tokenValueContainer, tokenValueElement, tokenValue, + ); } } @@ -153,6 +184,12 @@ class FilteredSearchVisualTokens { if (!lastVisualToken) return ''; + const valueContainer = lastVisualToken.querySelector('.value-container'); + const originalValue = valueContainer && valueContainer.dataset.originalValue; + if (originalValue) { + return originalValue; + } + const value = lastVisualToken.querySelector('.value'); const name = lastVisualToken.querySelector('.name'); @@ -205,17 +242,28 @@ class FilteredSearchVisualTokens { const inputLi = input.parentElement; tokenContainer.replaceChild(inputLi, token); - const name = token.querySelector('.name'); - const value = token.querySelector('.value'); + const nameElement = token.querySelector('.name'); + let value; - if (token.classList.contains('filtered-search-token') && value) { - FilteredSearchVisualTokens.addFilterVisualToken(name.innerText); - input.value = value.innerText; - } else { - // token is a search term - input.value = name.innerText; + if (token.classList.contains('filtered-search-token')) { + FilteredSearchVisualTokens.addFilterVisualToken(nameElement.innerText); + + const valueContainerElement = token.querySelector('.value-container'); + value = valueContainerElement.dataset.originalValue; + + if (!value) { + const valueElement = valueContainerElement.querySelector('.value'); + value = valueElement.innerText; + } } + // token is a search term + if (!value) { + value = nameElement.innerText; + } + + input.value = value; + // Opens dropdown const inputEvent = new Event('input'); input.dispatchEvent(inputEvent); |