forked from MapComplete/MapComplete
refactoring(maplibre): WIP
This commit is contained in:
parent
231d67361e
commit
4d48b1cf2b
89 changed files with 1166 additions and 3973 deletions
|
@ -23,8 +23,6 @@ import predifined_filters from "../../../assets/layers/filters/filters.json"
|
|||
import { TagConfigJson } from "../Json/TagConfigJson"
|
||||
import PointRenderingConfigJson from "../Json/PointRenderingConfigJson"
|
||||
import LineRenderingConfigJson from "../Json/LineRenderingConfigJson"
|
||||
import { type } from "os"
|
||||
import exp from "constants"
|
||||
|
||||
class ExpandFilter extends DesugaringStep<LayerConfigJson> {
|
||||
private static readonly predefinedFilters = ExpandFilter.load_filters()
|
||||
|
|
|
@ -175,7 +175,7 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
|
|||
}
|
||||
|
||||
class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
|
||||
private _state: DesugaringContext
|
||||
private readonly _state: DesugaringContext
|
||||
|
||||
constructor(state: DesugaringContext) {
|
||||
super(
|
||||
|
@ -430,7 +430,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
constructor(state: DesugaringContext) {
|
||||
super(
|
||||
`If a layer has a dependency on another layer, these layers are added automatically on the theme. (For example: defibrillator depends on 'walls_and_buildings' to snap onto. This layer is added automatically)
|
||||
|
||||
|
||||
Note that these layers are added _at the start_ of the layer list, meaning that they will see _every_ feature.
|
||||
Furthermore, \`passAllFeatures\` will be set, so that they won't steal away features from further layers.
|
||||
Some layers (e.g. \`all_buildings_and_walls\' or \'streets_with_a_name\') are invisible, so by default, \'force_load\' is set too.
|
||||
|
|
|
@ -15,6 +15,7 @@ import Svg from "../../../Svg"
|
|||
import FilterConfigJson from "../Json/FilterConfigJson"
|
||||
import DeleteConfig from "../DeleteConfig"
|
||||
import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
|
||||
import ValidatedTextField from "../../../UI/Input/ValidatedTextField"
|
||||
|
||||
class ValidateLanguageCompleteness extends DesugaringStep<any> {
|
||||
private readonly _languages: string[]
|
||||
|
@ -594,6 +595,7 @@ export class DetectMappingsWithImages extends DesugaringStep<TagRenderingConfigJ
|
|||
|
||||
class MiscTagRenderingChecks extends DesugaringStep<TagRenderingConfigJson> {
|
||||
private _options: { noQuestionHintCheck: boolean }
|
||||
|
||||
constructor(options: { noQuestionHintCheck: boolean }) {
|
||||
super("Miscellaneous checks on the tagrendering", ["special"], "MiscTagRenderingChecks")
|
||||
this._options = options
|
||||
|
@ -637,6 +639,19 @@ class MiscTagRenderingChecks extends DesugaringStep<TagRenderingConfigJson> {
|
|||
}
|
||||
}
|
||||
}
|
||||
const freeformType = json["freeform"]?.["type"]
|
||||
if (freeformType) {
|
||||
if (ValidatedTextField.AvailableTypes().indexOf(freeformType) < 0) {
|
||||
throw (
|
||||
"At " +
|
||||
context +
|
||||
".freeform.type is an unknown type: " +
|
||||
freeformType +
|
||||
"; try one of " +
|
||||
ValidatedTextField.AvailableTypes().join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
return {
|
||||
result: json,
|
||||
errors,
|
||||
|
@ -905,6 +920,38 @@ export class ValidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
}
|
||||
}
|
||||
|
||||
export class ValidateFilter extends DesugaringStep<FilterConfigJson> {
|
||||
constructor() {
|
||||
super("Detect common errors in the filters", [], "ValidateFilter")
|
||||
}
|
||||
|
||||
convert(
|
||||
filter: FilterConfigJson,
|
||||
context: string
|
||||
): {
|
||||
result: FilterConfigJson
|
||||
errors?: string[]
|
||||
warnings?: string[]
|
||||
information?: string[]
|
||||
} {
|
||||
const errors = []
|
||||
for (const option of filter.options) {
|
||||
for (let i = 0; i < option.fields.length; i++) {
|
||||
const field = option.fields[i]
|
||||
const type = field.type ?? "string"
|
||||
if (!ValidatedTextField.ForType(type) !== undefined) {
|
||||
continue
|
||||
}
|
||||
const err = `Invalid filter: ${type} is not a valid validated textfield type (at ${context}.fields[${i}])\n\tTry one of ${Array.from(
|
||||
ValidatedTextField.AvailableTypes()
|
||||
).join(",")}`
|
||||
errors.push(err)
|
||||
}
|
||||
}
|
||||
return { result: filter, errors }
|
||||
}
|
||||
}
|
||||
|
||||
export class DetectDuplicateFilters extends DesugaringStep<{
|
||||
layers: LayerConfigJson[]
|
||||
themes: LayoutConfigJson[]
|
||||
|
|
|
@ -3,7 +3,6 @@ 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 { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { FilterState } from "../FilteredLayer"
|
||||
|
@ -54,11 +53,7 @@ export default class FilterConfig {
|
|||
|
||||
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(",")}`
|
||||
}
|
||||
// Type is validated against 'ValidatedTextField' in Validation.ts, in ValidateFilterConfig
|
||||
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}]`
|
||||
}
|
||||
|
|
|
@ -40,8 +40,9 @@ export interface LayerConfigJson {
|
|||
*
|
||||
* Every source _must_ define which tags _must_ be present in order to be picked up.
|
||||
*
|
||||
* Note: a source must always be defined. 'special' is only allowed if this is a builtin-layer
|
||||
*/
|
||||
source: {
|
||||
source: "special" | "special:library" | ({
|
||||
/**
|
||||
* Every source must set which tags have to be present in order to load the given layer.
|
||||
*/
|
||||
|
@ -102,7 +103,7 @@ export interface LayerConfigJson {
|
|||
* Setting this key will rename this field into 'id'
|
||||
*/
|
||||
idKey?: string
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,8 +12,11 @@ import { TagConfigJson } from "./TagConfigJson"
|
|||
export default interface PointRenderingConfigJson {
|
||||
/**
|
||||
* All the locations that this point should be rendered at.
|
||||
* Using `location: ["point", "centroid"] will always render centerpoint.
|
||||
* 'projected_centerpoint' will show an item on the line itself, near the middle of the line. (LineStrings only)
|
||||
* Possible values are:
|
||||
* - `point`: only renders points at their location
|
||||
* - `centroid`: show a symbol at the centerpoint of a (multi)Linestring and (multi)polygon. Points will _not_ be rendered with this
|
||||
* - `projected_centerpoint`: Only on (multi)linestrings: calculate the centerpoint and snap it to the way
|
||||
* - `start` and `end`: only on linestrings: add a point to the first/last coordinate of the LineString
|
||||
*/
|
||||
location: ("point" | "centroid" | "start" | "end" | "projected_centerpoint" | string)[]
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ import { Overpass } from "../../Logic/Osm/Overpass"
|
|||
import Constants from "../Constants"
|
||||
import { FixedUiElement } from "../../UI/Base/FixedUiElement"
|
||||
import Svg from "../../Svg"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { ImmutableStore } from "../../Logic/UIEventSource"
|
||||
import { OsmTags } from "../OsmFeature"
|
||||
|
||||
export default class LayerConfig extends WithContextLoader {
|
||||
|
@ -37,7 +37,10 @@ export default class LayerConfig extends WithContextLoader {
|
|||
public readonly id: string
|
||||
public readonly name: Translation
|
||||
public readonly description: Translation
|
||||
public readonly source: SourceConfig
|
||||
/**
|
||||
* Only 'null' for special, privileged layers
|
||||
*/
|
||||
public readonly source: SourceConfig | null
|
||||
public readonly calculatedTags: [string, string, boolean][]
|
||||
public readonly doNotDownload: boolean
|
||||
public readonly passAllFeatures: boolean
|
||||
|
@ -83,7 +86,9 @@ export default class LayerConfig extends WithContextLoader {
|
|||
throw "Layer " + this.id + " does not define a source section (" + context + ")"
|
||||
}
|
||||
|
||||
if (json.source.osmTags === undefined) {
|
||||
if(json.source === "special" || json.source === "special:library"){
|
||||
this.source = null
|
||||
}else if (json.source.osmTags === undefined) {
|
||||
throw (
|
||||
"Layer " +
|
||||
this.id +
|
||||
|
@ -584,11 +589,9 @@ export default class LayerConfig extends WithContextLoader {
|
|||
.filter((mr) => mr.location.has("point"))
|
||||
.map(
|
||||
(mr) =>
|
||||
mr.GenerateLeafletStyle(
|
||||
new UIEventSource<OsmTags>({ id: "node/-1" }),
|
||||
false,
|
||||
{ includeBadges: false }
|
||||
).html
|
||||
mr.RenderIcon(new ImmutableStore<OsmTags>({ id: "node/-1" }), false, {
|
||||
includeBadges: false,
|
||||
}).html
|
||||
)
|
||||
.find((i) => i !== undefined)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import { ExtractImages } from "./Conversion/FixImages"
|
|||
import ExtraLinkConfig from "./ExtraLinkConfig"
|
||||
import { Utils } from "../../Utils"
|
||||
import LanguageUtils from "../../Utils/LanguageUtils"
|
||||
|
||||
/**
|
||||
* Minimal information about a theme
|
||||
**/
|
||||
|
|
|
@ -175,7 +175,7 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
)
|
||||
}
|
||||
|
||||
public GenerateLeafletStyle(
|
||||
public RenderIcon(
|
||||
tags: Store<OsmTags>,
|
||||
clickable: boolean,
|
||||
options?: {
|
||||
|
@ -210,7 +210,7 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
|
||||
// in MapLibre, the offset is relative to the _center_ of the object, with left = [-x, 0] and up = [0,-y]
|
||||
let anchorW = 0
|
||||
let anchorH = iconH / 2
|
||||
let anchorH = 0
|
||||
if (mode === "left") {
|
||||
anchorW = -iconW / 2
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import { TagsFilter } from "../../Logic/Tags/TagsFilter"
|
|||
import Translations from "../../UI/i18n/Translations"
|
||||
import { TagUtils, UploadableTag } from "../../Logic/Tags/TagUtils"
|
||||
import { And } from "../../Logic/Tags/And"
|
||||
import ValidatedTextField from "../../UI/Input/ValidatedTextField"
|
||||
import { Utils } from "../../Utils"
|
||||
import { Tag } from "../../Logic/Tags/Tag"
|
||||
import BaseUIElement from "../../UI/BaseUIElement"
|
||||
|
@ -132,17 +131,6 @@ export default class TagRenderingConfig {
|
|||
}
|
||||
const type = json.freeform.type ?? "string"
|
||||
|
||||
if (ValidatedTextField.AvailableTypes().indexOf(type) < 0) {
|
||||
throw (
|
||||
"At " +
|
||||
context +
|
||||
".freeform.type is an unknown type: " +
|
||||
type +
|
||||
"; try one of " +
|
||||
ValidatedTextField.AvailableTypes().join(", ")
|
||||
)
|
||||
}
|
||||
|
||||
let placeholder: Translation = Translations.T(json.freeform.placeholder)
|
||||
if (placeholder === undefined) {
|
||||
const typeDescription = <Translation>Translations.t.validation[type]?.description
|
||||
|
@ -182,13 +170,7 @@ export default class TagRenderingConfig {
|
|||
}
|
||||
}
|
||||
|
||||
if (
|
||||
this.freeform.type !== undefined &&
|
||||
ValidatedTextField.AvailableTypes().indexOf(this.freeform.type) < 0
|
||||
) {
|
||||
const knownKeys = ValidatedTextField.AvailableTypes().join(", ")
|
||||
throw `Freeform.key ${this.freeform.key} is an invalid type. Known keys are ${knownKeys}`
|
||||
}
|
||||
// freeform.type is validated in Validation.ts so that we don't need ValidatedTextFields here
|
||||
if (this.freeform.addExtraTags) {
|
||||
const usedKeys = new And(this.freeform.addExtraTags).usedKeys()
|
||||
if (usedKeys.indexOf(this.freeform.key) >= 0) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue