Move legacy theme handling into a rewritting class, various small fixes

This commit is contained in:
pietervdvn 2021-10-29 01:41:37 +02:00
parent 4471319588
commit c2682fc56d
8 changed files with 178 additions and 174 deletions

View file

@ -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)))];

View file

@ -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<string, TagRenderingConfig[]> = new Map<string, TagRenderingConfig[]>()
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)
})

View file

@ -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 = <LineRenderingConfigJson>{
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"]
}
}
}

View file

@ -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": [

View file

@ -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,

View file

@ -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);
});
}
}
}

View file

@ -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)

View file

@ -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 = <LineRenderingConfigJson>{
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, " "))
}
//*/