wip: make it simpler to create an autocomplete class

This commit is contained in:
Yohan Boniface 2024-05-23 16:47:08 +02:00
parent e51347e239
commit 5b914c1bd2
3 changed files with 106 additions and 89 deletions

View file

@ -1,6 +1,11 @@
import { DomUtil, DomEvent, setOptions } from '../../vendors/leaflet/leaflet-src.esm.js' import {
DomUtil,
DomEvent,
setOptions,
Util,
} from '../../vendors/leaflet/leaflet-src.esm.js'
import { translate } from './i18n.js' import { translate } from './i18n.js'
import { ServerRequest } from './request.js' import { Request, ServerRequest } from './request.js'
export class BaseAutocomplete { export class BaseAutocomplete {
constructor(el, options) { constructor(el, options) {
@ -216,11 +221,17 @@ export class BaseAutocomplete {
} }
} }
class BaseAjax extends BaseAutocomplete { export class BaseAjax extends BaseAutocomplete {
URL = '/foobar/?q={q}'
constructor(el, options) { constructor(el, options) {
super(el, options) super(el, options)
this.server = new ServerRequest() this.initRequest()
} }
initRequest() {
this.request = new Request()
}
optionToResult(option) { optionToResult(option) {
return { return {
value: option.value, value: option.value,
@ -237,71 +248,94 @@ class BaseAjax extends BaseAutocomplete {
if (val === this.cache) return if (val === this.cache) return
else this.cache = val else this.cache = val
val = val.toLowerCase() val = val.toLowerCase()
const [{ data }, response] = await this.server.get( const url = Util.template(this.URL, {q: encodeURIComponent(val)})
`/agnocomplete/AutocompleteUser/?q=${encodeURIComponent(val)}` this.handleResults(await this._search(url))
) }
this.handleResults(data)
async _search(url) {
const response = await this.request.get(url)
if (response && response.ok) {
return await response.json()
}
} }
} }
export class AjaxAutocompleteMultiple extends BaseAjax { class BaseServerAjax extends BaseAjax {
initSelectedContainer() { URL = '/agnocomplete/AutocompleteUser/?q={q}'
return DomUtil.after( initRequest() {
this.input, this.server = new ServerRequest()
DomUtil.element({ tagName: 'ul', className: 'umap-multiresult' })
)
} }
async _search(url) {
displaySelected(result) { const [{ data }, response] = await this.server.get(url)
const result_el = DomUtil.element({ return data
tagName: 'li',
parent: this.selectedContainer,
})
result_el.textContent = result.item.label
const close = DomUtil.element({
tagName: 'span',
parent: result_el,
className: 'close',
textContent: '×',
})
DomEvent.on(close, 'click', () => {
this.selectedContainer.removeChild(result_el)
this.options.on_unselect(result)
})
this.hide()
} }
} }
export class AjaxAutocomplete extends BaseAjax { export const SingleMixin = (Base) =>
initSelectedContainer() { class extends Base {
return DomUtil.after( initSelectedContainer() {
this.input, return DomUtil.after(
DomUtil.element({ tagName: 'div', className: 'umap-singleresult' }) this.input,
) DomUtil.element({ tagName: 'div', className: 'umap-singleresult' })
)
}
displaySelected(result) {
const result_el = DomUtil.element({
tagName: 'div',
parent: this.selectedContainer,
})
result_el.textContent = result.item.label
const close = DomUtil.element({
tagName: 'span',
parent: result_el,
className: 'close',
textContent: '×',
})
this.input.style.display = 'none'
DomEvent.on(
close,
'click',
function () {
this.selectedContainer.innerHTML = ''
this.input.style.display = 'block'
},
this
)
this.hide()
}
} }
displaySelected(result) { export const MultipleMixin = (Base) =>
const result_el = DomUtil.element({ class extends Base {
tagName: 'div', initSelectedContainer() {
parent: this.selectedContainer, return DomUtil.after(
}) this.input,
result_el.textContent = result.item.label DomUtil.element({ tagName: 'ul', className: 'umap-multiresult' })
const close = DomUtil.element({ )
tagName: 'span', }
parent: result_el,
className: 'close', displaySelected(result) {
textContent: '×', const result_el = DomUtil.element({
}) tagName: 'li',
this.input.style.display = 'none' parent: this.selectedContainer,
DomEvent.on( })
close, result_el.textContent = result.item.label
'click', const close = DomUtil.element({
function () { tagName: 'span',
this.selectedContainer.innerHTML = '' parent: result_el,
this.input.style.display = 'block' className: 'close',
}, textContent: '×',
this })
) DomEvent.on(close, 'click', () => {
this.hide() this.selectedContainer.removeChild(result_el)
this.options.on_unselect(result)
})
this.hide()
}
} }
}
export class AjaxAutocompleteMultiple extends MultipleMixin(BaseServerAjax) {}
export class AjaxAutocomplete extends SingleMixin(BaseServerAjax) {}

View file

@ -42,9 +42,13 @@ export default class Importer {
parent: this.container, parent: this.container,
textContent: translate('Import from:'), textContent: translate('Import from:'),
}) })
const plugins = L.DomUtil.element({tagName: 'div', className: 'umap-multiplechoice by2', parent: this.container}) const plugins = L.DomUtil.element({
tagName: 'div',
className: 'umap-multiplechoice by2',
parent: this.container,
})
for (const plugin of this.map.plugins) { for (const plugin of this.map.plugins) {
const {name, callback} = plugin.addImporter() const { name, callback } = plugin.addImporter()
L.DomUtil.createButton('flat', plugins, name, () => callback.bind(plugin)(this)) L.DomUtil.createButton('flat', plugins, name, () => callback.bind(plugin)(this))
} }
this.typeLabel = L.DomUtil.add( this.typeLabel = L.DomUtil.add(

View file

@ -1,15 +1,12 @@
import { DomUtil, DomEvent, stamp } from '../../../vendors/leaflet/leaflet-src.esm.js' import { DomUtil, DomEvent, stamp } from '../../../vendors/leaflet/leaflet-src.esm.js'
import { translate } from '../i18n.js' import { translate } from '../i18n.js'
import { AjaxAutocomplete } from '../autocomplete.js' import { BaseAjax, SingleMixin } from '../autocomplete.js'
import { Request } from '../request.js' import { Request } from '../request.js'
import Alert from '../ui/alert.js' import Alert from '../ui/alert.js'
import Dialog from '../ui/dialog.js' import Dialog from '../ui/dialog.js'
class Autocomplete extends AjaxAutocomplete { class Autocomplete extends SingleMixin(BaseAjax) {
constructor(request, el, options) { URL = 'https://geodatamine.fr/boundaries/search?text={q}'
super(el, options)
this.request = request
}
createResult(item) { createResult(item) {
return super.createResult({ return super.createResult({
@ -17,24 +14,6 @@ class Autocomplete extends AjaxAutocomplete {
label: `${item.name} (${item.ref})`, label: `${item.name} (${item.ref})`,
}) })
} }
async search() {
let val = this.input.value
if (val.length < this.options.minChar) {
this.clear()
return
}
if (`${val}` === `${this.cache}`) return
else this.cache = val
val = val.toLowerCase()
const response = await this.request.get(
`https://geodatamine.fr/boundaries/search?text=${encodeURIComponent(val)}`
)
if (response && response.ok) {
const data = await response.json()
this.handleResults(data)
}
}
} }
export class Plugin { export class Plugin {
@ -83,7 +62,7 @@ export class Plugin {
className: 'edit-owner', className: 'edit-owner',
on_select: (choice) => this.onSelect(choice), on_select: (choice) => this.onSelect(choice),
} }
this.autocomplete = new Autocomplete(this.request, container, options) this.autocomplete = new Autocomplete(container, options)
const confirm = () => { const confirm = () => {
importer.urlInput.value = `${this.baseUrl}/data/${select.value}/${this.options.boundary}?format=geojson` importer.urlInput.value = `${this.baseUrl}/data/${select.value}/${this.options.boundary}?format=geojson`
importer.typeInput.value = 'geojson' importer.typeInput.value = 'geojson'