Skip to content

Commit 68eb389

Browse files
committed
Migrate script
1 parent d97d34b commit 68eb389

File tree

1 file changed

+86
-5
lines changed

1 file changed

+86
-5
lines changed

index.js

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,96 @@
11
/* @flow strict */
22

33
class FilterableInputElement extends HTMLElement {
4-
constructor() {
5-
super()
6-
}
4+
currentQuery: ?string
5+
debounceInputChange: Event => void
6+
boundFetchResults: Event => mixed
77

88
connectedCallback() {
9-
this.textContent = ':wave:'
9+
const input = this.input
10+
if (!input) return
11+
12+
input.setAttribute('autocomplete', 'off')
13+
input.setAttribute('spellcheck', 'false')
14+
15+
this.debounceInputChange = debounce(this.fetchResults.bind(this))
16+
this.boundFetchResults = this.fetchResults.bind(this)
17+
input.addEventListener('focus', this.boundFetchResults)
18+
input.addEventListener('change', this.boundFetchResults)
19+
input.addEventListener('input', this.debounceInputChange)
20+
}
21+
22+
disconnectedCallback() {
23+
const input = this.input
24+
if (!input) return
25+
26+
input.removeEventListener('focus', this.boundFetchResults)
27+
input.removeEventListener('change', this.boundFetchResults)
28+
input.removeEventListener('input', this.debounceInputChange)
29+
}
30+
31+
get input(): ?HTMLInputElement {
32+
const input = this.querySelector('input')
33+
return input instanceof HTMLInputElement ? input : null
34+
}
35+
36+
get resultsContainer(): ?HTMLElement {
37+
return document.getElementById(this.getAttribute('aria-owns') || '')
38+
}
39+
40+
get src(): string {
41+
return this.getAttribute('src') || ''
1042
}
1143

12-
disconnectedCallback() {}
44+
set src(url: string) {
45+
this.setAttribute('src', url)
46+
}
47+
48+
get name(): string {
49+
return this.getAttribute('name') || 'q'
50+
}
51+
52+
set name(name: string) {
53+
this.setAttribute('name', name)
54+
}
55+
56+
async fetchResults() {
57+
if (!this.input) return
58+
const query = this.input.value.trim()
59+
if (this.currentQuery === query) return
60+
this.currentQuery = query
61+
const src = this.src
62+
if (!src) return
63+
const resultsContainer = this.resultsContainer
64+
if (!resultsContainer) return
65+
66+
const url = new URL(src, window.location.origin)
67+
const params = new URLSearchParams(url.search)
68+
params.append(this.name, query)
69+
url.search = params.toString()
70+
71+
this.dispatchEvent(new CustomEvent('loadstart'))
72+
this.setAttribute('loading', '')
73+
try {
74+
const html = await fetch(url).then(data => data.text())
75+
this.dispatchEvent(new CustomEvent('load'))
76+
resultsContainer.innerHTML = html
77+
} catch (err) {
78+
this.dispatchEvent(new CustomEvent('error'))
79+
}
80+
this.removeAttribute('loading')
81+
this.dispatchEvent(new CustomEvent('loadend'))
82+
}
83+
}
84+
85+
function debounce(callback) {
86+
let timeout
87+
return function() {
88+
clearTimeout(timeout)
89+
timeout = setTimeout(() => {
90+
clearTimeout(timeout)
91+
callback()
92+
}, 300)
93+
}
1394
}
1495

1596
export default FilterableInputElement

0 commit comments

Comments
 (0)