forked from MapComplete/MapComplete
Merge develop
This commit is contained in:
commit
c672fe7668
138 changed files with 14304 additions and 1299 deletions
|
@ -116,28 +116,42 @@ export default class Constants {
|
|||
* These are the values that are allowed to use as 'backdrop' icon for a map pin
|
||||
*/
|
||||
private static readonly _defaultPinIcons = [
|
||||
"pin",
|
||||
"square",
|
||||
"circle",
|
||||
"none",
|
||||
"pin",
|
||||
"person",
|
||||
"plus",
|
||||
"ring",
|
||||
"star",
|
||||
"teardrop",
|
||||
"triangle",
|
||||
"checkmark",
|
||||
"clock",
|
||||
"close",
|
||||
"crosshair",
|
||||
"help",
|
||||
"home",
|
||||
"invalid",
|
||||
"location",
|
||||
"location_empty",
|
||||
"location_locked",
|
||||
"note",
|
||||
"resolved",
|
||||
"ring",
|
||||
"scissors",
|
||||
"teardrop",
|
||||
"teardrop_with_hole_green",
|
||||
"triangle",
|
||||
"brick_wall_square",
|
||||
"brick_wall_round",
|
||||
"gps_arrow",
|
||||
"checkmark",
|
||||
"help",
|
||||
"clock",
|
||||
"invalid",
|
||||
"close",
|
||||
"invalid",
|
||||
"heart",
|
||||
"heart_outline",
|
||||
"link",
|
||||
"confirm",
|
||||
"direction",
|
||||
"not_found",
|
||||
"mastodon",
|
||||
"party",
|
||||
"addSmall",
|
||||
] as const
|
||||
public static readonly defaultPinIcons: string[] = <any>Constants._defaultPinIcons
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import { UIEventSource } from "../Logic/UIEventSource"
|
|||
import UserRelatedState from "../Logic/State/UserRelatedState"
|
||||
import { Utils } from "../Utils"
|
||||
import { LocalStorageSource } from "../Logic/Web/LocalStorageSource"
|
||||
import Zoomcontrol from "../UI/Zoomcontrol"
|
||||
|
||||
export type ThemeViewTabStates = (typeof MenuState._themeviewTabs)[number]
|
||||
export type MenuViewTabStates = (typeof MenuState._menuviewTabs)[number]
|
||||
|
@ -114,7 +115,36 @@ export class MenuState {
|
|||
name: "background",
|
||||
showOverOthers: true,
|
||||
},
|
||||
{
|
||||
toggle: this.communityIndexPanelIsOpened,
|
||||
name: "community",
|
||||
showOverOthers: true,
|
||||
},
|
||||
{
|
||||
toggle: this.privacyPanelIsOpened,
|
||||
name: "privacy",
|
||||
showOverOthers: true,
|
||||
},
|
||||
{
|
||||
toggle: this.filtersPanelIsOpened,
|
||||
name: "filters",
|
||||
showOverOthers: true,
|
||||
},
|
||||
]
|
||||
for (const toggle of this.allToggles) {
|
||||
toggle.toggle.addCallback((isOpen) => {
|
||||
if (!isOpen) {
|
||||
this.resetZoomIfAllClosed()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private resetZoomIfAllClosed() {
|
||||
if (this.isSomethingOpen()) {
|
||||
return
|
||||
}
|
||||
Zoomcontrol.resetzoom()
|
||||
}
|
||||
|
||||
public openFilterView(highlightLayer?: LayerConfig | string) {
|
||||
|
@ -146,27 +176,23 @@ export class MenuState {
|
|||
this.highlightedUserSetting.setData(highlightTagRendering)
|
||||
}
|
||||
|
||||
public isSomethingOpen(): boolean {
|
||||
return this.allToggles.some((t) => t.toggle.data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all floatOvers.
|
||||
* Returns 'true' if at least one menu was opened
|
||||
*/
|
||||
public closeAll(): boolean {
|
||||
const toggles = [
|
||||
this.communityIndexPanelIsOpened,
|
||||
this.privacyPanelIsOpened,
|
||||
this.backgroundLayerSelectionIsOpened,
|
||||
this.filtersPanelIsOpened,
|
||||
this.menuIsOpened,
|
||||
this.themeIsOpened,
|
||||
]
|
||||
let somethingIsOpen = false
|
||||
for (const t of toggles) {
|
||||
somethingIsOpen = t.data
|
||||
t.setData(false)
|
||||
if (somethingIsOpen) {
|
||||
let somethingWasOpen = false
|
||||
for (const t of this.allToggles) {
|
||||
somethingWasOpen = t.toggle.data
|
||||
t.toggle.setData(false)
|
||||
if (somethingWasOpen) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return somethingIsOpen
|
||||
return somethingWasOpen
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,4 @@
|
|||
import {
|
||||
Concat,
|
||||
Conversion,
|
||||
DesugaringContext,
|
||||
DesugaringStep,
|
||||
Each,
|
||||
Fuse,
|
||||
On,
|
||||
Pass,
|
||||
SetDefault,
|
||||
} from "./Conversion"
|
||||
import { Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault } from "./Conversion"
|
||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
|
||||
import { PrepareLayer } from "./PrepareLayer"
|
||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||
|
@ -27,9 +17,9 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
|
|||
|
||||
constructor(state: DesugaringContext) {
|
||||
super(
|
||||
"Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form",
|
||||
"Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form. Note that 'tagRenderings+' will be inserted before 'leftover-questions'",
|
||||
[],
|
||||
"SubstituteLayer"
|
||||
"SubstituteLayer",
|
||||
)
|
||||
this._state = state
|
||||
}
|
||||
|
@ -80,21 +70,35 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
|
|||
(found["tagRenderings"] ?? []).length > 0
|
||||
) {
|
||||
context.err(
|
||||
`When overriding a layer, an override is not allowed to override into tagRenderings. Use "+tagRenderings" or "tagRenderings+" instead to prepend or append some questions.`
|
||||
`When overriding a layer, an override is not allowed to override into tagRenderings. Use "+tagRenderings" or "tagRenderings+" instead to prepend or append some questions.`,
|
||||
)
|
||||
}
|
||||
try {
|
||||
|
||||
const trPlus = json["override"]["tagRenderings+"]
|
||||
if(trPlus){
|
||||
let index = found.tagRenderings.findIndex(tr => tr["id"] === "leftover-questions")
|
||||
if(index < 0){
|
||||
index = found.tagRenderings.length
|
||||
}
|
||||
found.tagRenderings.splice(index, 0, ...trPlus)
|
||||
delete json["override"]["tagRenderings+"]
|
||||
}
|
||||
|
||||
Utils.Merge(json["override"], found)
|
||||
layers.push(found)
|
||||
} catch (e) {
|
||||
context.err(
|
||||
`Could not apply an override due to: ${e}.\nThe override is: ${JSON.stringify(
|
||||
json["override"]
|
||||
)}`
|
||||
json["override"],
|
||||
)}`,
|
||||
)
|
||||
}
|
||||
|
||||
if (json["hideTagRenderingsWithLabels"]) {
|
||||
if (typeof json["hideTagRenderingsWithLabels"] === "string") {
|
||||
throw "At " + context + ".hideTagRenderingsWithLabels should be a list containing strings, you specified a string"
|
||||
}
|
||||
const hideLabels: Set<string> = new Set(json["hideTagRenderingsWithLabels"])
|
||||
// These labels caused at least one deletion
|
||||
const usedLabels: Set<string> = new Set<string>()
|
||||
|
@ -107,9 +111,9 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
|
|||
usedLabels.add(labels[forbiddenLabel])
|
||||
context.info(
|
||||
"Dropping tagRendering " +
|
||||
tr["id"] +
|
||||
" as it has a forbidden label: " +
|
||||
labels[forbiddenLabel]
|
||||
tr["id"] +
|
||||
" as it has a forbidden label: " +
|
||||
labels[forbiddenLabel],
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
@ -118,7 +122,7 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
|
|||
if (hideLabels.has(tr["id"])) {
|
||||
usedLabels.add(tr["id"])
|
||||
context.info(
|
||||
"Dropping tagRendering " + tr["id"] + " as its id is a forbidden label"
|
||||
"Dropping tagRendering " + tr["id"] + " as its id is a forbidden label",
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
@ -127,10 +131,10 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
|
|||
usedLabels.add(tr["group"])
|
||||
context.info(
|
||||
"Dropping tagRendering " +
|
||||
tr["id"] +
|
||||
" as its group `" +
|
||||
tr["group"] +
|
||||
"` is a forbidden label"
|
||||
tr["id"] +
|
||||
" as its group `" +
|
||||
tr["group"] +
|
||||
"` is a forbidden label",
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
@ -141,8 +145,8 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
|
|||
if (unused.length > 0) {
|
||||
context.err(
|
||||
"This theme specifies that certain tagrenderings have to be removed based on forbidden layers. One or more of these layers did not match any tagRenderings and caused no deletions: " +
|
||||
unused.join(", ") +
|
||||
"\n This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore"
|
||||
unused.join(", ") +
|
||||
"\n This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore",
|
||||
)
|
||||
}
|
||||
found.tagRenderings = filtered
|
||||
|
@ -159,7 +163,7 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
|
|||
super(
|
||||
"Adds the default layers, namely: " + Constants.added_by_default.join(", "),
|
||||
["layers"],
|
||||
"AddDefaultLayers"
|
||||
"AddDefaultLayers",
|
||||
)
|
||||
this._state = state
|
||||
}
|
||||
|
@ -183,10 +187,10 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
|
|||
if (alreadyLoaded.has(v.id)) {
|
||||
context.warn(
|
||||
"Layout " +
|
||||
context +
|
||||
" already has a layer with name " +
|
||||
v.id +
|
||||
"; skipping inclusion of this builtin layer"
|
||||
context +
|
||||
" already has a layer with name " +
|
||||
v.id +
|
||||
"; skipping inclusion of this builtin layer",
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
@ -202,14 +206,14 @@ class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
|
|||
super(
|
||||
"For every layer in the 'layers'-list, create a new layer which'll import notes. (Note that priviliged layers and layers which have a geojson-source set are ignored)",
|
||||
["layers"],
|
||||
"AddImportLayers"
|
||||
"AddImportLayers",
|
||||
)
|
||||
}
|
||||
|
||||
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
|
||||
if (!(json.enableNoteImports ?? true)) {
|
||||
context.info(
|
||||
"Not creating a note import layers for theme " + json.id + " as they are disabled"
|
||||
"Not creating a note import layers for theme " + json.id + " as they are disabled",
|
||||
)
|
||||
return json
|
||||
}
|
||||
|
@ -244,7 +248,7 @@ class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
|
|||
try {
|
||||
const importLayerResult = creator.convert(
|
||||
layer,
|
||||
context.inOperation(this.name).enter(i1)
|
||||
context.inOperation(this.name).enter(i1),
|
||||
)
|
||||
if (importLayerResult !== undefined) {
|
||||
json.layers.push(importLayerResult)
|
||||
|
@ -263,7 +267,7 @@ class AddContextToTranslationsInLayout extends DesugaringStep<LayoutConfigJson>
|
|||
super(
|
||||
"Adds context to translations, including the prefix 'themes:json.id'; this is to make sure terms in an 'overrides' or inline layer are linkable too",
|
||||
["_context"],
|
||||
"AddContextToTranlationsInLayout"
|
||||
"AddContextToTranlationsInLayout",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -278,7 +282,7 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
|
|||
super(
|
||||
"Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards",
|
||||
["overrideAll", "layers"],
|
||||
"ApplyOverrideAll"
|
||||
"ApplyOverrideAll",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -292,9 +296,29 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
|
|||
|
||||
delete json.overrideAll
|
||||
const newLayers = []
|
||||
|
||||
let tagRenderingsPlus = undefined
|
||||
if (overrideAll["tagRenderings+"] !== undefined) {
|
||||
tagRenderingsPlus = overrideAll["tagRenderings+"]
|
||||
delete overrideAll["tagRenderings+"]
|
||||
}
|
||||
|
||||
for (let layer of json.layers) {
|
||||
layer = Utils.Clone(<LayerConfigJson>layer)
|
||||
Utils.Merge(overrideAll, layer)
|
||||
if (tagRenderingsPlus) {
|
||||
if (!layer.tagRenderings) {
|
||||
layer.tagRenderings = tagRenderingsPlus
|
||||
} else {
|
||||
|
||||
let index = layer.tagRenderings.findIndex(tr => tr["id"] === "leftover-questions")
|
||||
if (index < 0) {
|
||||
index = layer.tagRenderings.length - 1
|
||||
}
|
||||
layer.tagRenderings.splice(index, 0, ...tagRenderingsPlus)
|
||||
}
|
||||
}
|
||||
|
||||
newLayers.push(layer)
|
||||
}
|
||||
json.layers = newLayers
|
||||
|
@ -314,7 +338,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
Some layers (e.g. \`all_buildings_and_walls\' or \'streets_with_a_name\') are invisible, so by default, \'force_load\' is set too.
|
||||
`,
|
||||
["layers"],
|
||||
"AddDependencyLayersToTheme"
|
||||
"AddDependencyLayersToTheme",
|
||||
)
|
||||
this._state = state
|
||||
}
|
||||
|
@ -322,7 +346,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
private static CalculateDependencies(
|
||||
alreadyLoaded: LayerConfigJson[],
|
||||
allKnownLayers: Map<string, LayerConfigJson>,
|
||||
themeId: string
|
||||
themeId: string,
|
||||
): { config: LayerConfigJson; reason: string }[] {
|
||||
const dependenciesToAdd: { config: LayerConfigJson; reason: string }[] = []
|
||||
const loadedLayerIds: Set<string> = new Set<string>(alreadyLoaded.map((l) => l.id))
|
||||
|
@ -345,7 +369,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
for (const layerConfig of alreadyLoaded) {
|
||||
try {
|
||||
const layerDeps = DependencyCalculator.getLayerDependencies(
|
||||
new LayerConfig(layerConfig, themeId + "(dependencies)")
|
||||
new LayerConfig(layerConfig, themeId + "(dependencies)"),
|
||||
)
|
||||
dependencies.push(...layerDeps)
|
||||
} catch (e) {
|
||||
|
@ -382,10 +406,10 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
if (dep === undefined) {
|
||||
const message = [
|
||||
"Loading a dependency failed: layer " +
|
||||
unmetDependency.neededLayer +
|
||||
" is not found, neither as layer of " +
|
||||
themeId +
|
||||
" nor as builtin layer.",
|
||||
unmetDependency.neededLayer +
|
||||
" is not found, neither as layer of " +
|
||||
themeId +
|
||||
" nor as builtin layer.",
|
||||
reason,
|
||||
"Loaded layers are: " + alreadyLoaded.map((l) => l.id).join(","),
|
||||
]
|
||||
|
@ -401,7 +425,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
})
|
||||
loadedLayerIds.add(dep.id)
|
||||
unmetDependencies = unmetDependencies.filter(
|
||||
(d) => d.neededLayer !== unmetDependency.neededLayer
|
||||
(d) => d.neededLayer !== unmetDependency.neededLayer,
|
||||
)
|
||||
}
|
||||
} while (unmetDependencies.length > 0)
|
||||
|
@ -422,14 +446,14 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
const dependencies = AddDependencyLayersToTheme.CalculateDependencies(
|
||||
layers,
|
||||
allKnownLayers,
|
||||
theme.id
|
||||
theme.id,
|
||||
)
|
||||
for (const dependency of dependencies) {
|
||||
}
|
||||
if (dependencies.length > 0) {
|
||||
for (const dependency of dependencies) {
|
||||
context.info(
|
||||
"Added " + dependency.config.id + " to the theme. " + dependency.reason
|
||||
"Added " + dependency.config.id + " to the theme. " + dependency.reason,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -471,7 +495,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
|
|||
super(
|
||||
"Generates a warning if a theme uses an unsubstituted layer",
|
||||
["layers"],
|
||||
"WarnForUnsubstitutedLayersInTheme"
|
||||
"WarnForUnsubstitutedLayersInTheme",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -483,7 +507,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
|
|||
context
|
||||
.enter("layers")
|
||||
.err(
|
||||
"No layers are defined. You must define at least one layer to have a valid theme"
|
||||
"No layers are defined. You must define at least one layer to have a valid theme",
|
||||
)
|
||||
return json
|
||||
}
|
||||
|
@ -507,10 +531,10 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
|
|||
|
||||
context.warn(
|
||||
"The theme " +
|
||||
json.id +
|
||||
" has an inline layer: " +
|
||||
layer["id"] +
|
||||
". This is discouraged."
|
||||
json.id +
|
||||
" has an inline layer: " +
|
||||
layer["id"] +
|
||||
". This is discouraged.",
|
||||
)
|
||||
}
|
||||
return json
|
||||
|
@ -519,11 +543,12 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
|
|||
|
||||
export class PrepareTheme extends Fuse<LayoutConfigJson> {
|
||||
private state: DesugaringContext
|
||||
|
||||
constructor(
|
||||
state: DesugaringContext,
|
||||
options?: {
|
||||
skipDefaultLayers: false | boolean
|
||||
}
|
||||
},
|
||||
) {
|
||||
super(
|
||||
"Fully prepares and expands a theme",
|
||||
|
@ -536,6 +561,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
|
|||
// We expand all tagrenderings first...
|
||||
new On("layers", new Each(new PrepareLayer(state))),
|
||||
// Then we apply the override all. We must first expand everything in case that we override something in an expanded tag
|
||||
// Note that it'll cheat with tagRenderings+
|
||||
new ApplyOverrideAll(),
|
||||
// And then we prepare all the layers _again_ in case that an override all contained unexpanded tagrenderings!
|
||||
new On("layers", new Each(new PrepareLayer(state))),
|
||||
|
@ -543,7 +569,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
|
|||
? new Pass("AddDefaultLayers is disabled due to the set flag")
|
||||
: new AddDefaultLayers(state),
|
||||
new AddDependencyLayersToTheme(state),
|
||||
new AddImportLayers()
|
||||
new AddImportLayers(),
|
||||
)
|
||||
this.state = state
|
||||
}
|
||||
|
@ -558,13 +584,13 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
|
|||
const needsNodeDatabase = result.layers?.some((l: LayerConfigJson) =>
|
||||
l.tagRenderings?.some((tr) =>
|
||||
ValidationUtils.getSpecialVisualisations(<any>tr)?.some(
|
||||
(special) => special.needsNodeDatabase
|
||||
)
|
||||
)
|
||||
(special) => special.needsNodeDatabase,
|
||||
),
|
||||
),
|
||||
)
|
||||
if (needsNodeDatabase) {
|
||||
context.info(
|
||||
"Setting 'enableNodeDatabase' as this theme uses a special visualisation which needs to keep track of _all_ nodes"
|
||||
"Setting 'enableNodeDatabase' as this theme uses a special visualisation which needs to keep track of _all_ nodes",
|
||||
)
|
||||
result.enableNodeDatabase = true
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import { ConversionContext } from "./ConversionContext"
|
|||
import * as eli from "../../../assets/editor-layer-index.json"
|
||||
import { AvailableRasterLayers } from "../../RasterLayers"
|
||||
import Back from "../../../assets/svg/Back.svelte"
|
||||
import PointRenderingConfigJson from "../Json/PointRenderingConfigJson"
|
||||
|
||||
class ValidateLanguageCompleteness extends DesugaringStep<LayoutConfig> {
|
||||
private readonly _languages: string[]
|
||||
|
@ -177,6 +178,9 @@ export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
if (!json.title) {
|
||||
context.enter("title").err(`The theme ${json.id} does not have a title defined.`)
|
||||
}
|
||||
if(!json.icon){
|
||||
context.enter("icon").err("A theme should have an icon")
|
||||
}
|
||||
if (this._isBuiltin && this._extractImages !== undefined) {
|
||||
// Check images: are they local, are the licenses there, is the theme icon square, ...
|
||||
const images = this._extractImages.convert(json, context.inOperation("ValidateTheme"))
|
||||
|
@ -243,7 +247,8 @@ export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
|||
new ValidateLanguageCompleteness("en").convert(theme, context)
|
||||
}
|
||||
} catch (e) {
|
||||
context.err(e)
|
||||
console.error(e)
|
||||
context.err("Could not validate the theme due to: " + e)
|
||||
}
|
||||
|
||||
if (theme.id !== "personal") {
|
||||
|
@ -411,7 +416,7 @@ export class DetectConflictingAddExtraTags extends DesugaringStep<TagRenderingCo
|
|||
|
||||
return json
|
||||
} catch (e) {
|
||||
context.err(e)
|
||||
context.err("Could not check for conflicting extra tags due to: " + e)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
@ -1016,6 +1021,7 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
*/
|
||||
private readonly _path: string
|
||||
private readonly _studioValidations: boolean
|
||||
private readonly _validatePointRendering = new ValidatePointRendering()
|
||||
|
||||
constructor(path: string, isBuiltin, doesImageExist, studioValidations) {
|
||||
super("Runs various checks against common mistakes for a layer", [], "PrevalidateLayer")
|
||||
|
@ -1105,6 +1111,8 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
context.enter("pointRendering").err("There are no pointRenderings at all...")
|
||||
}
|
||||
|
||||
json.pointRendering?.forEach((pr,i) => this._validatePointRendering.convert(pr, context.enters("pointeRendering", i)))
|
||||
|
||||
if (json["mapRendering"]) {
|
||||
context.enter("mapRendering").err("This layer has a legacy 'mapRendering'")
|
||||
}
|
||||
|
@ -1409,13 +1417,40 @@ export class ValidateLayerConfig extends DesugaringStep<LayerConfigJson> {
|
|||
}
|
||||
}
|
||||
|
||||
class ValidatePointRendering extends DesugaringStep<PointRenderingConfigJson> {
|
||||
constructor() {
|
||||
super("Various checks for pointRenderings", [], "ValidatePOintRendering")
|
||||
}
|
||||
|
||||
convert(json: PointRenderingConfigJson, context: ConversionContext): PointRenderingConfigJson {
|
||||
if (json.marker === undefined && json.label === undefined) {
|
||||
context.err(`A point rendering should define at least an marker or a label`)
|
||||
}
|
||||
|
||||
if (json["markers"]) {
|
||||
context.enter("markers").err(`Detected a field 'markerS' in pointRendering. It is written as a singular case`)
|
||||
}
|
||||
if (json.marker && !Array.isArray(json.marker)) {
|
||||
context.enter("marker").err(
|
||||
"The marker in a pointRendering should be an array"
|
||||
)
|
||||
}
|
||||
if (json.location.length == 0) {
|
||||
context.enter("location").err (
|
||||
"A pointRendering should have at least one 'location' to defined where it should be rendered. "
|
||||
)
|
||||
}
|
||||
return json
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
export class ValidateLayer extends Conversion<
|
||||
LayerConfigJson,
|
||||
{ parsed: LayerConfig; raw: LayerConfigJson }
|
||||
> {
|
||||
private readonly _skipDefaultLayers: boolean
|
||||
private readonly _prevalidation: PrevalidateLayer
|
||||
|
||||
constructor(
|
||||
path: string,
|
||||
isBuiltin: boolean,
|
||||
|
|
|
@ -506,7 +506,7 @@ export interface LayerConfigJson {
|
|||
* If the way is part of a relation, MapComplete will attempt to update this relation as well
|
||||
* question: Should the contributor be able to split ways using this layer?
|
||||
* iftrue: enable the 'split-roads'-component
|
||||
* iffalse: don't enable the split-roads componenet
|
||||
* iffalse: don't enable the split-roads component
|
||||
* ifunset: don't enable the split-roads component
|
||||
* group: editing
|
||||
*/
|
||||
|
|
|
@ -5,7 +5,7 @@ export interface IconConfigJson {
|
|||
/**
|
||||
* question: What icon should be used?
|
||||
* type: icon
|
||||
* suggestions: return ["pin","square","circle","checkmark","clock","close","crosshair","help","home","invalid","location","location_empty","location_locked","note","resolved","ring","scissors","teardrop","teardrop_with_hole_green","triangle"].map(i => ({if: "value="+i, then: i, icon: i}))
|
||||
* suggestions: return Constants.defaultPinIcons.map(i => ({if: "value="+i, then: i, icon: i}))
|
||||
*/
|
||||
icon: string | MinimalTagRenderingConfigJson | { builtin: string; override: any }
|
||||
/**
|
||||
|
|
|
@ -106,8 +106,12 @@ export interface MappingConfigJson {
|
|||
hideInAnswer?: boolean | TagConfigJson
|
||||
|
||||
/**
|
||||
* question: In what other cases should this item be rendered?
|
||||
*
|
||||
* Also show this 'then'-option if the feature matches these tags.
|
||||
* Ideal for outdated tags.
|
||||
* Ideal for outdated tags or default assumptions. The tags from this options will <b>not</b> be set if the option is chosen!
|
||||
*
|
||||
* ifunset: No other cases when this text is shown
|
||||
*/
|
||||
alsoShowIf?: TagConfigJson
|
||||
|
||||
|
|
|
@ -79,23 +79,7 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
}
|
||||
})
|
||||
|
||||
if (json.marker === undefined && json.label === undefined) {
|
||||
throw `At ${context}: A point rendering should define at least an marker or a label`
|
||||
}
|
||||
|
||||
if (json["markers"]) {
|
||||
throw `At ${context}.markers: detected a field 'markerS' in pointRendering. It is written as a singular case`
|
||||
}
|
||||
if (json.marker && !Array.isArray(json.marker)) {
|
||||
throw `At ${context}.marker: the marker in a pointRendering should be an array`
|
||||
}
|
||||
if (this.location.size == 0) {
|
||||
throw (
|
||||
"A pointRendering should have at least one 'location' to defined where it should be rendered. (At " +
|
||||
context +
|
||||
".location)"
|
||||
)
|
||||
}
|
||||
this.marker = (json.marker ?? []).map((m) => new IconConfig(<any>m))
|
||||
if (json.css !== undefined) {
|
||||
this.cssDef = this.tr("css", undefined)
|
||||
|
|
|
@ -15,7 +15,6 @@ import {
|
|||
QuestionableTagRenderingConfigJson,
|
||||
} from "./Json/QuestionableTagRenderingConfigJson"
|
||||
import { FixedUiElement } from "../../UI/Base/FixedUiElement"
|
||||
import { Paragraph } from "../../UI/Base/Paragraph"
|
||||
import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
|
||||
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
|
||||
import Constants from "../Constants"
|
||||
|
@ -371,20 +370,9 @@ export default class TagRenderingConfig {
|
|||
let iconClass = commonSize
|
||||
if (!!mapping.icon) {
|
||||
if (typeof mapping.icon === "string" && mapping.icon !== "") {
|
||||
let stripped = mapping.icon
|
||||
if (stripped.endsWith(".svg")) {
|
||||
stripped = stripped.substring(0, stripped.length - 4)
|
||||
}
|
||||
if (Constants.defaultPinIcons.indexOf(stripped) >= 0) {
|
||||
icon = "./assets/svg/" + mapping.icon
|
||||
if (!icon.endsWith(".svg")) {
|
||||
icon += ".svg"
|
||||
}
|
||||
} else {
|
||||
icon = mapping.icon
|
||||
}
|
||||
icon = mapping.icon.trim()
|
||||
} else if (mapping.icon["path"]) {
|
||||
icon = mapping.icon["path"]
|
||||
icon = mapping.icon["path"].trim()
|
||||
iconClass = mapping.icon["class"] ?? iconClass
|
||||
}
|
||||
}
|
||||
|
@ -754,12 +742,10 @@ export default class TagRenderingConfig {
|
|||
withRender = [
|
||||
`This rendering asks information about the property `,
|
||||
Link.OsmWiki(this.freeform.key),
|
||||
new Paragraph(
|
||||
new Combine([
|
||||
"This is rendered with ",
|
||||
new FixedUiElement(this.render.txt).SetClass("code font-bold"),
|
||||
])
|
||||
),
|
||||
new Combine([
|
||||
"This is rendered with ",
|
||||
new FixedUiElement(this.render.txt).SetClass("code font-bold"),
|
||||
]),
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ import NearbyFeatureSource from "../Logic/FeatureSource/Sources/NearbyFeatureSou
|
|||
import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFeatureSource"
|
||||
import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider"
|
||||
import { GeolocationControlState } from "../UI/BigComponents/GeolocationControl"
|
||||
import Zoomcontrol from "../UI/Zoomcontrol"
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -481,6 +482,12 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
this.lastClickObject.features.setData([])
|
||||
})
|
||||
|
||||
this.selectedElement.addCallback((selected) => {
|
||||
if (selected === undefined) {
|
||||
Zoomcontrol.resetzoom()
|
||||
}
|
||||
})
|
||||
|
||||
if (this.layout.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) {
|
||||
Utils.LoadCustomCss(this.layout.customCss)
|
||||
}
|
||||
|
@ -524,7 +531,10 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
}
|
||||
this.selectedElement.setData(undefined)
|
||||
this.guistate.closeAll()
|
||||
this.focusOnMap()
|
||||
if (!this.guistate.isSomethingOpen()) {
|
||||
Zoomcontrol.resetzoom()
|
||||
this.focusOnMap()
|
||||
}
|
||||
})
|
||||
|
||||
Hotkeys.RegisterHotkey({ nomod: "f" }, docs.selectFavourites, () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue