diff --git a/Logic/DetermineLayout.ts b/Logic/DetermineLayout.ts index 563b8c1a79..b29e5f8b5a 100644 --- a/Logic/DetermineLayout.ts +++ b/Logic/DetermineLayout.ts @@ -10,6 +10,7 @@ import {UIEventSource} from "./UIEventSource"; import {LocalStorageSource} from "./Web/LocalStorageSource"; import LZString from "lz-string"; import * as personal from "../assets/themes/personal/personal.json"; +import LegacyJsonConvert from "../Models/ThemeConfig/LegacyJsonConvert"; export default class DetermineLayout { @@ -74,6 +75,7 @@ export default class DetermineLayout { const parsed = await Utils.downloadJson(link) console.log("Got ", parsed) + LegacyJsonConvert.fixThemeConfig(parsed) try { parsed.id = link; return new LayoutConfig(parsed, false).patchImages(link, JSON.stringify(parsed)); @@ -136,6 +138,7 @@ export default class DetermineLayout { } } + LegacyJsonConvert.fixThemeConfig(json) const layoutToUse = new LayoutConfig(json, false); userLayoutParam.setData(layoutToUse.id); return [layoutToUse, btoa(Utils.MinifyJSON(JSON.stringify(json)))]; diff --git a/Models/ThemeConfig/LayerConfig.ts b/Models/ThemeConfig/LayerConfig.ts index b09ffcb603..e30f0a20ed 100644 --- a/Models/ThemeConfig/LayerConfig.ts +++ b/Models/ThemeConfig/LayerConfig.ts @@ -1,7 +1,6 @@ import {Translation} from "../../UI/i18n/Translation"; import SourceConfig from "./SourceConfig"; import TagRenderingConfig from "./TagRenderingConfig"; -import {TagsFilter} from "../../Logic/Tags/TagsFilter"; import PresetConfig from "./PresetConfig"; import {LayerConfigJson} from "./Json/LayerConfigJson"; import Translations from "../../UI/i18n/Translations"; @@ -58,56 +57,43 @@ export default class LayerConfig extends WithContextLoader { context = context + "." + json.id; super(json, context) this.id = json.id; - let legacy = undefined; - if (json["overpassTags"] !== undefined) { - // @ts-ignore - legacy = TagUtils.Tag(json["overpassTags"], context + ".overpasstags"); + + if (json.source === undefined) { + throw "Layer " + this.id + " does not define a source section ("+context+")" } - if (json.source !== undefined) { - this.maxAgeOfCache = json.source.maxCacheAge ?? 24 * 60 * 60 * 30 - if (legacy !== undefined) { - throw ( - context + - "Both the legacy 'layer.overpasstags' and the new 'layer.source'-field are defined" - ); - } + if (json.source.osmTags === undefined) { + throw "Layer " + this.id + " does not define a osmTags in the source section - these should always be present, even for geojson layers ("+context+")" - let osmTags: TagsFilter = legacy; - if (json.source["osmTags"]) { - osmTags = TagUtils.Tag( - json.source["osmTags"], - context + "source.osmTags" - ); - } - - if (json.source["geoJsonSource"] !== undefined) { - throw context + "Use 'geoJson' instead of 'geoJsonSource'"; - } - - if (json.source["geojson"] !== undefined) { - throw context + "Use 'geoJson' instead of 'geojson' (the J is a capital letter)"; - } - - this.source = new SourceConfig( - { - osmTags: osmTags, - geojsonSource: json.source["geoJson"], - geojsonSourceLevel: json.source["geoJsonZoomLevel"], - overpassScript: json.source["overpassScript"], - isOsmCache: json.source["isOsmCache"], - mercatorCrs: json.source["mercatorCrs"] - }, - json.id - ); - }else if(legacy === undefined){ - throw "No valid source defined ("+context+")" - } else { - this.source = new SourceConfig({ - osmTags: legacy, - }); } + this.maxAgeOfCache = json.source.maxCacheAge ?? 24 * 60 * 60 * 30 + + const osmTags = TagUtils.Tag( + json.source.osmTags, + context + "source.osmTags" + ); + + if (json.source["geoJsonSource"] !== undefined) { + throw context + "Use 'geoJson' instead of 'geoJsonSource'"; + } + + if (json.source["geojson"] !== undefined) { + throw context + "Use 'geoJson' instead of 'geojson' (the J is a capital letter)"; + } + + this.source = new SourceConfig( + { + osmTags: osmTags, + geojsonSource: json.source["geoJson"], + geojsonSourceLevel: json.source["geoJsonZoomLevel"], + overpassScript: json.source["overpassScript"], + isOsmCache: json.source["isOsmCache"], + mercatorCrs: json.source["mercatorCrs"] + }, + json.id + ); + this.allowSplit = json.allowSplit ?? false; this.name = Translations.T(json.name, context + ".name"); @@ -284,11 +270,13 @@ export default class LayerConfig extends WithContextLoader { const normalTagRenderings: (string | { builtin: string, override: any } | TagRenderingConfigJson)[] = [] - - const renderingsToRewrite: ({ rewrite:{ + + const renderingsToRewrite: ({ + rewrite: { sourceString: string, into: string[] - }, renderings: (string | { builtin: string, override: any } | TagRenderingConfigJson)[] })[] = [] + }, renderings: (string | { builtin: string, override: any } | TagRenderingConfigJson)[] + })[] = [] for (let i = 0; i < json.tagRenderings.length; i++) { const tr = json.tagRenderings[i]; const rewriteDefined = tr["rewrite"] !== undefined @@ -309,17 +297,17 @@ export default class LayerConfig extends WithContextLoader { const allRenderings = this.ParseTagRenderings(normalTagRenderings, false); - if(renderingsToRewrite.length === 0){ + if (renderingsToRewrite.length === 0) { return allRenderings } - - function prepConfig(keyToRewrite: string, target:string, tr: TagRenderingConfigJson){ - - function replaceRecursive(transl: string | any){ - if(typeof transl === "string"){ + + function prepConfig(keyToRewrite: string, target: string, tr: TagRenderingConfigJson) { + + function replaceRecursive(transl: string | any) { + if (typeof transl === "string") { return transl.replace(keyToRewrite, target) } - if(transl.map !== undefined){ + if (transl.map !== undefined) { return transl.map(o => replaceRecursive(o)) } transl = {...transl} @@ -328,39 +316,39 @@ export default class LayerConfig extends WithContextLoader { } return transl } - + const orig = tr; tr = replaceRecursive(tr) - - tr.id = target+"-"+orig.id + + tr.id = target + "-" + orig.id tr.group = target return tr } const rewriteGroups: Map = new Map() for (const rewriteGroup of renderingsToRewrite) { - + const tagRenderings = rewriteGroup.renderings const textToReplace = rewriteGroup.rewrite.sourceString const targets = rewriteGroup.rewrite.into for (const target of targets) { const parsedRenderings = this.ParseTagRenderings(tagRenderings, false, tr => prepConfig(textToReplace, target, tr)) - - if(!rewriteGroups.has(target)){ + + if (!rewriteGroups.has(target)) { rewriteGroups.set(target, []) } - rewriteGroups.get(target).push(... parsedRenderings) + rewriteGroups.get(target).push(...parsedRenderings) } } - - + + rewriteGroups.forEach((group, groupName) => { group.push(new TagRenderingConfig({ - id:"questions", - group:groupName + id: "questions", + group: groupName })) }) - + rewriteGroups.forEach(group => { allRenderings.push(...group) }) diff --git a/Models/ThemeConfig/LegacyJsonConvert.ts b/Models/ThemeConfig/LegacyJsonConvert.ts new file mode 100644 index 0000000000..43274643c7 --- /dev/null +++ b/Models/ThemeConfig/LegacyJsonConvert.ts @@ -0,0 +1,108 @@ +import LineRenderingConfigJson from "./Json/LineRenderingConfigJson"; + +export default class LegacyJsonConvert { + + /** + * Updates the config file in-place + * @param config + * @private + */ + public static fixLayerConfig(config: any): void { + if (config["overpassTags"]) { + config.source = config.source ?? {} + config.source.osmTags = config["overpassTags"] + delete config["overpassTags"] + } + + if (config.tagRenderings !== undefined) { + for (const tagRendering of config.tagRenderings) { + if (tagRendering["#"] !== undefined) { + tagRendering["id"] = tagRendering["#"] + delete tagRendering["#"] + } + if (tagRendering["id"] === undefined) { + if (tagRendering["freeform"]?.key !== undefined) { + tagRendering["id"] = config.id + "-" + tagRendering["freeform"]["key"] + } + } + } + } + + if (config.mapRendering === undefined && config.id !== "sidewalks") { + // This is a legacy format, lets create a pointRendering + let location: ("point" | "centroid")[] = ["point"] + let wayHandling: number = config["wayHandling"] ?? 0 + if (wayHandling === 2) { + location = ["point", "centroid"] + } + config.mapRendering = [ + { + icon: config["icon"], + iconBadges: config["iconOverlays"], + label: config["label"], + iconSize: config["iconSize"], + location, + rotation: config["rotation"] + } + ] + + if (wayHandling !== 1) { + const lineRenderConfig = { + color: config["color"], + width: config["width"], + dashArray: config["dashArray"] + } + if (Object.keys(lineRenderConfig).length > 0) { + config.mapRendering.push(lineRenderConfig) + } + } + + + delete config["color"] + delete config["width"] + delete config["dashArray"] + + delete config["icon"] + delete config["iconOverlays"] + delete config["label"] + delete config["iconSize"] + delete config["rotation"] + delete config["wayHandling"] + + } + + for (const mapRenderingElement of config.mapRendering) { + if (mapRenderingElement["iconOverlays"] !== undefined) { + mapRenderingElement["iconBadges"] = mapRenderingElement["iconOverlays"] + } + for (const overlay of mapRenderingElement["iconBadges"] ?? []) { + if (overlay["badge"] !== true) { + console.log("Warning: non-overlay element for ", config.id) + } + delete overlay["badge"] + } + } + + } + + + /** + * Given an old (parsed) JSON-config, will (in place) fix some issues + * @param oldThemeConfig: the config to update to the latest format + */ + public static fixThemeConfig(oldThemeConfig: any): void { + for (const layerConfig of oldThemeConfig.layers ?? []) { + if (typeof layerConfig === "string" || layerConfig["builtin"] !== undefined) { + continue + } + // @ts-ignore + LegacyJsonConvert.fixLayerConfig(layerConfig) + } + + if (oldThemeConfig["roamingRenderings"] !== undefined && oldThemeConfig["roamingRenderings"].length == 0) { + delete oldThemeConfig["roamingRenderings"] + } + } + + +} \ No newline at end of file diff --git a/assets/layers/waste_basket/waste_basket.json b/assets/layers/waste_basket/waste_basket.json index 71d686f305..3e89c9e5a0 100644 --- a/assets/layers/waste_basket/waste_basket.json +++ b/assets/layers/waste_basket/waste_basket.json @@ -90,8 +90,7 @@ "id": "dispensing_dog_bags", "question": { "en": "Does this waste basket have a dispenser for dog excrement bags?", - "nl": "Heeft deze vuilnisbak een verdeler voor hondenpoepzakjes?", - "then": "Heeft deze vuilnisbak een verdeler voor hondenpoepzakjes?" + "nl": "Heeft deze vuilnisbak een verdeler voor hondenpoepzakjes?" }, "condition": { "or": [ diff --git a/assets/themes/grb_import/grb.json b/assets/themes/grb_import/grb.json index c79f6e5fe3..057bd50804 100644 --- a/assets/themes/grb_import/grb.json +++ b/assets/themes/grb_import/grb.json @@ -555,6 +555,7 @@ { "id": "GRB", "source": { + "osmTags": "HUISNR~*", "geoJson": "https://betadata.grbosm.site/grb?bbox={x_min},{y_min},{x_max},{y_max}", "geoJsonZoomLevel": 18, "mercatorCrs": true, diff --git a/index.ts b/index.ts index a383eaac26..3ff564ca95 100644 --- a/index.ts +++ b/index.ts @@ -1,7 +1,6 @@ import {FixedUiElement} from "./UI/Base/FixedUiElement"; import {QueryParameters} from "./Logic/Web/QueryParameters"; import Combine from "./UI/Base/Combine"; -import ValidatedTextField from "./UI/Input/ValidatedTextField"; import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers"; import MinimapImplementation from "./UI/Base/MinimapImplementation"; import CountryCoder from "latlon2country/index"; @@ -70,7 +69,6 @@ class Init { window.mapcomplete_state = State.state; new DefaultGUI(State.state, guiState) - if (encoded !== undefined && encoded.length > 10) { // We save the layout to the user settings and local storage State.state.osmConnection.OnLoggedIn(() => { @@ -78,13 +76,8 @@ class Init { .GetLongPreference("installed-theme-" + layoutToUse.id) .setData(encoded); }); - } - - } - - } diff --git a/scripts/generateTranslations.ts b/scripts/generateTranslations.ts index 7880605494..760fbbd4e2 100644 --- a/scripts/generateTranslations.ts +++ b/scripts/generateTranslations.ts @@ -31,6 +31,9 @@ class TranslationPart { if (!translations.hasOwnProperty(translationsKey)) { continue; } + if(translationsKey == "then"){ + throw "Suspicious translation at "+context + } const v = translations[translationsKey] if (typeof (v) != "string") { console.error("Non-string object in translation while trying to add more translations to '", translationsKey, "': ", v) diff --git a/scripts/lint.ts b/scripts/lint.ts index 565903c23c..e883fa3aea 100644 --- a/scripts/lint.ts +++ b/scripts/lint.ts @@ -1,114 +1,23 @@ -/* - * This script reads all theme and layer files and reformats them inplace - * Use with caution, make a commit beforehand! - */ - import ScriptUtils from "./ScriptUtils"; import {writeFileSync} from "fs"; import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson"; import LineRenderingConfigJson from "../Models/ThemeConfig/Json/LineRenderingConfigJson"; +import LegacyJsonConvert from "../Models/ThemeConfig/LegacyJsonConvert"; -/** - * In place fix +/* + * This script reads all theme and layer files and reformats them inplace + * Use with caution, make a commit beforehand! */ -function fixLayerConfig(config: LayerConfigJson): void { - if(config["overpassTags"]){ - config.source.osmTags = config["overpassTags"] - delete config["overpassTags"] - } - - if (config.tagRenderings !== undefined) { - for (const tagRendering of config.tagRenderings) { - if (tagRendering["#"] !== undefined) { - tagRendering["id"] = tagRendering["#"] - delete tagRendering["#"] - } - if (tagRendering["id"] === undefined) { - if (tagRendering["freeform"]?.key !== undefined) { - tagRendering["id"] = config.id + "-" + tagRendering["freeform"]["key"] - } - } - } - } - - if (config.mapRendering === undefined && config.id !== "sidewalks") { - // This is a legacy format, lets create a pointRendering - let location: ("point" | "centroid")[] = ["point"] - let wayHandling: number = config["wayHandling"] ?? 0 - if (wayHandling === 2) { - location = ["point", "centroid"] - } - config.mapRendering = [ - { - icon: config["icon"], - iconBadges: config["iconOverlays"], - label: config["label"], - iconSize: config["iconSize"], - location, - rotation: config["rotation"] - } - ] - - if (wayHandling !== 1) { - const lineRenderConfig = { - color: config["color"], - width: config["width"], - dashArray: config["dashArray"] - } - if (Object.keys(lineRenderConfig).length > 0) { - config.mapRendering.push(lineRenderConfig) - } - } - - - delete config["color"] - delete config["width"] - delete config["dashArray"] - - delete config["icon"] - delete config["iconOverlays"] - delete config["label"] - delete config["iconSize"] - delete config["rotation"] - delete config["wayHandling"] - - } - - for (const mapRenderingElement of config.mapRendering) { - if (mapRenderingElement["iconOverlays"] !== undefined) { - mapRenderingElement["iconBadges"] = mapRenderingElement["iconOverlays"] - } - for (const overlay of mapRenderingElement["iconBadges"] ?? []) { - if (overlay["badge"] !== true) { - console.log("Warning: non-overlay element for ", config.id) - } - delete overlay["badge"] - } - } - -} const layerFiles = ScriptUtils.getLayerFiles(); for (const layerFile of layerFiles) { - fixLayerConfig(layerFile.parsed) + LegacyJsonConvert. fixLayerConfig(layerFile.parsed) writeFileSync(layerFile.path, JSON.stringify(layerFile.parsed, null, " ")) } const themeFiles = ScriptUtils.getThemeFiles() for (const themeFile of themeFiles) { - for (const layerConfig of themeFile.parsed.layers ?? []) { - if (typeof layerConfig === "string" || layerConfig["builtin"] !== undefined) { - continue - } - // @ts-ignore - fixLayerConfig(layerConfig) - } - - if (themeFile.parsed["roamingRenderings"] !== undefined && themeFile.parsed["roamingRenderings"].length == 0) { - delete themeFile.parsed["roamingRenderings"] - } - + LegacyJsonConvert.fixThemeConfig(themeFile.parsed) writeFileSync(themeFile.path, JSON.stringify(themeFile.parsed, null, " ")) } -//*/