forked from MapComplete/MapComplete
Finetuning of the filter functionality
This commit is contained in:
parent
31d2bd83b9
commit
79569f5119
17 changed files with 219 additions and 309 deletions
|
@ -23,7 +23,7 @@ export class VariableUiElement extends BaseUIElement {
|
|||
el.innerHTML = contents;
|
||||
} else if (contents instanceof Array) {
|
||||
for (const content of contents) {
|
||||
const c = content.ConstructElement();
|
||||
const c = content?.ConstructElement();
|
||||
if (c !== undefined && c !== null) {
|
||||
el.appendChild(c);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@ import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
|||
import {And} from "../../Logic/Tags/And";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import State from "../../State";
|
||||
import {control} from "leaflet";
|
||||
|
||||
|
||||
/**
|
||||
* Shows the filter
|
||||
|
@ -22,12 +25,16 @@ export default class FilterView extends VariableUiElement {
|
|||
constructor(filteredLayer) {
|
||||
super(
|
||||
filteredLayer.map((filteredLayers) =>
|
||||
filteredLayers.map(FilterView.createOneFilteredLayerElement)
|
||||
filteredLayers.map(l => FilterView.createOneFilteredLayerElement(l))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
static createOneFilteredLayerElement(filteredLayer) {
|
||||
private static createOneFilteredLayerElement(filteredLayer) {
|
||||
if(filteredLayer.layerDef.name === undefined){
|
||||
// Name is not defined: we hide this one
|
||||
return undefined;
|
||||
}
|
||||
const iconStyle = "width:1.5rem;height:1.5rem;margin-left:1.25rem";
|
||||
|
||||
const icon = new Combine([Svg.checkbox_filled]).SetStyle(iconStyle);
|
||||
|
@ -52,9 +59,19 @@ export default class FilterView extends VariableUiElement {
|
|||
.Clone()
|
||||
.SetStyle("font-size:large;padding-left:1.25rem");
|
||||
|
||||
const zoomStatus =
|
||||
new Toggle(
|
||||
undefined,
|
||||
Translations.t.general.layerSelection.zoomInToSeeThisLayer.Clone()
|
||||
.SetClass("alert")
|
||||
.SetStyle("display: block ruby;width:min-content;"),
|
||||
State.state.locationControl.map(location =>location.zoom > filteredLayer.layerDef.minzoom )
|
||||
)
|
||||
|
||||
|
||||
const style =
|
||||
"display:flex;align-items:center;color:#007759;padding:0.5rem 0;";
|
||||
const layerChecked = new Combine([icon, styledNameChecked])
|
||||
const layerChecked = new Combine([icon, styledNameChecked, zoomStatus])
|
||||
.SetStyle(style)
|
||||
.onClick(() => filteredLayer.isDisplayed.setData(false));
|
||||
|
||||
|
@ -62,25 +79,27 @@ export default class FilterView extends VariableUiElement {
|
|||
.SetStyle(style)
|
||||
.onClick(() => filteredLayer.isDisplayed.setData(true));
|
||||
|
||||
|
||||
|
||||
const filterPanel: BaseUIElement = FilterView.createFilterPanel(filteredLayer)
|
||||
|
||||
|
||||
|
||||
|
||||
return new Toggle(
|
||||
new Combine([layerChecked, filterPanel]),
|
||||
layerNotChecked,
|
||||
filteredLayer.isDisplayed
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static createFilterPanel(flayer: {
|
||||
layerDef: LayerConfig,
|
||||
appliedFilters: UIEventSource<TagsFilter>
|
||||
}): BaseUIElement{
|
||||
}): BaseUIElement {
|
||||
const layer = flayer.layerDef
|
||||
if(layer.filters.length === 0){
|
||||
if (layer.filters.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
let listFilterElements: [BaseUIElement, UIEventSource<TagsFilter>][] = layer.filters.map(
|
||||
FilterView.createFilter
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import State from "../../State";
|
||||
import BackgroundSelector from "./BackgroundSelector";
|
||||
import LayerSelection from "./LayerSelection";
|
||||
import Combine from "../Base/Combine";
|
||||
import ScrollableFullScreen from "../Base/ScrollableFullScreen";
|
||||
import Translations from "../i18n/Translations";
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import State from "../../State";
|
||||
import Toggle from "../Input/Toggle";
|
||||
import Combine from "../Base/Combine";
|
||||
import Translations from "../i18n/Translations";
|
||||
import LayerConfig from "../../Customizations/JSON/LayerConfig";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import {Translation} from "../i18n/Translation";
|
||||
|
||||
/**
|
||||
* Shows the panel with all layers and a toggle for each of them
|
||||
*/
|
||||
export default class LayerSelection extends Combine {
|
||||
|
||||
|
||||
constructor(activeLayers: UIEventSource<{
|
||||
readonly isDisplayed: UIEventSource<boolean>,
|
||||
readonly layerDef: LayerConfig;
|
||||
}[]>) {
|
||||
|
||||
if (activeLayers === undefined) {
|
||||
throw "ActiveLayers should be defined..."
|
||||
}
|
||||
|
||||
|
||||
const checkboxes: BaseUIElement[] = [];
|
||||
|
||||
for (const layer of activeLayers.data) {
|
||||
const leafletStyle = layer.layerDef.GenerateLeafletStyle(
|
||||
new UIEventSource<any>({id: "node/-1"}),
|
||||
false)
|
||||
const leafletStyleNa = layer.layerDef.GenerateLeafletStyle(
|
||||
new UIEventSource<any>({id: "node/-1"}),
|
||||
false)
|
||||
const icon = new Combine([leafletStyle.icon.html]).SetClass("single-layer-selection-toggle")
|
||||
let iconUnselected: BaseUIElement = new Combine([leafletStyleNa.icon.html])
|
||||
.SetClass("single-layer-selection-toggle")
|
||||
.SetStyle("opacity:0.2;");
|
||||
|
||||
if (layer.layerDef.name === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const name: Translation = Translations.WT(layer.layerDef.name)?.Clone()
|
||||
name.SetStyle("font-size:large;margin-left: 0.5em;");
|
||||
|
||||
const zoomStatus = new VariableUiElement(State.state.locationControl.map(location => {
|
||||
if (location.zoom < layer.layerDef.minzoom) {
|
||||
return Translations.t.general.layerSelection.zoomInToSeeThisLayer.Clone()
|
||||
.SetClass("alert")
|
||||
.SetStyle("display: block ruby;width:min-content;")
|
||||
}
|
||||
return ""
|
||||
}))
|
||||
const zoomStatusNonActive = new VariableUiElement(State.state.locationControl.map(location => {
|
||||
if (location.zoom < layer.layerDef.minzoom) {
|
||||
return Translations.t.general.layerSelection.zoomInToSeeThisLayer.Clone()
|
||||
.SetClass("alert")
|
||||
.SetStyle("display: block ruby;width:min-content;")
|
||||
}
|
||||
return ""
|
||||
}))
|
||||
|
||||
const style = "display:flex;align-items:center;"
|
||||
const styleWhole = "display:flex; flex-wrap: wrap"
|
||||
checkboxes.push(new Toggle(
|
||||
new Combine([new Combine([icon, name.Clone()]).SetStyle(style), zoomStatus])
|
||||
.SetStyle(styleWhole),
|
||||
new Combine([new Combine([iconUnselected, "<del>", name.Clone(), "</del>"]).SetStyle(style), zoomStatusNonActive])
|
||||
.SetStyle(styleWhole),
|
||||
layer.isDisplayed).ToggleOnClick()
|
||||
.SetStyle("margin:0.3em;")
|
||||
);
|
||||
}
|
||||
|
||||
super(checkboxes)
|
||||
this.SetStyle("display:flex;flex-direction:column;")
|
||||
|
||||
}
|
||||
}
|
|
@ -118,7 +118,7 @@ export class RadioButton<T> extends InputElement<T> {
|
|||
const label = document.createElement("label");
|
||||
label.appendChild(labelHtml);
|
||||
label.htmlFor = input.id;
|
||||
label.classList.add("block", "w-full", "cursor-pointer", "bg-red");
|
||||
label.classList.add("flex", "w-full", "cursor-pointer", "bg-red");
|
||||
|
||||
if (!this._dontStyle) {
|
||||
labelHtml.classList.add("p-2")
|
||||
|
|
|
@ -19,7 +19,7 @@ export default class Translations {
|
|||
|
||||
|
||||
static T(t: string | any, context = undefined): Translation {
|
||||
if(t === undefined){
|
||||
if(t === undefined || t === null){
|
||||
return undefined;
|
||||
}
|
||||
if(typeof t === "string"){
|
||||
|
@ -38,7 +38,7 @@ export default class Translations {
|
|||
|
||||
private static wtcache = {}
|
||||
public static WT(s: string | Translation): Translation {
|
||||
if(s === undefined){
|
||||
if(s === undefined || s === null){
|
||||
return undefined;
|
||||
}
|
||||
if (typeof (s) === "string") {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue