/ app / ui / find-menu.js
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)