From 0f8d7b73bc28b08df6a884ef2e8d99e0c0eff3e3 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Mon, 30 Jan 2017 16:53:18 -0600 Subject: Auto hide filtered search input placeholder --- .../filtered_search/filtered_search_manager.js.es6 | 17 +++++ spec/features/merge_requests/reset_filters_spec.rb | 26 ++++++++ .../filtered_search_manager_spec.js.es6 | 73 +++++++++++++++++++--- .../filtered_search_visual_tokens_spec.js.es6 | 2 +- spec/support/filtered_search_helpers.rb | 8 +++ 5 files changed, 117 insertions(+), 9 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 7a28963cb14..c1fc1111ecf 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 @@ -27,6 +27,7 @@ this.handleFormSubmit = this.handleFormSubmit.bind(this); this.setDropdownWrapper = this.dropdownManager.setDropdown.bind(this.dropdownManager); this.toggleClearSearchButtonWrapper = this.toggleClearSearchButton.bind(this); + this.handleInputPlaceholderWrapper = this.handleInputPlaceholder.bind(this); this.handleInputVisualTokenWrapper = this.handleInputVisualToken.bind(this); this.checkForEnterWrapper = this.checkForEnter.bind(this); this.clearSearchWrapper = this.clearSearch.bind(this); @@ -36,6 +37,7 @@ this.filteredSearchInput.form.addEventListener('submit', this.handleFormSubmit); this.filteredSearchInput.addEventListener('input', this.setDropdownWrapper); this.filteredSearchInput.addEventListener('input', this.toggleClearSearchButtonWrapper); + this.filteredSearchInput.addEventListener('input', this.handleInputPlaceholderWrapper); this.filteredSearchInput.addEventListener('input', this.handleInputVisualTokenWrapper); this.filteredSearchInput.addEventListener('keydown', this.checkForEnterWrapper); this.filteredSearchInput.addEventListener('keyup', this.checkForBackspaceWrapper); @@ -48,6 +50,7 @@ this.filteredSearchInput.form.removeEventListener('submit', this.handleFormSubmit); this.filteredSearchInput.removeEventListener('input', this.setDropdownWrapper); this.filteredSearchInput.removeEventListener('input', this.toggleClearSearchButtonWrapper); + this.filteredSearchInput.removeEventListener('input', this.handleInputPlaceholderWrapper); this.filteredSearchInput.removeEventListener('input', this.handleInputVisualTokenWrapper); this.filteredSearchInput.removeEventListener('keydown', this.checkForEnterWrapper); this.filteredSearchInput.removeEventListener('keyup', this.checkForBackspaceWrapper); @@ -101,12 +104,25 @@ } } + handleInputPlaceholder() { + const query = gl.DropdownUtils.getSearchQuery(); + const placeholder = 'Search or filter results...'; + const currentPlaceholder = this.filteredSearchInput.placeholder; + + if (query.length === 0 && currentPlaceholder !== placeholder) { + this.filteredSearchInput.placeholder = placeholder; + } else if (query.length > 0 && currentPlaceholder !== '') { + this.filteredSearchInput.placeholder = ''; + } + } + clearSearch(e) { e.preventDefault(); this.filteredSearchInput.value = ''; this.filteredSearchInput.parentElement.querySelector('.tokens-container').innerHTML = ''; this.clearSearchButton.classList.add('hidden'); + this.handleInputPlaceholder(); this.dropdownManager.resetDropdowns(); } @@ -214,6 +230,7 @@ if (hasFilteredSearch) { this.clearSearchButton.classList.remove('hidden'); + this.handleInputPlaceholder(); } } diff --git a/spec/features/merge_requests/reset_filters_spec.rb b/spec/features/merge_requests/reset_filters_spec.rb index 16fd15599e6..6fed1568fcf 100644 --- a/spec/features/merge_requests/reset_filters_spec.rb +++ b/spec/features/merge_requests/reset_filters_spec.rb @@ -24,67 +24,93 @@ feature 'Merge requests filter clear button', feature: true, js: true do context 'when a milestone filter has been applied' do it 'resets the milestone filter' do visit_merge_requests(project, milestone_title: milestone.title) + expect(page).to have_css(merge_request_css, count: 1) + expect(get_filtered_search_placeholder).to eq('') reset_filters + expect(page).to have_css(merge_request_css, count: 2) + expect(get_filtered_search_placeholder).to eq(default_placeholder) end end context 'when a label filter has been applied' do it 'resets the label filter' do visit_merge_requests(project, label_name: bug.name) + expect(page).to have_css(merge_request_css, count: 1) + expect(get_filtered_search_placeholder).to eq('') reset_filters + expect(page).to have_css(merge_request_css, count: 2) + expect(get_filtered_search_placeholder).to eq(default_placeholder) end end context 'when a text search has been conducted' do it 'resets the text search filter' do visit_merge_requests(project, search: 'Bug') + expect(page).to have_css(merge_request_css, count: 1) + expect(get_filtered_search_placeholder).to eq('') reset_filters + expect(page).to have_css(merge_request_css, count: 2) + expect(get_filtered_search_placeholder).to eq(default_placeholder) end end context 'when author filter has been applied' do it 'resets the author filter' do visit_merge_requests(project, author_username: user.username) + expect(page).to have_css(merge_request_css, count: 1) + expect(get_filtered_search_placeholder).to eq('') reset_filters + expect(page).to have_css(merge_request_css, count: 2) + expect(get_filtered_search_placeholder).to eq(default_placeholder) end end context 'when assignee filter has been applied' do it 'resets the assignee filter' do visit_merge_requests(project, assignee_username: user.username) + expect(page).to have_css(merge_request_css, count: 1) + expect(get_filtered_search_placeholder).to eq('') reset_filters + expect(page).to have_css(merge_request_css, count: 2) + expect(get_filtered_search_placeholder).to eq(default_placeholder) end end context 'when all filters have been applied' do it 'clears all filters' do visit_merge_requests(project, assignee_username: user.username, author_username: user.username, milestone_title: milestone.title, label_name: bug.name, search: 'Bug') + expect(page).to have_css(merge_request_css, count: 0) + expect(get_filtered_search_placeholder).to eq('') reset_filters + expect(page).to have_css(merge_request_css, count: 2) + expect(get_filtered_search_placeholder).to eq(default_placeholder) end end context 'when no filters have been applied' do it 'the clear button should not be visible' do visit_merge_requests(project) + expect(page).to have_css(merge_request_css, count: 2) + expect(get_filtered_search_placeholder).to eq(default_placeholder) expect(page).not_to have_css(clear_search_css) end end diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 index 98959dda242..2440e55bb47 100644 --- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 @@ -7,14 +7,12 @@ require('~/filtered_search/filtered_search_manager'); (() => { describe('Filtered Search Manager', () => { + let input; + describe('search', () => { let manager; const defaultParams = '?scope=all&utf8=✓&state=opened'; - function getInput() { - return document.querySelector('.filtered-search'); - } - beforeEach(() => { setFixtures(` @@ -26,15 +24,16 @@ require('~/filtered_search/filtered_search_manager'); spyOn(gl.FilteredSearchDropdownManager.prototype, 'setDropdown').and.callFake(() => {}); spyOn(gl.utils, 'getParameterByName').and.returnValue(null); + input = document.querySelector('.filtered-search'); manager = new gl.FilteredSearchManager(); }); afterEach(() => { - getInput().outerHTML = ''; + input.outerHTML = ''; }); it('should search with a single word', () => { - getInput().value = 'searchTerm'; + input.value = 'searchTerm'; spyOn(gl.utils, 'visitUrl').and.callFake((url) => { expect(url).toEqual(`${defaultParams}&search=searchTerm`); @@ -44,7 +43,7 @@ require('~/filtered_search/filtered_search_manager'); }); it('should search with multiple words', () => { - getInput().value = 'awesome search terms'; + input.value = 'awesome search terms'; spyOn(gl.utils, 'visitUrl').and.callFake((url) => { expect(url).toEqual(`${defaultParams}&search=awesome+search+terms`); @@ -54,7 +53,7 @@ require('~/filtered_search/filtered_search_manager'); }); it('should search with special characters', () => { - getInput().value = '~!@#$%^&*()_+{}:<>,.?/'; + input.value = '~!@#$%^&*()_+{}:<>,.?/'; spyOn(gl.utils, 'visitUrl').and.callFake((url) => { expect(url).toEqual(`${defaultParams}&search=~!%40%23%24%25%5E%26*()_%2B%7B%7D%3A%3C%3E%2C.%3F%2F`); @@ -63,5 +62,63 @@ require('~/filtered_search/filtered_search_manager'); manager.search(); }); }); + + describe('handleInputPlaceholder', () => { + const placeholder = 'Search or filter results...'; + let tokensContainer; + + beforeEach(() => { + setFixtures(` +
+ + + +
+ `); + + spyOn(gl.FilteredSearchManager.prototype, 'cleanup').and.callFake(() => {}); + spyOn(gl.FilteredSearchManager.prototype, 'loadSearchParamsFromURL').and.callFake(() => {}); + spyOn(gl.FilteredSearchDropdownManager.prototype, 'setDropdown').and.callFake(() => {}); + spyOn(gl.utils, 'getParameterByName').and.returnValue(null); + + input = document.querySelector('.filtered-search'); + tokensContainer = document.querySelector('.tokens-container'); + return new gl.FilteredSearchManager(); + }); + + afterEach(() => { + input.outerHTML = ''; + tokensContainer.innerHTML = ''; + }); + + it('should render placeholder when there is no input', () => { + expect(input.placeholder).toEqual(placeholder); + }); + + it('should not render placeholder when there is input', () => { + input.value = 'test words'; + + const event = new Event('input'); + input.dispatchEvent(event); + + expect(input.placeholder).toEqual(''); + }); + + it('should not render placeholder when there are tokens and no input', () => { + tokensContainer.innerHTML = ` +
  • +
    label
    +
    ~bug
    +
  • + `; + + const event = new Event('input'); + input.dispatchEvent(event); + + expect(input.placeholder).toEqual(''); + }); + }); }); })(); diff --git a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js.es6 index 19f797a034e..4f07dfbd7d9 100644 --- a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js.es6 @@ -12,7 +12,7 @@ require('~/filtered_search/filtered_search_visual_tokens'); }); afterEach(() => { - document.querySelector('.tokens-container').innerHTML = ''; + tokensContainer.innerHTML = ''; }); describe('getLastVisualToken', () => { diff --git a/spec/support/filtered_search_helpers.rb b/spec/support/filtered_search_helpers.rb index f43379f258e..62c40b431c7 100644 --- a/spec/support/filtered_search_helpers.rb +++ b/spec/support/filtered_search_helpers.rb @@ -52,4 +52,12 @@ module FilteredSearchHelpers end end end + + def default_placeholder + 'Search or filter results...' + end + + def get_filtered_search_placeholder + find('.filtered-search')['placeholder'] + end end -- cgit v1.2.1