mirror of
https://github.com/plausible/analytics.git
synced 2024-12-25 10:33:01 +03:00
518cdb3307
* Migration: add country rules * Add CountryRule schema * Implement CountryRule cache * Add country rules context interface * Start country rules cache * Lookup country rules on ingestion * Remove :shields feature flag from test helpers * Add nested sidebar menu for Shields * Fix typo * IP Rules: hide description on mobile view * Prepare SiteController to handle multiple shield types * Seed some country shield * Implement LV for country rules * Remove "YOU" indicator from country rules * Fix small build * Format * Update typespecs * Make docs link point at /countries * Fix flash on top of modal for Safari * Build the rule struct with site_id provided up-front * Clarify why we're messaging the ComboBox component * Re-open combobox suggestions after pressing Escape * Update changelog * Fix font size in country table cells * Pass `added_by` via rule add options * Display site's timezone timestamps in rule tooltips * Display formatted timestamps in site's timezone And simplify+test Timezone module; an input timestamp converted to UTC can never be ambiguous. * Remove no-op atom * Display the maximum number of rules when reached * Improve readability of remove button tests * Credo --------- Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
84 lines
2.1 KiB
JavaScript
84 lines
2.1 KiB
JavaScript
// Courtesy of Benjamin von Polheim:
|
|
// https://blog.devgenius.io/build-a-performat-autocomplete-using-phoenix-liveview-and-alpine-js-8bcbbed17ba7
|
|
|
|
export default (id) => ({
|
|
isOpen: false,
|
|
id: id,
|
|
focus: null,
|
|
selectionInProgress: false,
|
|
setFocus(f) {
|
|
this.focus = f;
|
|
},
|
|
initFocus() {
|
|
if (this.focus === null) {
|
|
this.setFocus(this.leastFocusableIndex())
|
|
}
|
|
},
|
|
trackSubmitValueChange() {
|
|
this.selectionInProgress = false;
|
|
},
|
|
open() {
|
|
if (!this.isOpen) {
|
|
this.initFocus()
|
|
this.isOpen = true
|
|
}
|
|
},
|
|
suggestionsCount() {
|
|
return this.$refs.suggestions?.querySelectorAll('li').length
|
|
},
|
|
hasCreatableOption() {
|
|
return this.$refs.suggestions?.querySelector('li').classList.contains("creatable")
|
|
},
|
|
leastFocusableIndex() {
|
|
if (this.suggestionsCount() === 0) {
|
|
return 0
|
|
}
|
|
return this.hasCreatableOption() ? 0 : 1
|
|
},
|
|
maxFocusableIndex() {
|
|
return this.hasCreatableOption() ? this.suggestionsCount() - 1 : this.suggestionsCount()
|
|
},
|
|
nextFocusableIndex() {
|
|
const currentFocus = this.focus
|
|
return currentFocus + 1 > this.maxFocusableIndex() ? this.leastFocusableIndex() : currentFocus + 1
|
|
},
|
|
prevFocusableIndex() {
|
|
const currentFocus = this.focus
|
|
return currentFocus - 1 >= this.leastFocusableIndex() ? currentFocus - 1 : this.maxFocusableIndex()
|
|
},
|
|
close(e) {
|
|
// Pressing Escape should not propagate to window,
|
|
// so we'll only close the suggestions pop-up
|
|
if (this.isOpen && e.key === "Escape") {
|
|
e.stopPropagation()
|
|
}
|
|
this.isOpen = false
|
|
},
|
|
select() {
|
|
this.$refs[`dropdown-${this.id}-option-${this.focus}`]?.click()
|
|
this.close()
|
|
document.getElementById(this.id).blur()
|
|
},
|
|
scrollTo(idx) {
|
|
this.$refs[`dropdown-${this.id}-option-${idx}`]?.scrollIntoView(
|
|
{ block: 'nearest', behavior: 'smooth', inline: 'start' }
|
|
)
|
|
},
|
|
focusNext() {
|
|
const nextIndex = this.nextFocusableIndex()
|
|
|
|
this.open()
|
|
|
|
this.setFocus(nextIndex)
|
|
this.scrollTo(nextIndex)
|
|
},
|
|
focusPrev() {
|
|
const prevIndex = this.prevFocusableIndex()
|
|
|
|
this.open()
|
|
|
|
this.setFocus(prevIndex)
|
|
this.scrollTo(prevIndex)
|
|
}
|
|
})
|