diff options
author | Clement Ho <ClemMakesApps@gmail.com> | 2017-02-24 10:09:53 -0600 |
---|---|---|
committer | Clement Ho <ClemMakesApps@gmail.com> | 2017-03-01 10:14:08 -0600 |
commit | 7f337c9ded66f1b90b689ee2f5563dbb091ca942 (patch) | |
tree | 91ffcef01930435c8b39ab1c9ce1435cd7e43d97 | |
parent | 6d10767fb6bb5197f20260203264739bbb0e0e4a (diff) | |
download | gitlab-ce-highlight-selected-tokens-deletable.tar.gz |
Allow visual tokens to be deletable after selectionhighlight-selected-tokens-deletable
4 files changed, 111 insertions, 15 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 d216fff07e3..935daf3199b 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 @@ -33,6 +33,7 @@ this.checkForEnterWrapper = this.checkForEnter.bind(this); this.clearSearchWrapper = this.clearSearch.bind(this); this.checkForBackspaceWrapper = this.checkForBackspace.bind(this); + this.removeSelectedTokenWrapper = this.removeSelectedToken.bind(this); this.tokenChange = this.tokenChange.bind(this); this.filteredSearchInput.form.addEventListener('submit', this.handleFormSubmit); @@ -47,6 +48,7 @@ this.tokensContainer.addEventListener('click', FilteredSearchManager.selectToken); this.clearSearchButton.addEventListener('click', this.clearSearchWrapper); document.addEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens); + document.addEventListener('keydown', this.removeSelectedTokenWrapper); } unbindEvents() { @@ -62,6 +64,7 @@ this.tokensContainer.removeEventListener('click', FilteredSearchManager.selectToken); this.clearSearchButton.removeEventListener('click', this.clearSearchWrapper); document.removeEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens); + document.removeEventListener('keydown', this.removeSelectedTokenWrapper); } checkForBackspace(e) { @@ -138,6 +141,16 @@ } } + removeSelectedToken(e) { + // 8 = Backspace Key + // 46 = Delete Key + if (e.keyCode === 8 || e.keyCode === 46) { + gl.FilteredSearchVisualTokens.removeSelectedToken(); + this.handleInputPlaceholder(); + this.toggleClearSearchButton(); + } + } + clearSearch(e) { e.preventDefault(); diff --git a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js.es6 index 3b04c6ef6fa..4f3efea8e16 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js.es6 @@ -23,6 +23,15 @@ class FilteredSearchVisualTokens { } } + static removeSelectedToken() { + const selected = document.querySelector('.js-visual-token .selected'); + + if (selected) { + const li = selected.closest('.js-visual-token'); + li.parentElement.removeChild(li); + } + } + static addVisualTokenElement(name, value, isSearchTerm) { const li = document.createElement('li'); li.classList.add('js-visual-token'); 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 51582251cbe..8312928a8c5 100644 --- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 @@ -13,6 +13,20 @@ const FilteredSearchSpecHelper = require('../helpers/filtered_search_spec_helper let tokensContainer; const placeholder = 'Search or filter results...'; + function dispatchBackspaceEvent(element, eventType) { + const backspaceKey = 8; + const event = new Event(eventType); + event.keyCode = backspaceKey; + element.dispatchEvent(event); + } + + function dispatchDeleteEvent(element, eventType) { + const deleteKey = 46; + const event = new Event(eventType); + event.keyCode = deleteKey; + element.dispatchEvent(event); + } + beforeEach(() => { setFixtures(` <form> @@ -99,9 +113,6 @@ const FilteredSearchSpecHelper = require('../helpers/filtered_search_spec_helper }); describe('checkForBackspace', () => { - const backspaceKey = 8; - const deleteKey = 46; - describe('tokens and no input', () => { beforeEach(() => { tokensContainer.innerHTML = FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug'); @@ -109,20 +120,14 @@ const FilteredSearchSpecHelper = require('../helpers/filtered_search_spec_helper it('removes last token', () => { spyOn(gl.FilteredSearchVisualTokens, 'removeLastTokenPartial').and.callThrough(); - - const event = new Event('keyup'); - event.keyCode = backspaceKey; - input.dispatchEvent(event); + dispatchBackspaceEvent(input, 'keyup'); expect(gl.FilteredSearchVisualTokens.removeLastTokenPartial).toHaveBeenCalled(); }); it('sets the input', () => { spyOn(gl.FilteredSearchVisualTokens, 'getLastTokenPartial').and.callThrough(); - - const event = new Event('keyup'); - event.keyCode = deleteKey; - input.dispatchEvent(event); + dispatchDeleteEvent(input, 'keyup'); expect(gl.FilteredSearchVisualTokens.getLastTokenPartial).toHaveBeenCalled(); expect(input.value).toEqual('~bug'); @@ -134,10 +139,7 @@ const FilteredSearchSpecHelper = require('../helpers/filtered_search_spec_helper spyOn(gl.FilteredSearchVisualTokens, 'getLastTokenPartial').and.callThrough(); input.value = 'text'; - - const event = new Event('keyup'); - event.keyCode = deleteKey; - input.dispatchEvent(event); + dispatchDeleteEvent(input, 'keyup'); expect(gl.FilteredSearchVisualTokens.removeLastTokenPartial).not.toHaveBeenCalled(); expect(gl.FilteredSearchVisualTokens.getLastTokenPartial).not.toHaveBeenCalled(); @@ -145,6 +147,56 @@ const FilteredSearchSpecHelper = require('../helpers/filtered_search_spec_helper }); }); + describe('removeSelectedToken', () => { + beforeEach(() => { + tokensContainer.innerHTML = FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'none', true); + }); + + it('removes selected token when the backspace key is pressed', () => { + expect(tokensContainer.children.length).toEqual(1); + + dispatchBackspaceEvent(document, 'keydown'); + + expect(tokensContainer.children.length).toEqual(0); + }); + + it('removes selected token when the delete key is pressed', () => { + tokensContainer.innerHTML = FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'none', true); + + expect(tokensContainer.children.length).toEqual(1); + + dispatchDeleteEvent(document, 'keydown'); + + expect(tokensContainer.children.length).toEqual(0); + }); + + it('updates the input placeholder after removal', () => { + manager.handleInputPlaceholder(); + + expect(input.placeholder).toEqual(''); + expect(tokensContainer.children.length).toEqual(1); + + dispatchBackspaceEvent(document, 'keydown'); + + expect(input.placeholder).not.toEqual(''); + expect(tokensContainer.children.length).toEqual(0); + }); + + it('updates the clear button after removal', () => { + manager.toggleClearSearchButton(); + + const clearButton = document.querySelector('.clear-search'); + + expect(clearButton.classList.contains('hidden')).toEqual(false); + expect(tokensContainer.children.length).toEqual(1); + + dispatchBackspaceEvent(document, 'keydown'); + + expect(clearButton.classList.contains('hidden')).toEqual(true); + expect(tokensContainer.children.length).toEqual(0); + }); + }); + describe('unselects token', () => { beforeEach(() => { tokensContainer.innerHTML = ` 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 ff21d096f9d..4d6eda83e79 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 @@ -138,6 +138,28 @@ const FilteredSearchSpecHelper = require('../helpers/filtered_search_spec_helper }); }); + describe('removeSelectedToken', () => { + it('does not remove when there are no selected tokens', () => { + tokensContainer.innerHTML = FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'none'); + + expect(tokensContainer.querySelector('.js-visual-token .selectable')).not.toEqual(null); + + gl.FilteredSearchVisualTokens.removeSelectedToken(); + + expect(tokensContainer.querySelector('.js-visual-token .selectable')).not.toEqual(null); + }); + + it('removes selected token', () => { + tokensContainer.innerHTML = FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'none', true); + + expect(tokensContainer.querySelector('.js-visual-token .selectable')).not.toEqual(null); + + gl.FilteredSearchVisualTokens.removeSelectedToken(); + + expect(tokensContainer.querySelector('.js-visual-token .selectable')).toEqual(null); + }); + }); + describe('addVisualTokenElement', () => { it('renders search visual tokens', () => { gl.FilteredSearchVisualTokens.addVisualTokenElement('search term', null, true); |