Support date properties in facet search - split type into dataType and inputType

This commit is contained in:
flammermann 2024-01-03 02:25:10 +00:00 committed by Yohan Boniface
parent 2c48b97b4b
commit 839bb4c5d8
6 changed files with 50 additions and 21 deletions

View file

@ -263,6 +263,10 @@ input[type="checkbox"] + label {
display: inline; display: inline;
padding: 0 14px; padding: 0 14px;
} }
input[type="radio"] + label {
display: inline;
padding: 0 14px;
}
select + .error, select + .error,
input + .error { input + .error {
display: block; display: block;

View file

@ -669,22 +669,26 @@ const ControlsMixin = {
const facetCriteria = {} const facetCriteria = {}
keys.forEach((key) => { keys.forEach((key) => {
if (facetKeys[key]["type"] === "date") { if (facetKeys[key]["dataType"] === "date") {
if (!facetCriteria[key]) facetCriteria[key] = { if (!facetCriteria[key]) facetCriteria[key] = {
"dataType": facetKeys[key]["dataType"],
"inputType": facetKeys[key]["inputType"],
"min": undefined, "min": undefined,
"max": undefined "max": undefined
} }
if (!this.facets[key]) this.facets[key] = { if (!this.facets[key]) this.facets[key] = {
"type": facetKeys[key]["type"], "dataType": facetKeys[key]["dataType"],
"min": undefined, "min": undefined,
"max": undefined "max": undefined
} }
} else { } else {
if (!facetCriteria[key]) facetCriteria[key] = { if (!facetCriteria[key]) facetCriteria[key] = {
"dataType": facetKeys[key]["dataType"],
"inputType": facetKeys[key]["inputType"],
"choices": [] "choices": []
} }
if (!this.facets[key]) this.facets[key] = { if (!this.facets[key]) this.facets[key] = {
"type": facetKeys[key]["type"], "dataType": facetKeys[key]["dataType"],
"choices": [] "choices": []
} }
} }
@ -694,7 +698,7 @@ const ControlsMixin = {
datalayer.eachFeature((feature) => { datalayer.eachFeature((feature) => {
keys.forEach((key) => { keys.forEach((key) => {
let value = feature.properties[key] let value = feature.properties[key]
if (facetKeys[key]["type"] === "date") { if (facetKeys[key]["dataType"] === "date") {
value = L.Util.parseDateField(value) value = L.Util.parseDateField(value)
if (!!value && (!facetCriteria[key]["min"] || facetCriteria[key]["min"] > value)) { if (!!value && (!facetCriteria[key]["min"] || facetCriteria[key]["min"] > value)) {
facetCriteria[key]["min"] = value facetCriteria[key]["min"] = value
@ -725,7 +729,7 @@ const ControlsMixin = {
const fields = keys.map((key) => [ const fields = keys.map((key) => [
`facets.${key}`, `facets.${key}`,
{ {
handler: facetKeys[key]["type"] === "date" ? 'FacetSearchDate' : 'FacetSearchCheckbox', handler: facetCriteria[key]["inputType"] === "datetime-local" ? 'FacetSearchDate' : 'FacetSearchCheckbox',
criteria: facetCriteria[key], criteria: facetCriteria[key],
label: facetKeys[key]["label"] label: facetKeys[key]["label"]
}, },

View file

@ -553,7 +553,7 @@ U.Help = L.Class.extend({
slugKey: L._('The name of the property to use as feature unique identifier.'), slugKey: L._('The name of the property to use as feature unique identifier.'),
filterKey: L._('Comma separated list of properties to use when filtering features'), filterKey: L._('Comma separated list of properties to use when filtering features'),
facetKey: L._( facetKey: L._(
'Comma separated list of properties to use for facet search (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control data type, add it after another | (eg.: mykey|My Key|enum,otherkey|Other Key|date). Allowed values for the data type are date and enum (default).' 'Comma separated list of properties to use for facet search (eg.: mykey,otherkey). To control label, add it after a | (eg.: mykey|My Key,otherkey|Other Key). To control data type, add it after another | (eg.: mykey|My Key|enum,otherkey|Other Key|date). Allowed values for the data type are date and enum (default). To control input field type, add it after another | (eg.: mykey|My Key|enum|checkbox,otherkey|Other Key|date|datetime-local). Allowed values for the input field type are checkbox (default) or radio for data type enum and datetime-local (default) for data type date.'
), ),
interactive: L._( interactive: L._(
'If false, the polygon or line will act as a part of the underlying map.' 'If false, the polygon or line will act as a part of the underlying map.'

View file

@ -496,8 +496,8 @@ U.FeatureMixin = {
const facets = this.map.facets const facets = this.map.facets
for (const [property, criteria] of Object.entries(facets)) { for (const [property, criteria] of Object.entries(facets)) {
let value = this.properties[property] let value = this.properties[property]
const type = criteria["type"] const dataType = criteria["dataType"]
if (type === "date") { if (dataType === "date") {
const min = new Date(criteria["min"]) const min = new Date(criteria["min"])
const max = new Date(criteria["max"]) const max = new Date(criteria["max"])
value = L.Util.parseDateField(value) value = L.Util.parseDateField(value)

View file

@ -748,6 +748,9 @@ L.FormBuilder.FacetSearchCheckbox = L.FormBuilder.Element.extend({
build: function () { build: function () {
this.container = L.DomUtil.create('div', 'umap-facet', this.parentNode) this.container = L.DomUtil.create('div', 'umap-facet', this.parentNode)
this.ul = L.DomUtil.create('ul', '', this.container) this.ul = L.DomUtil.create('ul', '', this.container)
this.dataType = this.options.criteria["dataType"]
this.inputType = this.options.criteria["inputType"]
const choices = this.options.criteria["choices"] const choices = this.options.criteria["choices"]
choices.sort() choices.sort()
choices.forEach((value) => this.buildLi(value)) choices.forEach((value) => this.buildLi(value))
@ -761,18 +764,21 @@ L.FormBuilder.FacetSearchCheckbox = L.FormBuilder.Element.extend({
const property_li = L.DomUtil.create('li', '', this.ul), const property_li = L.DomUtil.create('li', '', this.ul),
input = L.DomUtil.create('input', '', property_li), input = L.DomUtil.create('input', '', property_li),
label = L.DomUtil.create('label', '', property_li) label = L.DomUtil.create('label', '', property_li)
input.type = 'checkbox'
input.id = `checkbox_${this.name}_${value}` input.type = this.inputType
input.name = `${this.inputType}_${this.name}`
input.id = `${this.inputType}_${this.name}_${value}`
input.checked = this.get()['choices'].includes(value) input.checked = this.get()['choices'].includes(value)
input.dataset.value = value input.dataset.value = value
label.htmlFor = `checkbox_${this.name}_${value}` label.htmlFor = `${this.inputType}_${this.name}_${value}`
label.innerHTML = value label.innerHTML = value
L.DomEvent.on(input, 'change', (e) => this.sync()) L.DomEvent.on(input, 'change', (e) => this.sync())
}, },
toJS: function () { toJS: function () {
return { return {
'type': 'checkbox', 'dataType': this.dataType,
'choices': [...this.ul.querySelectorAll('input:checked')].map((i) => i.dataset.value) 'choices': [...this.ul.querySelectorAll('input:checked')].map((i) => i.dataset.value)
} }
}, },
@ -782,6 +788,8 @@ L.FormBuilder.FacetSearchDate = L.FormBuilder.Element.extend({
build: function () { build: function () {
this.container = L.DomUtil.create('div', 'umap-facet', this.parentNode); this.container = L.DomUtil.create('div', 'umap-facet', this.parentNode);
this.table = L.DomUtil.create('table', '', this.container); this.table = L.DomUtil.create('table', '', this.container);
this.dataType = this.options.criteria["dataType"];
this.inputType = this.options.criteria["inputType"];
const min = this.options.criteria['min']; const min = this.options.criteria['min'];
const max = this.options.criteria['max']; const max = this.options.criteria['max'];
@ -791,13 +799,13 @@ L.FormBuilder.FacetSearchDate = L.FormBuilder.Element.extend({
this.minTdLabel = L.DomUtil.create('td', '', this.minTr); this.minTdLabel = L.DomUtil.create('td', '', this.minTr);
this.minLabel = L.DomUtil.create('label', '', this.minTdLabel); this.minLabel = L.DomUtil.create('label', '', this.minTdLabel);
this.minLabel.innerHTML = 'From'; this.minLabel.innerHTML = 'From';
this.minLabel.htmlFor = `date_${this.name}_min`; this.minLabel.htmlFor = `${this.inputType}_${this.name}_min`;
this.minTdInput = L.DomUtil.create('td', '', this.minTr); this.minTdInput = L.DomUtil.create('td', '', this.minTr);
this.minInput = L.DomUtil.create('input', '', this.minTdInput); this.minInput = L.DomUtil.create('input', '', this.minTdInput);
this.minInput.type = 'datetime-local'; this.minInput.type = this.inputType;
this.minInput.step = '0.001'; this.minInput.step = '0.001';
this.minInput.id = `date_${this.name}_min`; this.minInput.id = `${this.inputType}_${this.name}_min`;
this.minInput.valueAsNumber = (min.valueOf() - min.getTimezoneOffset() * 60000);; this.minInput.valueAsNumber = (min.valueOf() - min.getTimezoneOffset() * 60000);;
this.minInput.dataset.value = min; this.minInput.dataset.value = min;
@ -806,13 +814,13 @@ L.FormBuilder.FacetSearchDate = L.FormBuilder.Element.extend({
this.maxTdLabel = L.DomUtil.create('td', '', this.maxTr); this.maxTdLabel = L.DomUtil.create('td', '', this.maxTr);
this.maxLabel = L.DomUtil.create('label', '', this.maxTdLabel); this.maxLabel = L.DomUtil.create('label', '', this.maxTdLabel);
this.maxLabel.innerHTML = 'Until'; this.maxLabel.innerHTML = 'Until';
this.maxLabel.htmlFor = `date_${this.name}_max`; this.maxLabel.htmlFor = `${this.inputType}_${this.name}_max`;
this.maxTdInput = L.DomUtil.create('td', '', this.maxTr); this.maxTdInput = L.DomUtil.create('td', '', this.maxTr);
this.maxInput = L.DomUtil.create('input', '', this.maxTdInput); this.maxInput = L.DomUtil.create('input', '', this.maxTdInput);
this.maxInput.type = 'datetime-local'; this.maxInput.type = this.inputType;
this.maxInput.step = '0.001'; this.maxInput.step = '0.001';
this.maxInput.id = `date_${this.name}_max`; this.maxInput.id = `${this.inputType}_${this.name}_max`;
this.maxInput.valueAsNumber = (max.valueOf() - max.getTimezoneOffset() * 60000);; this.maxInput.valueAsNumber = (max.valueOf() - max.getTimezoneOffset() * 60000);;
this.maxInput.dataset.value = max; this.maxInput.dataset.value = max;
@ -826,7 +834,7 @@ L.FormBuilder.FacetSearchDate = L.FormBuilder.Element.extend({
toJS: function () { toJS: function () {
return { return {
'type': 'date', 'dataType': this.dataType,
'min': this.minInput.value, 'min': this.minInput.value,
'max': this.maxInput.value, 'max': this.maxInput.value,
}; };

View file

@ -1236,7 +1236,7 @@ U.Map = L.Map.extend({
{ {
handler: 'Input', handler: 'Input',
helpEntries: 'facetKey', helpEntries: 'facetKey',
placeholder: L._('Example: key1,key2|Label 2,key3|Label 3|enum'), placeholder: L._('Example: key1,key2|Label 2,key3|Label 3|enum|checkbox'),
label: L._('Facet keys'), label: L._('Facet keys'),
}, },
], ],
@ -1846,12 +1846,25 @@ U.Map = L.Map.extend({
}, },
getFacetKeys: function () { getFacetKeys: function () {
const allowedTypes = {
"enum": ["checkbox", "radio"],
"date": ["datetime-local"],
}
console.log(this.options.facetKey)
return (this.options.facetKey || '').split(',').reduce((acc, curr) => { return (this.options.facetKey || '').split(',').reduce((acc, curr) => {
const els = curr.split('|') const els = curr.split('|')
acc[els[0]] = { acc[els[0]] = {
"label": els[1] || els[0], "label": els[1] || els[0],
"type": els[2] || "enum" "dataType": (
(els[2] in allowedTypes) ? els[2] :
Object.keys(allowedTypes)[0]
)
} }
acc[els[0]]["inputType"] = (
allowedTypes[acc[els[0]]["dataType"]].includes(els[3]) ? els[3] :
allowedTypes[acc[els[0]]["dataType"]][0]
)
console.log(acc)
return acc return acc
}, {}) }, {})
}, },