diff --git a/umap/static/umap/js/modules/autocomplete.js b/umap/static/umap/js/modules/autocomplete.js
index 31d5d196..e693d6be 100644
--- a/umap/static/umap/js/modules/autocomplete.js
+++ b/umap/static/umap/js/modules/autocomplete.js
@@ -6,6 +6,7 @@ import {
} from '../../vendors/leaflet/leaflet-src.esm.js'
import { translate } from './i18n.js'
import { Request, ServerRequest } from './request.js'
+import { escapeHTML, generateId } from './utils.js'
export class BaseAutocomplete {
constructor(el, options) {
@@ -46,7 +47,7 @@ export class BaseAutocomplete {
placeholder: this.options.placeholder,
autocomplete: 'off',
className: this.options.className,
- name: this.options.name || 'autocomplete'
+ name: this.options.name || 'autocomplete',
})
DomEvent.on(this.input, 'keydown', this.onKeyDown, this)
DomEvent.on(this.input, 'keyup', this.onKeyUp, this)
@@ -350,3 +351,19 @@ export const MultipleMixin = (Base) =>
export class AjaxAutocompleteMultiple extends MultipleMixin(BaseServerAjax) {}
export class AjaxAutocomplete extends SingleMixin(BaseServerAjax) {}
+
+export class AutocompleteDatalist {
+ constructor(input) {
+ this.input = input
+ this.datalist = document.createElement('datalist')
+ this.datalist.id = generateId()
+ this.input.setAttribute('list', this.datalist.id)
+ this.input.parentElement.appendChild(this.datalist)
+ }
+
+ set suggestions(values) {
+ this.datalist.innerHTML = values
+ .map((value) => ``)
+ .join('')
+ }
+}
diff --git a/umap/static/umap/js/modules/global.js b/umap/static/umap/js/modules/global.js
index fe2ef751..1f62f927 100644
--- a/umap/static/umap/js/modules/global.js
+++ b/umap/static/umap/js/modules/global.js
@@ -3,7 +3,7 @@ import {
uMapAlertConflict as AlertConflict,
uMapAlertCreation as AlertCreation,
} from '../components/alerts/alert.js'
-import { AjaxAutocomplete, AjaxAutocompleteMultiple } from './autocomplete.js'
+import { AjaxAutocomplete, AjaxAutocompleteMultiple, AutocompleteDatalist } from './autocomplete.js'
import Browser from './browser.js'
import Caption from './caption.js'
import Facets from './facets.js'
@@ -30,6 +30,7 @@ window.U = {
AlertConflict,
AjaxAutocomplete,
AjaxAutocompleteMultiple,
+ AutocompleteDatalist,
Browser,
Caption,
Dialog,
diff --git a/umap/static/umap/js/modules/ui/dialog.js b/umap/static/umap/js/modules/ui/dialog.js
index 798ef167..25f869fd 100644
--- a/umap/static/umap/js/modules/ui/dialog.js
+++ b/umap/static/umap/js/modules/ui/dialog.js
@@ -181,8 +181,8 @@ export default class Dialog {
return this.open(Object.assign({}, config, { message, template: false }))
}
- prompt(message, fallback = '', config = {}) {
- const template = ``
+ prompt(message, config = {}) {
+ const template = ``
return this.open(Object.assign({}, config, { message, template }))
}
}
diff --git a/umap/static/umap/js/umap.layer.js b/umap/static/umap/js/umap.layer.js
index 857befe0..852e4b07 100644
--- a/umap/static/umap/js/umap.layer.js
+++ b/umap/static/umap/js/umap.layer.js
@@ -919,6 +919,13 @@ U.DataLayer = L.Evented.extend({
if (idx !== -1) this._propertiesIndex.splice(idx, 1)
},
+ sortedValues: function (property) {
+ return Object.values(this._layers)
+ .map((feature) => feature.properties[property])
+ .filter((val, idx, arr) => arr.indexOf(val) === idx)
+ .sort(U.Utils.naturalSort)
+ },
+
addData: function (geojson, sync) {
try {
// Do not fail if remote data is somehow invalid,
diff --git a/umap/static/umap/js/umap.tableeditor.js b/umap/static/umap/js/umap.tableeditor.js
index 509d246d..c9b4c7fe 100644
--- a/umap/static/umap/js/umap.tableeditor.js
+++ b/umap/static/umap/js/umap.tableeditor.js
@@ -101,14 +101,29 @@ U.TableEditor = L.Class.extend({
})
},
- refine: function () {
- const promise = new U.Prompt().open({
- className: 'dark',
- title: L._('Deleting rows matching condition'),
+ deleteRows: function () {
+ const dialog = this.datalayer.map.dialog
+ const promise = dialog.prompt(L._('Deleting rows matching condition'))
+
+ const autocomplete = new U.AutocompleteDatalist(
+ dialog.dialog.querySelector('[name=prompt]')
+ )
+ autocomplete.suggestions = this.datalayer._propertiesIndex
+ autocomplete.input.addEventListener('input', (event) => {
+ const value = event.target.value
+ if (this.datalayer._propertiesIndex.includes(value)) {
+ autocomplete.suggestions = [`${value}=`, `${value}!=`, `${value}>`, `${value}<`]
+ } else if (value.endsWith('=')) {
+ const key = value.split('!')[0].split('=')[0]
+ autocomplete.suggestions = this.datalayer
+ .sortedValues(key)
+ .map((str) => `${value}${str || ''}`)
+ }
})
- promise.then((raw) => {
- if (!raw) return
- const rule = new U.Rule(raw)
+
+ promise.then(({ prompt }) => {
+ if (!prompt) return
+ const rule = new U.Rule(prompt)
const matched = []
this.datalayer.eachLayer((feature) => {
if (rule.match(feature.properties)) {
@@ -148,7 +163,7 @@ U.TableEditor = L.Class.extend({
L.DomUtil.createIcon(refineButton, 'icon-add'),
refineButton.firstChild
)
- L.DomEvent.on(refineButton, 'click', this.refine, this)
+ L.DomEvent.on(refineButton, 'click', this.deleteRows, this)
this.datalayer.map.fullPanel.open({
content: this.table,
className: 'umap-table-editor',