Use Leaflet.FormBuilder to build advanced filters form
This commit is contained in:
parent
56cb4b44d0
commit
9abbfbc01e
3 changed files with 69 additions and 81 deletions
|
@ -789,113 +789,68 @@ L.U.Map.include({
|
||||||
L.DomEvent.on(filter, 'input', appendAll, this)
|
L.DomEvent.on(filter, 'input', appendAll, this)
|
||||||
L.DomEvent.on(filter, 'input', resetLayers, this)
|
L.DomEvent.on(filter, 'input', resetLayers, this)
|
||||||
|
|
||||||
this.ui.openPanel({ data: { html: browserContainer }, actions: [this._aboutLink()] })
|
this.ui.openPanel({
|
||||||
|
data: { html: browserContainer },
|
||||||
|
actions: [this._aboutLink()],
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
_openFilter: function () {
|
_openFilter: function () {
|
||||||
const filterContainer = L.DomUtil.create('div', 'umap-filter-data'),
|
const container = L.DomUtil.create('div', 'umap-filter-data'),
|
||||||
title = L.DomUtil.add(
|
title = L.DomUtil.add('h3', 'umap-filter-title', container, this.options.name),
|
||||||
'h3',
|
|
||||||
'umap-filter-title',
|
|
||||||
filterContainer,
|
|
||||||
this.options.name
|
|
||||||
),
|
|
||||||
propertiesContainer = L.DomUtil.create(
|
propertiesContainer = L.DomUtil.create(
|
||||||
'div',
|
'div',
|
||||||
'umap-filter-properties',
|
'umap-filter-properties',
|
||||||
filterContainer
|
container
|
||||||
),
|
),
|
||||||
advancedFilterKeys = this.getAdvancedFilterKeys()
|
keys = this.getAdvancedFilterKeys()
|
||||||
|
|
||||||
const advancedFiltersFull = {}
|
const knownValues = {}
|
||||||
let filtersAlreadyLoaded = true
|
if (!this.options.advancedFilters) this.options.advancedFilters = {}
|
||||||
if (!this.options.advancedFilters) {
|
|
||||||
this.options.advancedFilters = {}
|
keys.forEach((key) => {
|
||||||
filtersAlreadyLoaded = false
|
knownValues[key] = []
|
||||||
}
|
if (!this.options.advancedFilters[key])
|
||||||
advancedFilterKeys.forEach((property) => {
|
this.options.advancedFilters[key] = []
|
||||||
advancedFiltersFull[property] = []
|
|
||||||
if (!filtersAlreadyLoaded || !this.options.advancedFilters[property]) {
|
|
||||||
this.options.advancedFilters[property] = []
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.eachBrowsableDataLayer((datalayer) => {
|
this.eachBrowsableDataLayer((datalayer) => {
|
||||||
datalayer.eachFeature((feature) => {
|
datalayer.eachFeature((feature) => {
|
||||||
advancedFilterKeys.forEach((property) => {
|
keys.forEach((key) => {
|
||||||
if (feature.properties[property]) {
|
let value = feature.properties[key]
|
||||||
if (!advancedFiltersFull[property].includes(feature.properties[property])) {
|
if (typeof value !== 'undefined' && !knownValues[key].includes(value)) {
|
||||||
advancedFiltersFull[property].push(feature.properties[property])
|
knownValues[key].push(value)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const addPropertyValue = function (property, value) {
|
|
||||||
const property_li = L.DomUtil.create('li', ''),
|
|
||||||
filter_check = L.DomUtil.create('input', '', property_li),
|
|
||||||
filter_label = L.DomUtil.create('label', '', property_li)
|
|
||||||
filter_check.type = 'checkbox'
|
|
||||||
filter_check.id = `checkbox_${property}_${value}`
|
|
||||||
filter_check.checked =
|
|
||||||
this.options.advancedFilters[property] &&
|
|
||||||
this.options.advancedFilters[property].includes(value)
|
|
||||||
filter_check.dataset.property = property
|
|
||||||
filter_check.dataset.value = value
|
|
||||||
filter_label.htmlFor = `checkbox_${property}_${value}`
|
|
||||||
filter_label.innerHTML = value
|
|
||||||
L.DomEvent.on(
|
|
||||||
filter_check,
|
|
||||||
'change',
|
|
||||||
function (e) {
|
|
||||||
const property = e.srcElement.dataset.property
|
|
||||||
const value = e.srcElement.dataset.value
|
|
||||||
if (e.srcElement.checked) {
|
|
||||||
this.options.advancedFilters[property].push(value)
|
|
||||||
} else {
|
|
||||||
this.options.advancedFilters[property].splice(
|
|
||||||
this.options.advancedFilters[property].indexOf(value),
|
|
||||||
1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
L.bind(filterFeatures, this)()
|
|
||||||
},
|
|
||||||
this
|
|
||||||
)
|
|
||||||
return property_li
|
|
||||||
}
|
|
||||||
|
|
||||||
const addProperty = function (property) {
|
|
||||||
const container = L.DomUtil.create(
|
|
||||||
'div',
|
|
||||||
'property-container',
|
|
||||||
propertiesContainer
|
|
||||||
),
|
|
||||||
headline = L.DomUtil.add('h5', '', container, property)
|
|
||||||
const ul = L.DomUtil.create('ul', '', container)
|
|
||||||
const orderedValues = advancedFiltersFull[property]
|
|
||||||
orderedValues.sort()
|
|
||||||
orderedValues.forEach((value) => {
|
|
||||||
ul.appendChild(L.bind(addPropertyValue, this)(property, value))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const filterFeatures = function () {
|
const filterFeatures = function () {
|
||||||
let found = false
|
let found = false
|
||||||
this.eachBrowsableDataLayer((datalayer) => {
|
this.eachBrowsableDataLayer((datalayer) => {
|
||||||
datalayer.resetLayer(true)
|
datalayer.resetLayer(true)
|
||||||
if (datalayer.hasDataVisible()) found = true
|
if (datalayer.hasDataVisible()) found = true
|
||||||
})
|
})
|
||||||
|
// TODO: display a results counter in the panel instead.
|
||||||
if (!found)
|
if (!found)
|
||||||
this.ui.alert({ content: L._('No results for these filters'), level: 'info' })
|
this.ui.alert({ content: L._('No results for these filters'), level: 'info' })
|
||||||
}
|
}
|
||||||
|
|
||||||
propertiesContainer.innerHTML = ''
|
const fields = keys.map((current) => [
|
||||||
advancedFilterKeys.forEach((property) => {
|
`options.advancedFilters.${current}`,
|
||||||
L.bind(addProperty, this)(property)
|
{
|
||||||
|
handler: 'AdvancedFilter',
|
||||||
|
choices: knownValues[current],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const builder = new L.U.FormBuilder(this, fields, {
|
||||||
|
makeDirty: false,
|
||||||
|
callback: filterFeatures,
|
||||||
|
callbackContext: this,
|
||||||
})
|
})
|
||||||
|
container.appendChild(builder.build())
|
||||||
|
|
||||||
this.ui.openPanel({ data: { html: filterContainer }, actions: [this._aboutLink()] })
|
this.ui.openPanel({ data: { html: container }, actions: [this._aboutLink()] })
|
||||||
},
|
},
|
||||||
|
|
||||||
_aboutLink: function () {
|
_aboutLink: function () {
|
||||||
|
|
|
@ -87,7 +87,12 @@ L.U.FeatureMixin = {
|
||||||
edit: function (e) {
|
edit: function (e) {
|
||||||
if (!this.map.editEnabled || this.isReadOnly()) return
|
if (!this.map.editEnabled || this.isReadOnly()) return
|
||||||
const container = L.DomUtil.create('div', 'umap-feature-container')
|
const container = L.DomUtil.create('div', 'umap-feature-container')
|
||||||
L.DomUtil.add('h3', `umap-feature-properties ${this.getClassName()}`, container, L._('Feature properties'))
|
L.DomUtil.add(
|
||||||
|
'h3',
|
||||||
|
`umap-feature-properties ${this.getClassName()}`,
|
||||||
|
container,
|
||||||
|
L._('Feature properties')
|
||||||
|
)
|
||||||
|
|
||||||
let builder = new L.U.FormBuilder(this, ['datalayer'], {
|
let builder = new L.U.FormBuilder(this, ['datalayer'], {
|
||||||
callback: function () {
|
callback: function () {
|
||||||
|
|
|
@ -684,6 +684,34 @@ L.FormBuilder.Switch = L.FormBuilder.CheckBox.extend({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
L.FormBuilder.AdvancedFilter = L.FormBuilder.Element.extend({
|
||||||
|
build: function () {
|
||||||
|
this.container = L.DomUtil.create('div', 'property-container', this.parentNode)
|
||||||
|
this.headline = L.DomUtil.add('h5', '', this.container, this.name)
|
||||||
|
this.ul = L.DomUtil.create('ul', '', this.container)
|
||||||
|
const choices = this.options.choices
|
||||||
|
choices.sort()
|
||||||
|
choices.forEach((value) => this.buildLi(value))
|
||||||
|
},
|
||||||
|
|
||||||
|
buildLi: function (value) {
|
||||||
|
const property_li = L.DomUtil.create('li', '', this.ul),
|
||||||
|
input = L.DomUtil.create('input', '', property_li),
|
||||||
|
label = L.DomUtil.create('label', '', property_li)
|
||||||
|
input.type = 'checkbox'
|
||||||
|
input.id = `checkbox_${this.name}_${value}`
|
||||||
|
input.checked = this.get().includes(value)
|
||||||
|
input.dataset.value = value
|
||||||
|
label.htmlFor = `checkbox_${this.name}_${value}`
|
||||||
|
label.innerHTML = value
|
||||||
|
L.DomEvent.on(input, 'change', (e) => this.sync())
|
||||||
|
},
|
||||||
|
|
||||||
|
toJS: function () {
|
||||||
|
return [...this.ul.querySelectorAll('input:checked')].map(i => i.dataset.value)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
L.FormBuilder.MultiChoice = L.FormBuilder.Element.extend({
|
L.FormBuilder.MultiChoice = L.FormBuilder.Element.extend({
|
||||||
default: 'null',
|
default: 'null',
|
||||||
className: 'umap-multiplechoice',
|
className: 'umap-multiplechoice',
|
||||||
|
@ -1125,7 +1153,7 @@ L.U.FormBuilder = L.FormBuilder.extend({
|
||||||
|
|
||||||
setter: function (field, value) {
|
setter: function (field, value) {
|
||||||
L.FormBuilder.prototype.setter.call(this, field, value)
|
L.FormBuilder.prototype.setter.call(this, field, value)
|
||||||
this.obj.isDirty = true
|
if (this.options.makeDirty !== false) this.obj.isDirty = true
|
||||||
},
|
},
|
||||||
|
|
||||||
finish: function () {
|
finish: function () {
|
||||||
|
|
Loading…
Reference in a new issue