forked from MapComplete/MapComplete
Reformat all files with prettier
This commit is contained in:
parent
e22d189376
commit
b541d3eab4
382 changed files with 50893 additions and 35566 deletions
|
@ -1,27 +1,27 @@
|
|||
import {Translation} from "../../UI/i18n/Translation";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import FilterConfigJson from "./Json/FilterConfigJson";
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
||||
import ValidatedTextField from "../../UI/Input/ValidatedTextField";
|
||||
import {TagConfigJson} from "./Json/TagConfigJson";
|
||||
import {ImmutableStore, Store, UIEventSource} from "../../Logic/UIEventSource";
|
||||
import {FilterState} from "../FilteredLayer";
|
||||
import {QueryParameters} from "../../Logic/Web/QueryParameters";
|
||||
import {Utils} from "../../Utils";
|
||||
import {RegexTag} from "../../Logic/Tags/RegexTag";
|
||||
import BaseUIElement from "../../UI/BaseUIElement";
|
||||
import {InputElement} from "../../UI/Input/InputElement";
|
||||
import { Translation } from "../../UI/i18n/Translation"
|
||||
import { TagsFilter } from "../../Logic/Tags/TagsFilter"
|
||||
import FilterConfigJson from "./Json/FilterConfigJson"
|
||||
import Translations from "../../UI/i18n/Translations"
|
||||
import { TagUtils } from "../../Logic/Tags/TagUtils"
|
||||
import ValidatedTextField from "../../UI/Input/ValidatedTextField"
|
||||
import { TagConfigJson } from "./Json/TagConfigJson"
|
||||
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { FilterState } from "../FilteredLayer"
|
||||
import { QueryParameters } from "../../Logic/Web/QueryParameters"
|
||||
import { Utils } from "../../Utils"
|
||||
import { RegexTag } from "../../Logic/Tags/RegexTag"
|
||||
import BaseUIElement from "../../UI/BaseUIElement"
|
||||
import { InputElement } from "../../UI/Input/InputElement"
|
||||
|
||||
export default class FilterConfig {
|
||||
public readonly id: string
|
||||
public readonly options: {
|
||||
question: Translation;
|
||||
osmTags: TagsFilter | undefined;
|
||||
question: Translation
|
||||
osmTags: TagsFilter | undefined
|
||||
originalTagsSpec: TagConfigJson
|
||||
fields: { name: string, type: string }[]
|
||||
}[];
|
||||
public readonly defaultSelection? : number
|
||||
fields: { name: string; type: string }[]
|
||||
}[]
|
||||
public readonly defaultSelection?: number
|
||||
|
||||
constructor(json: FilterConfigJson, context: string) {
|
||||
if (json.options === undefined) {
|
||||
|
@ -37,99 +37,114 @@ export default class FilterConfig {
|
|||
if (json.options.map === undefined) {
|
||||
throw `A filter was given where the options aren't a list at ${context}`
|
||||
}
|
||||
this.id = json.id;
|
||||
let defaultSelection : number = undefined
|
||||
this.id = json.id
|
||||
let defaultSelection: number = undefined
|
||||
this.options = json.options.map((option, i) => {
|
||||
const ctx = `${context}.options.${i}`;
|
||||
const question = Translations.T(
|
||||
option.question,
|
||||
`${ctx}.question`
|
||||
);
|
||||
let osmTags: undefined | TagsFilter = undefined;
|
||||
const ctx = `${context}.options.${i}`
|
||||
const question = Translations.T(option.question, `${ctx}.question`)
|
||||
let osmTags: undefined | TagsFilter = undefined
|
||||
if ((option.fields?.length ?? 0) == 0 && option.osmTags !== undefined) {
|
||||
osmTags = TagUtils.Tag(
|
||||
option.osmTags,
|
||||
`${ctx}.osmTags`
|
||||
);
|
||||
osmTags = TagUtils.Tag(option.osmTags, `${ctx}.osmTags`)
|
||||
FilterConfig.validateSearch(osmTags, ctx)
|
||||
}
|
||||
if (question === undefined) {
|
||||
throw `Invalid filter: no question given at ${ctx}`
|
||||
}
|
||||
|
||||
const fields: { name: string, type: string }[] = ((option.fields) ?? []).map((f, i) => {
|
||||
const fields: { name: string; type: string }[] = (option.fields ?? []).map((f, i) => {
|
||||
const type = f.type ?? "string"
|
||||
if (!ValidatedTextField.ForType(type) === undefined) {
|
||||
throw `Invalid filter: ${type} is not a valid validated textfield type (at ${ctx}.fields[${i}])\n\tTry one of ${Array.from(ValidatedTextField.AvailableTypes()).join(",")}`
|
||||
throw `Invalid filter: ${type} is not a valid validated textfield type (at ${ctx}.fields[${i}])\n\tTry one of ${Array.from(
|
||||
ValidatedTextField.AvailableTypes()
|
||||
).join(",")}`
|
||||
}
|
||||
if (f.name === undefined || f.name === "" || f.name.match(/[a-z0-9_-]+/) == null) {
|
||||
throw `Invalid filter: a variable name should match [a-z0-9_-]+ at ${ctx}.fields[${i}]`
|
||||
}
|
||||
return {
|
||||
name: f.name,
|
||||
type
|
||||
type,
|
||||
}
|
||||
})
|
||||
|
||||
for (const field of fields) {
|
||||
question.OnEveryLanguage((txt, language) => {
|
||||
if(txt.indexOf("{"+field.name+"}")<0){
|
||||
throw "Error in filter with fields at "+context+".question."+language+": The question text should contain every field, but it doesn't contain `{"+field+"}`: "+txt
|
||||
if (txt.indexOf("{" + field.name + "}") < 0) {
|
||||
throw (
|
||||
"Error in filter with fields at " +
|
||||
context +
|
||||
".question." +
|
||||
language +
|
||||
": The question text should contain every field, but it doesn't contain `{" +
|
||||
field +
|
||||
"}`: " +
|
||||
txt
|
||||
)
|
||||
}
|
||||
return txt
|
||||
})
|
||||
}
|
||||
|
||||
if(option.default){
|
||||
if(defaultSelection === undefined){
|
||||
defaultSelection = i;
|
||||
}else{
|
||||
if (option.default) {
|
||||
if (defaultSelection === undefined) {
|
||||
defaultSelection = i
|
||||
} else {
|
||||
throw `Invalid filter: multiple filters are set as default, namely ${i} and ${defaultSelection} at ${context}`
|
||||
}
|
||||
}
|
||||
|
||||
if(option.osmTags !== undefined){
|
||||
|
||||
if (option.osmTags !== undefined) {
|
||||
FilterConfig.validateSearch(TagUtils.Tag(option.osmTags), ctx)
|
||||
}
|
||||
|
||||
return {question: question, osmTags: osmTags, fields, originalTagsSpec: option.osmTags};
|
||||
});
|
||||
|
||||
this.defaultSelection = defaultSelection
|
||||
return {
|
||||
question: question,
|
||||
osmTags: osmTags,
|
||||
fields,
|
||||
originalTagsSpec: option.osmTags,
|
||||
}
|
||||
})
|
||||
|
||||
if (this.options.some(o => o.fields.length > 0) && this.options.length > 1) {
|
||||
this.defaultSelection = defaultSelection
|
||||
|
||||
if (this.options.some((o) => o.fields.length > 0) && this.options.length > 1) {
|
||||
throw `Invalid filter at ${context}: a filter with textfields should only offer a single option.`
|
||||
}
|
||||
|
||||
if (this.options.length > 1 && this.options[0].osmTags !== undefined) {
|
||||
throw "Error in " + context + "." + this.id + ": the first option of a multi-filter should always be the 'reset' option and not have any filters"
|
||||
throw (
|
||||
"Error in " +
|
||||
context +
|
||||
"." +
|
||||
this.id +
|
||||
": the first option of a multi-filter should always be the 'reset' option and not have any filters"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static validateSearch(osmTags: TagsFilter, ctx: string){
|
||||
osmTags.visit(t => {
|
||||
private static validateSearch(osmTags: TagsFilter, ctx: string) {
|
||||
osmTags.visit((t) => {
|
||||
if (!(t instanceof RegexTag)) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
if(typeof t.value == "string"){
|
||||
return;
|
||||
}
|
||||
|
||||
if(t.value.source == '^..*$' || t.value.source == '^[\\s\\S][\\s\\S]*$' /*Compiled regex with 'm'*/){
|
||||
if (typeof t.value == "string") {
|
||||
return
|
||||
}
|
||||
|
||||
if(!t.value.ignoreCase) {
|
||||
throw `At ${ctx}: The filter for key '${t.key}' uses a regex '${t.value}', but you should use a case invariant regex with ~i~ instead, as search should be case insensitive`
|
||||
if (
|
||||
t.value.source == "^..*$" ||
|
||||
t.value.source == "^[\\s\\S][\\s\\S]*$" /*Compiled regex with 'm'*/
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!t.value.ignoreCase) {
|
||||
throw `At ${ctx}: The filter for key '${t.key}' uses a regex '${t.value}', but you should use a case invariant regex with ~i~ instead, as search should be case insensitive`
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public initState(): UIEventSource<FilterState> {
|
||||
|
||||
public initState(): UIEventSource<FilterState> {
|
||||
function reset(state: FilterState): string {
|
||||
if (state === undefined) {
|
||||
return ""
|
||||
|
@ -138,47 +153,54 @@ export default class FilterConfig {
|
|||
}
|
||||
|
||||
let defaultValue = ""
|
||||
if(this.options.length > 1){
|
||||
defaultValue = ""+(this.defaultSelection ?? 0)
|
||||
}else{
|
||||
if (this.options.length > 1) {
|
||||
defaultValue = "" + (this.defaultSelection ?? 0)
|
||||
} else {
|
||||
// Only a single option
|
||||
if(this.defaultSelection === 0){
|
||||
if (this.defaultSelection === 0) {
|
||||
defaultValue = "true"
|
||||
}
|
||||
}
|
||||
const qp = QueryParameters.GetQueryParameter("filter-" + this.id, defaultValue, "State of filter " + this.id)
|
||||
const qp = QueryParameters.GetQueryParameter(
|
||||
"filter-" + this.id,
|
||||
defaultValue,
|
||||
"State of filter " + this.id
|
||||
)
|
||||
|
||||
if (this.options.length > 1) {
|
||||
// This is a multi-option filter; state should be a number which selects the correct entry
|
||||
const possibleStates: FilterState [] = this.options.map((opt, i) => ({
|
||||
const possibleStates: FilterState[] = this.options.map((opt, i) => ({
|
||||
currentFilter: opt.osmTags,
|
||||
state: i
|
||||
state: i,
|
||||
}))
|
||||
|
||||
// We map the query parameter for this case
|
||||
return qp.sync(str => {
|
||||
const parsed = Number(str)
|
||||
if (isNaN(parsed)) {
|
||||
// Nope, not a correct number!
|
||||
return undefined
|
||||
}
|
||||
return possibleStates[parsed]
|
||||
}, [], reset)
|
||||
return qp.sync(
|
||||
(str) => {
|
||||
const parsed = Number(str)
|
||||
if (isNaN(parsed)) {
|
||||
// Nope, not a correct number!
|
||||
return undefined
|
||||
}
|
||||
return possibleStates[parsed]
|
||||
},
|
||||
[],
|
||||
reset
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
const option = this.options[0]
|
||||
|
||||
if (option.fields.length > 0) {
|
||||
return qp.sync(str => {
|
||||
// There are variables in play!
|
||||
// str should encode a json-hash
|
||||
try {
|
||||
const props = JSON.parse(str)
|
||||
return qp.sync(
|
||||
(str) => {
|
||||
// There are variables in play!
|
||||
// str should encode a json-hash
|
||||
try {
|
||||
const props = JSON.parse(str)
|
||||
|
||||
const origTags = option.originalTagsSpec
|
||||
const rewrittenTags = Utils.WalkJson(origTags,
|
||||
v => {
|
||||
const origTags = option.originalTagsSpec
|
||||
const rewrittenTags = Utils.WalkJson(origTags, (v) => {
|
||||
if (typeof v !== "string") {
|
||||
return v
|
||||
}
|
||||
|
@ -186,34 +208,36 @@ export default class FilterConfig {
|
|||
v = (<string>v).replace("{" + key + "}", props[key])
|
||||
}
|
||||
return v
|
||||
})
|
||||
const parsed = TagUtils.Tag(rewrittenTags)
|
||||
return <FilterState>{
|
||||
currentFilter: parsed,
|
||||
state: str,
|
||||
}
|
||||
)
|
||||
const parsed = TagUtils.Tag(rewrittenTags)
|
||||
return <FilterState>{
|
||||
currentFilter: parsed,
|
||||
state: str
|
||||
} catch (e) {
|
||||
return undefined
|
||||
}
|
||||
} catch (e) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
}, [], reset)
|
||||
},
|
||||
[],
|
||||
reset
|
||||
)
|
||||
}
|
||||
|
||||
// The last case is pretty boring: it is checked or it isn't
|
||||
const filterState: FilterState = {
|
||||
currentFilter: option.osmTags,
|
||||
state: "true"
|
||||
state: "true",
|
||||
}
|
||||
return qp.sync(
|
||||
str => {
|
||||
(str) => {
|
||||
// Only a single option exists here
|
||||
if (str === "true") {
|
||||
return filterState
|
||||
}
|
||||
return undefined
|
||||
}, [],
|
||||
},
|
||||
[],
|
||||
reset
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue