summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_hint.js.es63
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es67
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es612
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js.es68
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml6
-rw-r--r--changelogs/unreleased/issue-filter-click-to-search.yml4
-rw-r--r--spec/features/issues/filtered_search/dropdown_assignee_spec.rb8
-rw-r--r--spec/features/issues/filtered_search/dropdown_author_spec.rb4
-rw-r--r--spec/features/issues/filtered_search/dropdown_label_spec.rb16
-rw-r--r--spec/features/issues/filtered_search/dropdown_milestone_spec.rb18
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb6
-rw-r--r--spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es66
12 files changed, 62 insertions, 36 deletions
diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 b/app/assets/javascripts/filtered_search/dropdown_hint.js.es6
index f4ec3b206cc..7d297b8eee8 100644
--- a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6
+++ b/app/assets/javascripts/filtered_search/dropdown_hint.js.es6
@@ -20,6 +20,9 @@
if (selected.tagName === 'LI') {
if (selected.hasAttribute('data-value')) {
this.dismissDropdown();
+ } else if (selected.getAttribute('data-action') === 'submit') {
+ this.dismissDropdown();
+ this.dispatchFormSubmitEvent();
} else {
const token = selected.querySelector('.js-filter-hint').innerText.trim();
const tag = selected.querySelector('.js-filter-tag').innerText.trim();
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6
index 9128ea907b3..859d6515531 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6
@@ -39,6 +39,7 @@
}
this.dismissDropdown();
+ this.dispatchInputEvent();
}
}
@@ -84,6 +85,12 @@
}));
}
+ dispatchFormSubmitEvent() {
+ // dispatchEvent() is necessary as form.submit() does not
+ // trigger event handlers
+ this.input.form.dispatchEvent(new Event('submit'));
+ }
+
hideDropdown() {
this.getCurrentHook().list.hide();
}
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
index 408a0dfd768..00e1c28692f 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
@@ -61,11 +61,19 @@
const word = `${tokenName}:${tokenValue}`;
// Get the string to replace
- const selectionStart = input.selectionStart;
+ let newCaretPosition = input.selectionStart;
const { left, right } = gl.DropdownUtils.getInputSelectionPosition(input);
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) {
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 c7b72b36561..ae19bb68360 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
@@ -25,6 +25,7 @@
}
bindEvents() {
+ this.handleFormSubmit = this.handleFormSubmit.bind(this);
this.setDropdownWrapper = this.dropdownManager.setDropdown.bind(this.dropdownManager);
this.toggleClearSearchButtonWrapper = this.toggleClearSearchButton.bind(this);
this.checkForEnterWrapper = this.checkForEnter.bind(this);
@@ -32,6 +33,7 @@
this.checkForBackspaceWrapper = this.checkForBackspace.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.toggleClearSearchButtonWrapper);
this.filteredSearchInput.addEventListener('keydown', this.checkForEnterWrapper);
@@ -42,6 +44,7 @@
}
unbindEvents() {
+ this.filteredSearchInput.form.removeEventListener('submit', this.handleFormSubmit);
this.filteredSearchInput.removeEventListener('input', this.setDropdownWrapper);
this.filteredSearchInput.removeEventListener('input', this.toggleClearSearchButtonWrapper);
this.filteredSearchInput.removeEventListener('keydown', this.checkForEnterWrapper);
@@ -88,6 +91,11 @@
this.dropdownManager.resetDropdowns();
}
+ handleFormSubmit(e) {
+ e.preventDefault();
+ this.search();
+ }
+
loadSearchParamsFromURL() {
const params = gl.utils.getUrlParamsArray();
const usernameParams = this.getUsernameParams();
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index 44152319736..e9644ca0f12 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -17,7 +17,7 @@
= icon('times')
#js-dropdown-hint.dropdown-menu.hint-dropdown
%ul{ 'data-dropdown' => true }
- %li.filter-dropdown-item{ 'data-value' => '' }
+ %li.filter-dropdown-item{ 'data-action' => 'submit' }
%button.btn.btn-link
= icon('search')
%span
@@ -125,10 +125,6 @@
new MilestoneSelect();
new IssueStatusSelect();
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) {
if (gl.FilteredSearchManager) {
diff --git a/changelogs/unreleased/issue-filter-click-to-search.yml b/changelogs/unreleased/issue-filter-click-to-search.yml
new file mode 100644
index 00000000000..c024ea48dc7
--- /dev/null
+++ b/changelogs/unreleased/issue-filter-click-to-search.yml
@@ -0,0 +1,4 @@
+---
+title: allow issue filter bar to be operated with mouse only
+merge_request: 8681
+author:
diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
index 16dcc487812..8a155c3bfc5 100644
--- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
@@ -134,14 +134,14 @@ describe 'Dropdown assignee', js: true, feature: true do
click_button 'Assigned to me'
end
- expect(filtered_search.value).to eq("assignee:#{user.to_reference}")
+ expect(filtered_search.value).to eq("assignee:#{user.to_reference} ")
end
it 'fills in the assignee username when the assignee has not been filtered' do
click_assignee(user_jacob.name)
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
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
click_assignee(user.name)
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
it 'selects `no assignee`' do
find('#js-dropdown-assignee .filter-dropdown-item', text: 'No Assignee').click
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
diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb
index 464749d01e3..a5d5d9d4c5e 100644
--- a/spec/features/issues/filtered_search/dropdown_author_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb
@@ -121,14 +121,14 @@ describe 'Dropdown author', js: true, feature: true do
click_author(user_jacob.name)
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
it 'fills in the author username when the author has been filtered' do
click_author(user.name)
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
diff --git a/spec/features/issues/filtered_search/dropdown_label_spec.rb b/spec/features/issues/filtered_search/dropdown_label_spec.rb
index 89c144141c9..bea00160f96 100644
--- a/spec/features/issues/filtered_search/dropdown_label_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_label_spec.rb
@@ -159,7 +159,7 @@ describe 'Dropdown label', js: true, feature: true do
click_label(bug_label.title)
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
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
click_label(bug_label.title)
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
it 'fills in the label name that contains multiple words' do
click_label(two_words_label.title)
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
it 'fills in the label name that contains multiple words and is very long' do
click_label(long_label.title)
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
it 'fills in the label name that contains double quotes' do
click_label(wont_fix_label.title)
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
it 'fills in the label name with the correct capitalization' do
click_label(uppercase_label.title)
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
it 'fills in the label name with special characters' do
click_label(special_label.title)
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
it 'selects `no label`' do
find('#js-dropdown-label .filter-dropdown-item', text: 'No Label').click
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
diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
index e5a271b663f..134e58ad586 100644
--- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
@@ -127,7 +127,7 @@ describe 'Dropdown milestone', js: true, feature: true do
click_milestone(milestone.title)
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
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
click_milestone(milestone.title)
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
it 'fills in the milestone name that contains multiple words' do
click_milestone(two_words_milestone.title)
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
it 'fills in the milestone name that contains multiple words and is very long' do
click_milestone(long_milestone.title)
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
it 'fills in the milestone name that contains double quotes' do
click_milestone(wont_fix_milestone.title)
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
it 'fills in the milestone name with the correct capitalization' do
click_milestone(uppercase_milestone.title)
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
it 'fills in the milestone name with special characters' do
click_milestone(special_milestone.title)
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
it 'selects `no milestone`' do
click_static_milestone('No Milestone')
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
it 'selects `upcoming milestone`' do
click_static_milestone('Upcoming')
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
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index 1cdac520181..f48a0193545 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -539,7 +539,7 @@ describe 'Filter issues', js: true, feature: true do
click_button user2.username
end
- expect(filtered_search.value).to eq("author:@#{user2.username}")
+ expect(filtered_search.value).to eq("author:@#{user2.username} ")
end
it 'changes label' do
@@ -551,7 +551,7 @@ describe 'Filter issues', js: true, feature: true do
click_button label.name
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
it 'changes label correctly space is in previous label' do
@@ -563,7 +563,7 @@ describe 'Filter issues', js: true, feature: true do
click_button label.name
end
- expect(filtered_search.value).to eq("label:~#{label.name}")
+ expect(filtered_search.value).to eq("label:~#{label.name} ")
end
end
diff --git a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6
index d0d27ceb4a6..4bd45eb457d 100644
--- a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6
+++ b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6
@@ -31,7 +31,7 @@
it('should add tokenName and tokenValue', () => {
gl.FilteredSearchDropdownManager.addWordToInput('label', 'none');
- expect(getInputValue()).toBe('label:none');
+ expect(getInputValue()).toBe('label:none ');
});
});
@@ -45,13 +45,13 @@
it('should replace tokenValue', () => {
setInputValue('author:roo');
gl.FilteredSearchDropdownManager.addWordToInput('author', '@root');
- expect(getInputValue()).toBe('author:@root');
+ expect(getInputValue()).toBe('author:@root ');
});
it('should add tokenValues containing spaces', () => {
setInputValue('label:~"test');
gl.FilteredSearchDropdownManager.addWordToInput('label', '~\'"test me"\'');
- expect(getInputValue()).toBe('label:~\'"test me"\'');
+ expect(getInputValue()).toBe('label:~\'"test me"\' ');
});
});
});