Commit 32f6f5b9 authored by Jacob Schatz's avatar Jacob Schatz

Merge branch 'issue-filter-click-to-search' into 'master'

Allow issue filter submission using mouse only

See merge request !8681
parents 30d5e9fa b994596b
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
if (selected.tagName === 'LI') { if (selected.tagName === 'LI') {
if (selected.hasAttribute('data-value')) { if (selected.hasAttribute('data-value')) {
this.dismissDropdown(); this.dismissDropdown();
} else if (selected.getAttribute('data-action') === 'submit') {
this.dismissDropdown();
this.dispatchFormSubmitEvent();
} else { } else {
const token = selected.querySelector('.js-filter-hint').innerText.trim(); const token = selected.querySelector('.js-filter-hint').innerText.trim();
const tag = selected.querySelector('.js-filter-tag').innerText.trim(); const tag = selected.querySelector('.js-filter-tag').innerText.trim();
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
} }
this.dismissDropdown(); this.dismissDropdown();
this.dispatchInputEvent();
} }
} }
...@@ -84,6 +85,12 @@ ...@@ -84,6 +85,12 @@
})); }));
} }
dispatchFormSubmitEvent() {
// dispatchEvent() is necessary as form.submit() does not
// trigger event handlers
this.input.form.dispatchEvent(new Event('submit'));
}
hideDropdown() { hideDropdown() {
this.getCurrentHook().list.hide(); this.getCurrentHook().list.hide();
} }
......
...@@ -61,11 +61,19 @@ ...@@ -61,11 +61,19 @@
const word = `${tokenName}:${tokenValue}`; const word = `${tokenName}:${tokenValue}`;
// Get the string to replace // Get the string to replace
const selectionStart = input.selectionStart; let newCaretPosition = input.selectionStart;
const { left, right } = gl.DropdownUtils.getInputSelectionPosition(input); const { left, right } = gl.DropdownUtils.getInputSelectionPosition(input);
input.value = `${inputValue.substr(0, left)}${word}${inputValue.substr(right)}`; input.value = `${inputValue.substr(0, left)}${word}${inputValue.substr(right)}`;
gl.FilteredSearchDropdownManager.updateInputCaretPosition(selectionStart, input);
// If we have added a tokenValue at the end of the input,
// add a space and set selection to the end
if (right >= inputValue.length && tokenValue !== '') {
input.value += ' ';
newCaretPosition = input.value.length;
}
gl.FilteredSearchDropdownManager.updateInputCaretPosition(newCaretPosition, input);
} }
static updateInputCaretPosition(selectionStart, input) { static updateInputCaretPosition(selectionStart, input) {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
} }
bindEvents() { bindEvents() {
this.handleFormSubmit = this.handleFormSubmit.bind(this);
this.setDropdownWrapper = this.dropdownManager.setDropdown.bind(this.dropdownManager); this.setDropdownWrapper = this.dropdownManager.setDropdown.bind(this.dropdownManager);
this.toggleClearSearchButtonWrapper = this.toggleClearSearchButton.bind(this); this.toggleClearSearchButtonWrapper = this.toggleClearSearchButton.bind(this);
this.checkForEnterWrapper = this.checkForEnter.bind(this); this.checkForEnterWrapper = this.checkForEnter.bind(this);
...@@ -32,6 +33,7 @@ ...@@ -32,6 +33,7 @@
this.checkForBackspaceWrapper = this.checkForBackspace.bind(this); this.checkForBackspaceWrapper = this.checkForBackspace.bind(this);
this.tokenChange = this.tokenChange.bind(this); this.tokenChange = this.tokenChange.bind(this);
this.filteredSearchInput.form.addEventListener('submit', this.handleFormSubmit);
this.filteredSearchInput.addEventListener('input', this.setDropdownWrapper); this.filteredSearchInput.addEventListener('input', this.setDropdownWrapper);
this.filteredSearchInput.addEventListener('input', this.toggleClearSearchButtonWrapper); this.filteredSearchInput.addEventListener('input', this.toggleClearSearchButtonWrapper);
this.filteredSearchInput.addEventListener('keydown', this.checkForEnterWrapper); this.filteredSearchInput.addEventListener('keydown', this.checkForEnterWrapper);
...@@ -42,6 +44,7 @@ ...@@ -42,6 +44,7 @@
} }
unbindEvents() { unbindEvents() {
this.filteredSearchInput.form.removeEventListener('submit', this.handleFormSubmit);
this.filteredSearchInput.removeEventListener('input', this.setDropdownWrapper); this.filteredSearchInput.removeEventListener('input', this.setDropdownWrapper);
this.filteredSearchInput.removeEventListener('input', this.toggleClearSearchButtonWrapper); this.filteredSearchInput.removeEventListener('input', this.toggleClearSearchButtonWrapper);
this.filteredSearchInput.removeEventListener('keydown', this.checkForEnterWrapper); this.filteredSearchInput.removeEventListener('keydown', this.checkForEnterWrapper);
...@@ -88,6 +91,11 @@ ...@@ -88,6 +91,11 @@
this.dropdownManager.resetDropdowns(); this.dropdownManager.resetDropdowns();
} }
handleFormSubmit(e) {
e.preventDefault();
this.search();
}
loadSearchParamsFromURL() { loadSearchParamsFromURL() {
const params = gl.utils.getUrlParamsArray(); const params = gl.utils.getUrlParamsArray();
const usernameParams = this.getUsernameParams(); const usernameParams = this.getUsernameParams();
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
= icon('times') = icon('times')
#js-dropdown-hint.dropdown-menu.hint-dropdown #js-dropdown-hint.dropdown-menu.hint-dropdown
%ul{ 'data-dropdown' => true } %ul{ 'data-dropdown' => true }
%li.filter-dropdown-item{ 'data-value' => '' } %li.filter-dropdown-item{ 'data-action' => 'submit' }
%button.btn.btn-link %button.btn.btn-link
= icon('search') = icon('search')
%span %span
...@@ -125,10 +125,6 @@ ...@@ -125,10 +125,6 @@
new MilestoneSelect(); new MilestoneSelect();
new IssueStatusSelect(); new IssueStatusSelect();
new SubscriptionSelect(); new SubscriptionSelect();
$('form.filter-form').on('submit', function (event) {
event.preventDefault();
Turbolinks.visit(this.action + '&' + $(this).serialize());
});
$(document).off('page:restore').on('page:restore', function (event) { $(document).off('page:restore').on('page:restore', function (event) {
if (gl.FilteredSearchManager) { if (gl.FilteredSearchManager) {
......
---
title: allow issue filter bar to be operated with mouse only
merge_request: 8681
author:
...@@ -134,14 +134,14 @@ describe 'Dropdown assignee', js: true, feature: true do ...@@ -134,14 +134,14 @@ describe 'Dropdown assignee', js: true, feature: true do
click_button 'Assigned to me' click_button 'Assigned to me'
end end
expect(filtered_search.value).to eq("assignee:#{user.to_reference}") expect(filtered_search.value).to eq("assignee:#{user.to_reference} ")
end end
it 'fills in the assignee username when the assignee has not been filtered' do it 'fills in the assignee username when the assignee has not been filtered' do
click_assignee(user_jacob.name) click_assignee(user_jacob.name)
expect(page).to have_css(js_dropdown_assignee, visible: false) expect(page).to have_css(js_dropdown_assignee, visible: false)
expect(filtered_search.value).to eq("assignee:@#{user_jacob.username}") expect(filtered_search.value).to eq("assignee:@#{user_jacob.username} ")
end end
it 'fills in the assignee username when the assignee has been filtered' do it 'fills in the assignee username when the assignee has been filtered' do
...@@ -149,14 +149,14 @@ describe 'Dropdown assignee', js: true, feature: true do ...@@ -149,14 +149,14 @@ describe 'Dropdown assignee', js: true, feature: true do
click_assignee(user.name) click_assignee(user.name)
expect(page).to have_css(js_dropdown_assignee, visible: false) expect(page).to have_css(js_dropdown_assignee, visible: false)
expect(filtered_search.value).to eq("assignee:@#{user.username}") expect(filtered_search.value).to eq("assignee:@#{user.username} ")
end end
it 'selects `no assignee`' do it 'selects `no assignee`' do
find('#js-dropdown-assignee .filter-dropdown-item', text: 'No Assignee').click find('#js-dropdown-assignee .filter-dropdown-item', text: 'No Assignee').click
expect(page).to have_css(js_dropdown_assignee, visible: false) expect(page).to have_css(js_dropdown_assignee, visible: false)
expect(filtered_search.value).to eq("assignee:none") expect(filtered_search.value).to eq("assignee:none ")
end end
end end
......
...@@ -121,14 +121,14 @@ describe 'Dropdown author', js: true, feature: true do ...@@ -121,14 +121,14 @@ describe 'Dropdown author', js: true, feature: true do
click_author(user_jacob.name) click_author(user_jacob.name)
expect(page).to have_css(js_dropdown_author, visible: false) expect(page).to have_css(js_dropdown_author, visible: false)
expect(filtered_search.value).to eq("author:@#{user_jacob.username}") expect(filtered_search.value).to eq("author:@#{user_jacob.username} ")
end end
it 'fills in the author username when the author has been filtered' do it 'fills in the author username when the author has been filtered' do
click_author(user.name) click_author(user.name)
expect(page).to have_css(js_dropdown_author, visible: false) expect(page).to have_css(js_dropdown_author, visible: false)
expect(filtered_search.value).to eq("author:@#{user.username}") expect(filtered_search.value).to eq("author:@#{user.username} ")
end end
end end
......
...@@ -159,7 +159,7 @@ describe 'Dropdown label', js: true, feature: true do ...@@ -159,7 +159,7 @@ describe 'Dropdown label', js: true, feature: true do
click_label(bug_label.title) click_label(bug_label.title)
expect(page).to have_css(js_dropdown_label, visible: false) expect(page).to have_css(js_dropdown_label, visible: false)
expect(filtered_search.value).to eq("label:~#{bug_label.title}") expect(filtered_search.value).to eq("label:~#{bug_label.title} ")
end end
it 'fills in the label name when the label is partially filled' do it 'fills in the label name when the label is partially filled' do
...@@ -167,49 +167,49 @@ describe 'Dropdown label', js: true, feature: true do ...@@ -167,49 +167,49 @@ describe 'Dropdown label', js: true, feature: true do
click_label(bug_label.title) click_label(bug_label.title)
expect(page).to have_css(js_dropdown_label, visible: false) expect(page).to have_css(js_dropdown_label, visible: false)
expect(filtered_search.value).to eq("label:~#{bug_label.title}") expect(filtered_search.value).to eq("label:~#{bug_label.title} ")
end end
it 'fills in the label name that contains multiple words' do it 'fills in the label name that contains multiple words' do
click_label(two_words_label.title) click_label(two_words_label.title)
expect(page).to have_css(js_dropdown_label, visible: false) expect(page).to have_css(js_dropdown_label, visible: false)
expect(filtered_search.value).to eq("label:~\"#{two_words_label.title}\"") expect(filtered_search.value).to eq("label:~\"#{two_words_label.title}\" ")
end end
it 'fills in the label name that contains multiple words and is very long' do it 'fills in the label name that contains multiple words and is very long' do
click_label(long_label.title) click_label(long_label.title)
expect(page).to have_css(js_dropdown_label, visible: false) expect(page).to have_css(js_dropdown_label, visible: false)
expect(filtered_search.value).to eq("label:~\"#{long_label.title}\"") expect(filtered_search.value).to eq("label:~\"#{long_label.title}\" ")
end end
it 'fills in the label name that contains double quotes' do it 'fills in the label name that contains double quotes' do
click_label(wont_fix_label.title) click_label(wont_fix_label.title)
expect(page).to have_css(js_dropdown_label, visible: false) expect(page).to have_css(js_dropdown_label, visible: false)
expect(filtered_search.value).to eq("label:~'#{wont_fix_label.title}'") expect(filtered_search.value).to eq("label:~'#{wont_fix_label.title}' ")
end end
it 'fills in the label name with the correct capitalization' do it 'fills in the label name with the correct capitalization' do
click_label(uppercase_label.title) click_label(uppercase_label.title)
expect(page).to have_css(js_dropdown_label, visible: false) expect(page).to have_css(js_dropdown_label, visible: false)
expect(filtered_search.value).to eq("label:~#{uppercase_label.title}") expect(filtered_search.value).to eq("label:~#{uppercase_label.title} ")
end end
it 'fills in the label name with special characters' do it 'fills in the label name with special characters' do
click_label(special_label.title) click_label(special_label.title)
expect(page).to have_css(js_dropdown_label, visible: false) expect(page).to have_css(js_dropdown_label, visible: false)
expect(filtered_search.value).to eq("label:~#{special_label.title}") expect(filtered_search.value).to eq("label:~#{special_label.title} ")
end end
it 'selects `no label`' do it 'selects `no label`' do
find('#js-dropdown-label .filter-dropdown-item', text: 'No Label').click find('#js-dropdown-label .filter-dropdown-item', text: 'No Label').click
expect(page).to have_css(js_dropdown_label, visible: false) expect(page).to have_css(js_dropdown_label, visible: false)
expect(filtered_search.value).to eq("label:none") expect(filtered_search.value).to eq("label:none ")
end end
end end
......
...@@ -127,7 +127,7 @@ describe 'Dropdown milestone', js: true, feature: true do ...@@ -127,7 +127,7 @@ describe 'Dropdown milestone', js: true, feature: true do
click_milestone(milestone.title) click_milestone(milestone.title)
expect(page).to have_css(js_dropdown_milestone, visible: false) expect(page).to have_css(js_dropdown_milestone, visible: false)
expect(filtered_search.value).to eq("milestone:%#{milestone.title}") expect(filtered_search.value).to eq("milestone:%#{milestone.title} ")
end end
it 'fills in the milestone name when the milestone is partially filled' do it 'fills in the milestone name when the milestone is partially filled' do
...@@ -135,56 +135,56 @@ describe 'Dropdown milestone', js: true, feature: true do ...@@ -135,56 +135,56 @@ describe 'Dropdown milestone', js: true, feature: true do
click_milestone(milestone.title) click_milestone(milestone.title)
expect(page).to have_css(js_dropdown_milestone, visible: false) expect(page).to have_css(js_dropdown_milestone, visible: false)
expect(filtered_search.value).to eq("milestone:%#{milestone.title}") expect(filtered_search.value).to eq("milestone:%#{milestone.title} ")
end end
it 'fills in the milestone name that contains multiple words' do it 'fills in the milestone name that contains multiple words' do
click_milestone(two_words_milestone.title) click_milestone(two_words_milestone.title)
expect(page).to have_css(js_dropdown_milestone, visible: false) expect(page).to have_css(js_dropdown_milestone, visible: false)
expect(filtered_search.value).to eq("milestone:%\"#{two_words_milestone.title}\"") expect(filtered_search.value).to eq("milestone:%\"#{two_words_milestone.title}\" ")
end end
it 'fills in the milestone name that contains multiple words and is very long' do it 'fills in the milestone name that contains multiple words and is very long' do
click_milestone(long_milestone.title) click_milestone(long_milestone.title)
expect(page).to have_css(js_dropdown_milestone, visible: false) expect(page).to have_css(js_dropdown_milestone, visible: false)
expect(filtered_search.value).to eq("milestone:%\"#{long_milestone.title}\"") expect(filtered_search.value).to eq("milestone:%\"#{long_milestone.title}\" ")
end end
it 'fills in the milestone name that contains double quotes' do it 'fills in the milestone name that contains double quotes' do
click_milestone(wont_fix_milestone.title) click_milestone(wont_fix_milestone.title)
expect(page).to have_css(js_dropdown_milestone, visible: false) expect(page).to have_css(js_dropdown_milestone, visible: false)
expect(filtered_search.value).to eq("milestone:%'#{wont_fix_milestone.title}'") expect(filtered_search.value).to eq("milestone:%'#{wont_fix_milestone.title}' ")
end end
it 'fills in the milestone name with the correct capitalization' do it 'fills in the milestone name with the correct capitalization' do
click_milestone(uppercase_milestone.title) click_milestone(uppercase_milestone.title)
expect(page).to have_css(js_dropdown_milestone, visible: false) expect(page).to have_css(js_dropdown_milestone, visible: false)
expect(filtered_search.value).to eq("milestone:%#{uppercase_milestone.title}") expect(filtered_search.value).to eq("milestone:%#{uppercase_milestone.title} ")
end end
it 'fills in the milestone name with special characters' do it 'fills in the milestone name with special characters' do
click_milestone(special_milestone.title) click_milestone(special_milestone.title)
expect(page).to have_css(js_dropdown_milestone, visible: false) expect(page).to have_css(js_dropdown_milestone, visible: false)
expect(filtered_search.value).to eq("milestone:%#{special_milestone.title}") expect(filtered_search.value).to eq("milestone:%#{special_milestone.title} ")
end end
it 'selects `no milestone`' do it 'selects `no milestone`' do
click_static_milestone('No Milestone') click_static_milestone('No Milestone')
expect(page).to have_css(js_dropdown_milestone, visible: false) expect(page).to have_css(js_dropdown_milestone, visible: false)
expect(filtered_search.value).to eq("milestone:none") expect(filtered_search.value).to eq("milestone:none ")
end end
it 'selects `upcoming milestone`' do it 'selects `upcoming milestone`' do
click_static_milestone('Upcoming') click_static_milestone('Upcoming')
expect(page).to have_css(js_dropdown_milestone, visible: false) expect(page).to have_css(js_dropdown_milestone, visible: false)
expect(filtered_search.value).to eq("milestone:upcoming") expect(filtered_search.value).to eq("milestone:upcoming ")
end end
end end
......
...@@ -539,7 +539,7 @@ describe 'Filter issues', js: true, feature: true do ...@@ -539,7 +539,7 @@ describe 'Filter issues', js: true, feature: true do
click_button user2.username click_button user2.username
end end
expect(filtered_search.value).to eq("author:@#{user2.username}") expect(filtered_search.value).to eq("author:@#{user2.username} ")
end end
it 'changes label' do it 'changes label' do
...@@ -551,7 +551,7 @@ describe 'Filter issues', js: true, feature: true do ...@@ -551,7 +551,7 @@ describe 'Filter issues', js: true, feature: true do
click_button label.name click_button label.name
end end
expect(filtered_search.value).to eq("author:@#{user.username} label:~#{label.name}") expect(filtered_search.value).to eq("author:@#{user.username} label:~#{label.name} ")
end end
it 'changes label correctly space is in previous label' do it 'changes label correctly space is in previous label' do
...@@ -563,7 +563,7 @@ describe 'Filter issues', js: true, feature: true do ...@@ -563,7 +563,7 @@ describe 'Filter issues', js: true, feature: true do
click_button label.name click_button label.name
end end
expect(filtered_search.value).to eq("label:~#{label.name}") expect(filtered_search.value).to eq("label:~#{label.name} ")
end end
end end
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
it('should add tokenName and tokenValue', () => { it('should add tokenName and tokenValue', () => {
gl.FilteredSearchDropdownManager.addWordToInput('label', 'none'); gl.FilteredSearchDropdownManager.addWordToInput('label', 'none');
expect(getInputValue()).toBe('label:none'); expect(getInputValue()).toBe('label:none ');
}); });
}); });
...@@ -45,13 +45,13 @@ ...@@ -45,13 +45,13 @@
it('should replace tokenValue', () => { it('should replace tokenValue', () => {
setInputValue('author:roo'); setInputValue('author:roo');
gl.FilteredSearchDropdownManager.addWordToInput('author', '@root'); gl.FilteredSearchDropdownManager.addWordToInput('author', '@root');
expect(getInputValue()).toBe('author:@root'); expect(getInputValue()).toBe('author:@root ');
}); });
it('should add tokenValues containing spaces', () => { it('should add tokenValues containing spaces', () => {
setInputValue('label:~"test'); setInputValue('label:~"test');
gl.FilteredSearchDropdownManager.addWordToInput('label', '~\'"test me"\''); gl.FilteredSearchDropdownManager.addWordToInput('label', '~\'"test me"\'');
expect(getInputValue()).toBe('label:~\'"test me"\''); expect(getInputValue()).toBe('label:~\'"test me"\' ');
}); });
}); });
}); });
......
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