find-menu.js
1 /* global CustomEvent, customElements, HTMLElement */ 2 3 class FindMenu extends HTMLElement { 4 constructor () { 5 super() 6 7 this.addEventListener('keydown', ({ key }) => { 8 if (key === 'Escape') this.hide() 9 }) 10 } 11 12 connectedCallback () { 13 this.innerHTML = ` 14 <input class="find-menu-input" title="Enter text to find in page" /> 15 <button class="find-menu-button find-menu-previous" title="Find previous item">▲</button> 16 <button class="find-menu-button find-menu-next" title="Find next item">▼</button> 17 <button class="find-menu-button find-menu-hide" title="Hide find menu">✖</button> 18 ` 19 20 this.input = this.$('.find-menu-input') 21 this.previousButton = this.$('.find-menu-previous') 22 this.nextButton = this.$('.find-menu-next') 23 this.hideButton = this.$('.find-menu-hide') 24 25 this.input.addEventListener('input', (e) => { 26 const { value } = this 27 28 if (!value) return 29 30 this.dispatchEvent(new CustomEvent('next', { detail: { value } })) 31 }) 32 33 this.input.addEventListener('keydown', ({ keyCode, shiftKey }) => { 34 if (keyCode === 13) { 35 const { value } = this 36 37 if (!value) return this.hide() 38 39 const direction = shiftKey ? 'previous' : 'next' 40 this.dispatchEvent(new CustomEvent(direction, { detail: { value, findNext: true } })) 41 } 42 }) 43 44 this.previousButton.addEventListener('click', () => { 45 const { value } = this 46 47 if (!value) return 48 49 this.dispatchEvent(new CustomEvent('previous', { detail: { value, findNext: false } })) 50 }) 51 this.nextButton.addEventListener('click', () => { 52 const { value } = this 53 54 if (!value) return 55 56 this.dispatchEvent(new CustomEvent('next', { detail: { value, findNext: true } })) 57 }) 58 this.hideButton.addEventListener('click', () => this.hide()) 59 } 60 61 get value () { 62 return this.input.value 63 } 64 65 show () { 66 this.classList.toggle('hidden', false) 67 setTimeout(() => { 68 this.focus() 69 }, 10) 70 } 71 72 hide () { 73 this.classList.toggle('hidden', true) 74 this.dispatchEvent(new CustomEvent('hide')) 75 } 76 77 toggle () { 78 const isActive = this.classList.toggle('hidden') 79 if (isActive) this.focus() 80 else this.dispatchEvent(new CustomEvent('hide')) 81 } 82 83 focus () { 84 this.input.focus() 85 this.input.select() 86 } 87 88 $ (query) { 89 return this.querySelector(query) 90 } 91 } 92 93 customElements.define('find-menu', FindMenu)