Commit 1d5d2a10 authored by Phil Hughes's avatar Phil Hughes

Merge branch 'single-click-filter' into 'master'

Change from double click to single click to open dropdown

Closes #31757

See merge request !11943
parents 6ac1caa0 196a3c54
...@@ -105,11 +105,9 @@ class FilteredSearchManager { ...@@ -105,11 +105,9 @@ class FilteredSearchManager {
this.filteredSearchInput.addEventListener('click', this.tokenChange); this.filteredSearchInput.addEventListener('click', this.tokenChange);
this.filteredSearchInput.addEventListener('keyup', this.tokenChange); this.filteredSearchInput.addEventListener('keyup', this.tokenChange);
this.filteredSearchInput.addEventListener('focus', this.addInputContainerFocusWrapper); this.filteredSearchInput.addEventListener('focus', this.addInputContainerFocusWrapper);
this.tokensContainer.addEventListener('click', FilteredSearchManager.selectToken);
this.tokensContainer.addEventListener('click', this.removeTokenWrapper); this.tokensContainer.addEventListener('click', this.removeTokenWrapper);
this.tokensContainer.addEventListener('dblclick', this.editTokenWrapper); this.tokensContainer.addEventListener('click', this.editTokenWrapper);
this.clearSearchButton.addEventListener('click', this.onClearSearchWrapper); this.clearSearchButton.addEventListener('click', this.onClearSearchWrapper);
document.addEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens);
document.addEventListener('click', this.unselectEditTokensWrapper); document.addEventListener('click', this.unselectEditTokensWrapper);
document.addEventListener('click', this.removeInputContainerFocusWrapper); document.addEventListener('click', this.removeInputContainerFocusWrapper);
document.addEventListener('keydown', this.removeSelectedTokenKeydownWrapper); document.addEventListener('keydown', this.removeSelectedTokenKeydownWrapper);
...@@ -127,11 +125,9 @@ class FilteredSearchManager { ...@@ -127,11 +125,9 @@ class FilteredSearchManager {
this.filteredSearchInput.removeEventListener('click', this.tokenChange); this.filteredSearchInput.removeEventListener('click', this.tokenChange);
this.filteredSearchInput.removeEventListener('keyup', this.tokenChange); this.filteredSearchInput.removeEventListener('keyup', this.tokenChange);
this.filteredSearchInput.removeEventListener('focus', this.addInputContainerFocusWrapper); this.filteredSearchInput.removeEventListener('focus', this.addInputContainerFocusWrapper);
this.tokensContainer.removeEventListener('click', FilteredSearchManager.selectToken);
this.tokensContainer.removeEventListener('click', this.removeTokenWrapper); this.tokensContainer.removeEventListener('click', this.removeTokenWrapper);
this.tokensContainer.removeEventListener('dblclick', this.editTokenWrapper); this.tokensContainer.removeEventListener('click', this.editTokenWrapper);
this.clearSearchButton.removeEventListener('click', this.onClearSearchWrapper); this.clearSearchButton.removeEventListener('click', this.onClearSearchWrapper);
document.removeEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens);
document.removeEventListener('click', this.unselectEditTokensWrapper); document.removeEventListener('click', this.unselectEditTokensWrapper);
document.removeEventListener('click', this.removeInputContainerFocusWrapper); document.removeEventListener('click', this.removeInputContainerFocusWrapper);
document.removeEventListener('keydown', this.removeSelectedTokenKeydownWrapper); document.removeEventListener('keydown', this.removeSelectedTokenKeydownWrapper);
...@@ -207,23 +203,13 @@ class FilteredSearchManager { ...@@ -207,23 +203,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) { removeToken(e) {
const removeButtonSelected = e.target.closest('.remove-token'); const removeButtonSelected = e.target.closest('.remove-token');
if (removeButtonSelected) { if (removeButtonSelected) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); // Prevent editToken from being triggered after token is removed
e.stopImmediatePropagation();
const button = e.target.closest('.selectable'); const button = e.target.closest('.selectable');
gl.FilteredSearchVisualTokens.selectToken(button, true); gl.FilteredSearchVisualTokens.selectToken(button, true);
...@@ -245,10 +231,12 @@ class FilteredSearchManager { ...@@ -245,10 +231,12 @@ class FilteredSearchManager {
editToken(e) { editToken(e) {
const token = e.target.closest('.js-visual-token'); 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); const canEdit = this.canEdit && this.canEdit(sanitizedTokenName);
if (token && canEdit) { if (token && canEdit) {
e.preventDefault();
e.stopPropagation();
gl.FilteredSearchVisualTokens.editToken(token); gl.FilteredSearchVisualTokens.editToken(token);
this.tokenChange(); this.tokenChange();
} }
......
...@@ -142,15 +142,17 @@ ...@@ -142,15 +142,17 @@
} }
} }
} }
}
.selected { .filtered-search-token:hover,
.name { .filtered-search-token .selected,
background-color: $filter-name-selected-color; .filtered-search-term .selected {
} .name {
background-color: $filter-name-selected-color;
}
.value-container { .value-container {
background-color: $filter-value-selected-color; background-color: $filter-value-selected-color;
}
} }
} }
......
---
title: Single click on filter to open filtered search dropdown
merge_request:
author:
...@@ -34,7 +34,7 @@ describe 'Visual tokens', js: true, feature: true do ...@@ -34,7 +34,7 @@ describe 'Visual tokens', js: true, feature: true do
describe 'editing author token' do describe 'editing author token' do
before do before do
input_filtered_search('author:@root assignee:none', submit: false) input_filtered_search('author:@root assignee:none', submit: false)
first('.tokens-container .filtered-search-token').double_click first('.tokens-container .filtered-search-token').click
end end
it 'opens author dropdown' do it 'opens author dropdown' do
...@@ -331,7 +331,7 @@ describe 'Visual tokens', js: true, feature: true do ...@@ -331,7 +331,7 @@ describe 'Visual tokens', js: true, feature: true do
it 'does not tokenize incomplete token' do it 'does not tokenize incomplete token' do
filtered_search.send_keys('author:') filtered_search.send_keys('author:')
find('#content-body').click find('body').click
token = page.all('.tokens-container .js-visual-token')[1] token = page.all('.tokens-container .js-visual-token')[1]
expect_filtered_search_input_empty expect_filtered_search_input_empty
......
...@@ -316,42 +316,6 @@ describe('Filtered Search Manager', () => { ...@@ -316,42 +316,6 @@ describe('Filtered Search Manager', () => {
}); });
}); });
describe('unselects token', () => {
beforeEach(() => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug', true)}
${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~awesome')}
`);
});
it('unselects token when input is clicked', () => {
const selectedToken = tokensContainer.querySelector('.js-visual-token .selected');
expect(selectedToken.classList.contains('selected')).toEqual(true);
expect(gl.FilteredSearchVisualTokens.unselectTokens).not.toHaveBeenCalled();
// Click directly on input attached to document
// so that the click event will propagate properly
document.querySelector('.filtered-search').click();
expect(gl.FilteredSearchVisualTokens.unselectTokens).toHaveBeenCalled();
expect(selectedToken.classList.contains('selected')).toEqual(false);
});
it('unselects token when document.body is clicked', () => {
const selectedToken = tokensContainer.querySelector('.js-visual-token .selected');
expect(selectedToken.classList.contains('selected')).toEqual(true);
expect(gl.FilteredSearchVisualTokens.unselectTokens).not.toHaveBeenCalled();
document.body.click();
expect(selectedToken.classList.contains('selected')).toEqual(false);
expect(gl.FilteredSearchVisualTokens.unselectTokens).toHaveBeenCalled();
});
});
describe('toggleInputContainerFocus', () => { describe('toggleInputContainerFocus', () => {
it('toggles on focus', () => { it('toggles on focus', () => {
input.focus(); input.focus();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment