forked from MapComplete/MapComplete
		
	Better tag rewriting, add icons, add bicycle rental theme
This commit is contained in:
		
							parent
							
								
									1dcb3897e4
								
							
						
					
					
						commit
						9594868e83
					
				
					 23 changed files with 389 additions and 117 deletions
				
			
		|  | @ -49,8 +49,26 @@ export default class SharedTagRenderings { | ||||||
|                 return |                 return | ||||||
|             } |             } | ||||||
|             value.id = value.id ?? key; |             value.id = value.id ?? key; | ||||||
|  |             if(value["builtin"] !== undefined){ | ||||||
|  |                 if(value["override"] == undefined){ | ||||||
|  |                     throw "HUH? Why whould you want to reuse a builtin if one doesn't override? In questions.json/"+key | ||||||
|  |                 } | ||||||
|  |                 if(typeof value["builtin"] !== "string"){ | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 // This is a really funny situation: we extend another tagRendering!
 | ||||||
|  |                 const parent = Utils.Clone(dict.get(value["builtin"])) | ||||||
|  |                 delete parent.id | ||||||
|  |                 Utils.Merge(value["override"], parent) | ||||||
|  |                 delete value["builtin"] | ||||||
|  |                 delete value["override"] | ||||||
|  |                 for (const pkey in parent) { | ||||||
|  |                     value[pkey] = parent[pkey] | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         }) |         }) | ||||||
| 
 | 
 | ||||||
|  |          | ||||||
|         return dict; |         return dict; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ import SharedTagRenderings from "../Customizations/SharedTagRenderings"; | ||||||
| import * as known_layers from "../assets/generated/known_layers.json" | import * as known_layers from "../assets/generated/known_layers.json" | ||||||
| import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson"; | import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson"; | ||||||
| import {PrepareTheme} from "../Models/ThemeConfig/Conversion/PrepareTheme"; | import {PrepareTheme} from "../Models/ThemeConfig/Conversion/PrepareTheme"; | ||||||
|  | import {Layer} from "leaflet"; | ||||||
| 
 | 
 | ||||||
| export default class DetermineLayout { | export default class DetermineLayout { | ||||||
| 
 | 
 | ||||||
|  | @ -134,9 +135,9 @@ export default class DetermineLayout { | ||||||
| 
 | 
 | ||||||
|     private static prepCustomTheme(json: any): LayoutConfigJson { |     private static prepCustomTheme(json: any): LayoutConfigJson { | ||||||
|         const knownLayersDict = new Map<string, LayerConfigJson>() |         const knownLayersDict = new Map<string, LayerConfigJson>() | ||||||
|         for (const key in known_layers["default"]) { |         for (const key in known_layers.layers) { | ||||||
|             const layer = known_layers["default"][key] |             const layer = known_layers.layers[key] | ||||||
|             knownLayersDict.set(layer.id, layer) |             knownLayersDict.set(layer.id,<LayerConfigJson> layer) | ||||||
|         } |         } | ||||||
|         const converState = { |         const converState = { | ||||||
|             tagRenderings: SharedTagRenderings.SharedTagRenderingJson, |             tagRenderings: SharedTagRenderings.SharedTagRenderingJson, | ||||||
|  |  | ||||||
|  | @ -2,6 +2,8 @@ import {Conversion, DesugaringContext, Fuse, OnEveryConcat, SetDefault} from "./ | ||||||
| import {LayerConfigJson} from "../Json/LayerConfigJson"; | import {LayerConfigJson} from "../Json/LayerConfigJson"; | ||||||
| import {TagRenderingConfigJson} from "../Json/TagRenderingConfigJson"; | import {TagRenderingConfigJson} from "../Json/TagRenderingConfigJson"; | ||||||
| import {Utils} from "../../../Utils"; | import {Utils} from "../../../Utils"; | ||||||
|  | import Translations from "../../../UI/i18n/Translations"; | ||||||
|  | import {Translation} from "../../../UI/i18n/Translation"; | ||||||
| 
 | 
 | ||||||
| class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | { builtin: string | string[], override: any }, TagRenderingConfigJson[]> { | class ExpandTagRendering extends Conversion<string | TagRenderingConfigJson | { builtin: string | string[], override: any }, TagRenderingConfigJson[]> { | ||||||
|     constructor() { |     constructor() { | ||||||
|  | @ -156,13 +158,36 @@ class ExpandGroupRewrite extends Conversion<{ | ||||||
|         } |         } | ||||||
|         let config = <{ |         let config = <{ | ||||||
|             rewrite: |             rewrite: | ||||||
|                 { sourceString: string; into: string[] }[]; |                 { sourceString: string[]; into: (string | any)[][] }; | ||||||
|             renderings: (string | { builtin: string; override: any } | TagRenderingConfigJson)[] |             renderings: (string | { builtin: string; override: any } | TagRenderingConfigJson)[] | ||||||
|         }>json; |         }>json; | ||||||
| 
 | 
 | ||||||
|  |         { | ||||||
|  |             const errors = [] | ||||||
|    |    | ||||||
|         const subRenderingsRes = ExpandGroupRewrite.expandSubTagRenderings.convertAll(state, config.renderings, context); |             const expectedLength = config.rewrite.sourceString.length | ||||||
|         const subRenderings: TagRenderingConfigJson[] = [].concat(subRenderingsRes.result); |             for (let i = 0; i < config.rewrite.into.length; i++){ | ||||||
|  |                 const targets = config.rewrite.into[i]; | ||||||
|  |                 if(targets.length !== expectedLength){ | ||||||
|  |                     errors.push(context+".rewrite.into["+i+"]: expected "+expectedLength+" values, but got "+targets.length) | ||||||
|  |                 } | ||||||
|  |                 if(typeof targets[0] !== "string"){ | ||||||
|  |                     errors.push(context+".rewrite.into["+i+"]: expected a string as first rewrite value values, but got "+targets[0]) | ||||||
|  | 
 | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (errors.length > 0) { | ||||||
|  |                 return { | ||||||
|  |                     errors, | ||||||
|  |                     warnings: [], | ||||||
|  |                     result: undefined | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const subRenderingsRes = <{ result: TagRenderingConfigJson[][], errors, warnings }> ExpandGroupRewrite.expandSubTagRenderings.convertAll(state, config.renderings, context); | ||||||
|  |         const subRenderings: TagRenderingConfigJson[] = [].concat(...subRenderingsRes.result); | ||||||
|         const errors = subRenderingsRes.errors; |         const errors = subRenderingsRes.errors; | ||||||
|         const warnings = subRenderingsRes.warnings; |         const warnings = subRenderingsRes.warnings; | ||||||
| 
 | 
 | ||||||
|  | @ -170,22 +195,31 @@ class ExpandGroupRewrite extends Conversion<{ | ||||||
|         const rewrittenPerGroup = new Map<string, TagRenderingConfigJson[]>() |         const rewrittenPerGroup = new Map<string, TagRenderingConfigJson[]>() | ||||||
| 
 | 
 | ||||||
|         // The actual rewriting
 |         // The actual rewriting
 | ||||||
|         for (const rewrite of config.rewrite) { |         const sourceStrings = config.rewrite.sourceString; | ||||||
|             const source = rewrite.sourceString; |         for (const targets of config.rewrite.into) { | ||||||
|             for (const target of rewrite.into) { |             const groupName = targets[0]; | ||||||
|                 const groupName = target; |             if(typeof groupName !== "string"){ | ||||||
|                 const trs: TagRenderingConfigJson[] = [] |                 throw "The first string of 'targets' should always be a string" | ||||||
|  |             } | ||||||
|  |             const trs: TagRenderingConfigJson[] = [] | ||||||
| 
 | 
 | ||||||
|                 for (const tr of subRenderings) { |             for (const tr of subRenderings) { | ||||||
|                     trs.push(this.prepConfig(source, target, tr)) |                 let rewritten = tr; | ||||||
|  |                 for (let i = 0; i < sourceStrings.length; i++) { | ||||||
|  |                     const source = sourceStrings[i] | ||||||
|  |                     const target = targets[i] // This is a string OR a translation
 | ||||||
|  |                     console.log("Replacing every "+source+" with "+JSON.stringify(target)) | ||||||
|  |                     rewritten = this.prepConfig(source, target, rewritten) | ||||||
|                 } |                 } | ||||||
|                 if (rewrittenPerGroup.has(groupName)) { |                 rewritten.group = rewritten.group ?? groupName | ||||||
|                     rewrittenPerGroup.get(groupName).push(...trs) |                 trs.push(rewritten) | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|                 } else { |             if (rewrittenPerGroup.has(groupName)) { | ||||||
|                     rewrittenPerGroup.set(groupName, trs) |                 rewrittenPerGroup.get(groupName).push(...trs) | ||||||
|  |             } else { | ||||||
|  |                 rewrittenPerGroup.set(groupName, trs) | ||||||
| 
 | 
 | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -201,7 +235,7 @@ class ExpandGroupRewrite extends Conversion<{ | ||||||
|         rewrittenPerGroup.forEach((group, _) => { |         rewrittenPerGroup.forEach((group, _) => { | ||||||
|             group.forEach(tr => { |             group.forEach(tr => { | ||||||
|                 if (tr.id === undefined || tr.id === "") { |                 if (tr.id === undefined || tr.id === "") { | ||||||
|                     errors.push("A tagrendering has an empty ID after expanding the tag") |                     errors.push("A tagrendering has an empty ID after expanding the tag; the tagrendering is: "+JSON.stringify(tr)) | ||||||
|                 } |                 } | ||||||
|             }) |             }) | ||||||
|         }) |         }) | ||||||
|  | @ -212,16 +246,26 @@ class ExpandGroupRewrite extends Conversion<{ | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Used for left|right group creation and replacement */ |     /* Used for left|right group creation and replacement. | ||||||
|     private prepConfig(keyToRewrite: string, target: string, tr: TagRenderingConfigJson) { |     * Every 'keyToRewrite' will be replaced with 'target' recursively. This substitution will happen in place in the object 'tr' */ | ||||||
|  |     private prepConfig(keyToRewrite: string, target: string | any, tr: TagRenderingConfigJson): TagRenderingConfigJson { | ||||||
|  | 
 | ||||||
|  |         const isTranslation = typeof target !== "string" | ||||||
| 
 | 
 | ||||||
|         function replaceRecursive(transl: string | any) { |         function replaceRecursive(transl: string | any) { | ||||||
|             if (typeof transl === "string") { |             if (typeof transl === "string") { | ||||||
|  |                 // This is a simple string - we do a simple replace
 | ||||||
|                 return transl.replace(keyToRewrite, target) |                 return transl.replace(keyToRewrite, target) | ||||||
|             } |             } | ||||||
|             if (transl.map !== undefined) { |             if (transl.map !== undefined) { | ||||||
|  |                 // This is a list of items
 | ||||||
|                 return transl.map(o => replaceRecursive(o)) |                 return transl.map(o => replaceRecursive(o)) | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             if (Translations.isProbablyATranslation(transl) && isTranslation) { | ||||||
|  |                 return Translations.T(transl).Fuse(new Translation(target), keyToRewrite).translations | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             transl = {...transl} |             transl = {...transl} | ||||||
|             for (const key in transl) { |             for (const key in transl) { | ||||||
|                 transl[key] = replaceRecursive(transl[key]) |                 transl[key] = replaceRecursive(transl[key]) | ||||||
|  | @ -229,12 +273,7 @@ class ExpandGroupRewrite extends Conversion<{ | ||||||
|             return transl |             return transl | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const orig = tr; |         return replaceRecursive(tr) | ||||||
|         tr = replaceRecursive(tr) |  | ||||||
| 
 |  | ||||||
|         tr.id = target + "-" + orig.id |  | ||||||
|         tr.group = target |  | ||||||
|         return tr |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -225,9 +225,9 @@ export interface LayerConfigJson { | ||||||
|      */ |      */ | ||||||
|     tagRenderings?: (string | { builtin: string, override: any } | TagRenderingConfigJson | { |     tagRenderings?: (string | { builtin: string, override: any } | TagRenderingConfigJson | { | ||||||
|         rewrite: { |         rewrite: { | ||||||
|             sourceString: string, |             sourceString: string[], | ||||||
|             into: string[] |             into: (string | any)[][] | ||||||
|         }[], |         }, | ||||||
|         renderings: (string | { builtin: string, override: any } | TagRenderingConfigJson)[] |         renderings: (string | { builtin: string, override: any } | TagRenderingConfigJson)[] | ||||||
|     }) [], |     }) [], | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -106,6 +106,10 @@ export interface TagRenderingConfigJson { | ||||||
|          * If not known yet, the user will be presented with `then` as an option |          * If not known yet, the user will be presented with `then` as an option | ||||||
|          */ |          */ | ||||||
|         then: string | any, |         then: string | any, | ||||||
|  |         /** | ||||||
|  |          * An icon supporting this mapping; typically shown pretty small | ||||||
|  |          */ | ||||||
|  |         icon?: string | ||||||
|         /** |         /** | ||||||
|          * In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation). |          * In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation). | ||||||
|          * |          * | ||||||
|  |  | ||||||
|  | @ -41,7 +41,8 @@ export default class TagRenderingConfig { | ||||||
|     readonly mappings?: { |     readonly mappings?: { | ||||||
|         readonly if: TagsFilter, |         readonly if: TagsFilter, | ||||||
|         readonly ifnot?: TagsFilter, |         readonly ifnot?: TagsFilter, | ||||||
|         readonly then: Translation |         readonly then: Translation, | ||||||
|  |         readonly icon: string, | ||||||
|         readonly hideInAnswer: boolean | TagsFilter |         readonly hideInAnswer: boolean | TagsFilter | ||||||
|         readonly addExtraTags: Tag[] |         readonly addExtraTags: Tag[] | ||||||
|     }[] |     }[] | ||||||
|  | @ -163,11 +164,16 @@ export default class TagRenderingConfig { | ||||||
|                 } else if (mapping.hideInAnswer !== undefined) { |                 } else if (mapping.hideInAnswer !== undefined) { | ||||||
|                     hideInAnswer = TagUtils.Tag(mapping.hideInAnswer, `${context}.mapping[${i}].hideInAnswer`); |                     hideInAnswer = TagUtils.Tag(mapping.hideInAnswer, `${context}.mapping[${i}].hideInAnswer`); | ||||||
|                 } |                 } | ||||||
|  |                 let icon = undefined; | ||||||
|  |                 if(mapping.icon !== ""){ | ||||||
|  |                     icon = mapping.icon | ||||||
|  |                 } | ||||||
|                 const mp = { |                 const mp = { | ||||||
|                     if: TagUtils.Tag(mapping.if, `${ctx}.if`), |                     if: TagUtils.Tag(mapping.if, `${ctx}.if`), | ||||||
|                     ifnot: (mapping.ifnot !== undefined ? TagUtils.Tag(mapping.ifnot, `${ctx}.ifnot`) : undefined), |                     ifnot: (mapping.ifnot !== undefined ? TagUtils.Tag(mapping.ifnot, `${ctx}.ifnot`) : undefined), | ||||||
|                     then: Translations.T(mapping.then, `${ctx}.then`), |                     then: Translations.T(mapping.then, `${ctx}.then`), | ||||||
|                     hideInAnswer: hideInAnswer, |                     hideInAnswer, | ||||||
|  |                     icon, | ||||||
|                     addExtraTags: (mapping.addExtraTags ?? []).map((str, j) => TagUtils.SimpleTag(str, `${ctx}.addExtraTags[${j}]`)) |                     addExtraTags: (mapping.addExtraTags ?? []).map((str, j) => TagUtils.SimpleTag(str, `${ctx}.addExtraTags[${j}]`)) | ||||||
|                 }; |                 }; | ||||||
|                 if (this.question) { |                 if (this.question) { | ||||||
|  | @ -329,18 +335,18 @@ export default class TagRenderingConfig { | ||||||
|      * @param tags |      * @param tags | ||||||
|      * @constructor |      * @constructor | ||||||
|      */ |      */ | ||||||
|     public GetRenderValues(tags: any): Translation[] { |     public GetRenderValues(tags: any): {then: Translation, icon?: string}[] { | ||||||
|         if (!this.multiAnswer) { |         if (!this.multiAnswer) { | ||||||
|             return [this.GetRenderValue(tags)] |             return [this.GetRenderValueWithImage(tags)] | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // A flag to check that the freeform key isn't matched multiple times 
 |         // A flag to check that the freeform key isn't matched multiple times 
 | ||||||
|         // If it is undefined, it is "used" already, or at least we don't have to check for it anymore
 |         // If it is undefined, it is "used" already, or at least we don't have to check for it anymore
 | ||||||
|         let freeformKeyUsed = this.freeform?.key === undefined; |         let freeformKeyUsed = this.freeform?.key === undefined; | ||||||
|         // We run over all the mappings first, to check if the mapping matches
 |         // We run over all the mappings first, to check if the mapping matches
 | ||||||
|         const applicableMappings: Translation[] = Utils.NoNull((this.mappings ?? [])?.map(mapping => { |         const applicableMappings: {then: Translation, img?: string}[] = Utils.NoNull((this.mappings ?? [])?.map(mapping => { | ||||||
|             if (mapping.if === undefined) { |             if (mapping.if === undefined) { | ||||||
|                 return mapping.then; |                 return mapping; | ||||||
|             } |             } | ||||||
|             if (TagUtils.MatchesMultiAnswer(mapping.if, tags)) { |             if (TagUtils.MatchesMultiAnswer(mapping.if, tags)) { | ||||||
|                 if (!freeformKeyUsed) { |                 if (!freeformKeyUsed) { | ||||||
|  | @ -349,7 +355,7 @@ export default class TagRenderingConfig { | ||||||
|                         freeformKeyUsed = true; |                         freeformKeyUsed = true; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 return mapping.then; |                 return mapping; | ||||||
|             } |             } | ||||||
|             return undefined; |             return undefined; | ||||||
|         })) |         })) | ||||||
|  | @ -357,43 +363,42 @@ export default class TagRenderingConfig { | ||||||
| 
 | 
 | ||||||
|         if (!freeformKeyUsed |         if (!freeformKeyUsed | ||||||
|             && tags[this.freeform.key] !== undefined) { |             && tags[this.freeform.key] !== undefined) { | ||||||
|             applicableMappings.push(this.render) |             applicableMappings.push({then: this.render}) | ||||||
|         } |         } | ||||||
|         return applicableMappings |         return applicableMappings | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public GetRenderValue(tags: any, defltValue: any = undefined): Translation { | ||||||
|  |         return this.GetRenderValueWithImage(tags, defltValue).then | ||||||
|  |     } | ||||||
|     /** |     /** | ||||||
|      * Gets the correct rendering value (or undefined if not known) |      * Gets the correct rendering value (or undefined if not known) | ||||||
|      * Not compatible with multiAnswer - use GetRenderValueS instead in that case |      * Not compatible with multiAnswer - use GetRenderValueS instead in that case | ||||||
|      * @constructor |      * @constructor | ||||||
|      */ |      */ | ||||||
|     public GetRenderValue(tags: any, defltValue: any = undefined): Translation { |     public GetRenderValueWithImage(tags: any, defltValue: any = undefined): { then: Translation, icon?: string } { | ||||||
|         if (this.mappings !== undefined && !this.multiAnswer) { |         if (this.mappings !== undefined && !this.multiAnswer) { | ||||||
|             for (const mapping of this.mappings) { |             for (const mapping of this.mappings) { | ||||||
|                 if (mapping.if === undefined) { |                 if (mapping.if === undefined) { | ||||||
|                     return mapping.then; |                     return mapping; | ||||||
|                 } |                 } | ||||||
|                 if (mapping.if.matchesProperties(tags)) { |                 if (mapping.if.matchesProperties(tags)) { | ||||||
|                     if (this.id === "uk_addresses_placename") { |                     if (this.id === "uk_addresses_placename") { | ||||||
|                         console.log("Matched", mapping.if, "with ", tags["addr:place"]) |                         console.log("Matched", mapping.if, "with ", tags["addr:place"]) | ||||||
|                     } |                     } | ||||||
|                     return mapping.then; |                     return mapping; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (this.id === "questions") { |         if (this.id === "questions" || | ||||||
|             return this.render |             this.freeform?.key === undefined || | ||||||
|  |             tags[this.freeform.key] !== undefined | ||||||
|  |         ) { | ||||||
|  |             return {then: this.render} | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (this.freeform?.key === undefined) { |         return {then: defltValue}; | ||||||
|             return this.render; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (tags[this.freeform.key] !== undefined) { |  | ||||||
|             return this.render; |  | ||||||
|         } |  | ||||||
|         return defltValue; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  |  | ||||||
|  | @ -26,7 +26,6 @@ export default class TableOfContents extends Combine { | ||||||
|         let els: { level: number, content: BaseUIElement }[] = [] |         let els: { level: number, content: BaseUIElement }[] = [] | ||||||
|         for (const title of titles) { |         for (const title of titles) { | ||||||
|             let content: BaseUIElement |             let content: BaseUIElement | ||||||
|             console.log("Constructing content for ", title) |  | ||||||
|             if (title.title instanceof Translation) { |             if (title.title instanceof Translation) { | ||||||
|                 content = title.title.Clone() |                 content = title.title.Clone() | ||||||
|             } else if (title.title instanceof FixedUiElement) { |             } else if (title.title instanceof FixedUiElement) { | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ import {VariableUiElement} from "../Base/VariableUIElement"; | ||||||
| import List from "../Base/List"; | import List from "../Base/List"; | ||||||
| import {SubstitutedTranslation} from "../SubstitutedTranslation"; | import {SubstitutedTranslation} from "../SubstitutedTranslation"; | ||||||
| import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"; | import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"; | ||||||
|  | import Combine from "../Base/Combine"; | ||||||
|  | import Img from "../Base/Img"; | ||||||
| 
 | 
 | ||||||
| /*** | /*** | ||||||
|  * Displays the correct value for a known tagrendering |  * Displays the correct value for a known tagrendering | ||||||
|  | @ -38,11 +40,17 @@ export default class TagRenderingAnswer extends VariableUiElement { | ||||||
|                 return undefined; |                 return undefined; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const valuesToRender: BaseUIElement[] = trs.map(tr => new SubstitutedTranslation(tr, tagsSource, state, options?.specialViz)) |             const valuesToRender: BaseUIElement[] = trs.map(tr => { | ||||||
|  |                 const text = new SubstitutedTranslation(tr.then, tagsSource, state, options?.specialViz); | ||||||
|  |                 if(tr.icon === undefined){ | ||||||
|  |                     return text | ||||||
|  |                 } | ||||||
|  |                 return new Combine([new Img(tr.icon).SetClass("w-6 max-h-6 pr-2"), text]).SetClass("flex") | ||||||
|  |             }) | ||||||
|             if (valuesToRender.length === 1) { |             if (valuesToRender.length === 1) { | ||||||
|                 return valuesToRender[0]; |                 return valuesToRender[0]; | ||||||
|             } else if (valuesToRender.length > 1) { |             } else if (valuesToRender.length > 1) { | ||||||
|                 return new List(valuesToRender) |                 return new Combine(valuesToRender).SetClass("flex flex-col") | ||||||
|             } |             } | ||||||
|             return undefined; |             return undefined; | ||||||
|         }).map((element: BaseUIElement) => element?.SetClass(contentClasses)?.SetStyle(contentStyle))) |         }).map((element: BaseUIElement) => element?.SetClass(contentClasses)?.SetStyle(contentStyle))) | ||||||
|  |  | ||||||
|  | @ -26,6 +26,10 @@ import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"; | ||||||
| import {Unit} from "../../Models/Unit"; | import {Unit} from "../../Models/Unit"; | ||||||
| import VariableInputElement from "../Input/VariableInputElement"; | import VariableInputElement from "../Input/VariableInputElement"; | ||||||
| import Toggle from "../Input/Toggle"; | import Toggle from "../Input/Toggle"; | ||||||
|  | import Img from "../Base/Img"; | ||||||
|  | import {flattenEach, tag} from "@turf/turf"; | ||||||
|  | import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline"; | ||||||
|  | import FeaturePipelineState from "../../Logic/State/FeaturePipelineState"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Shows the question element. |  * Shows the question element. | ||||||
|  | @ -343,7 +347,8 @@ export default class TagRenderingQuestion extends Combine { | ||||||
|         mapping: { |         mapping: { | ||||||
|             if: TagsFilter, |             if: TagsFilter, | ||||||
|             then: Translation, |             then: Translation, | ||||||
|             addExtraTags: Tag[] |             addExtraTags: Tag[], | ||||||
|  |             img?: string | ||||||
|         }, ifNot?: TagsFilter[]): InputElement<TagsFilter> { |         }, ifNot?: TagsFilter[]): InputElement<TagsFilter> { | ||||||
| 
 | 
 | ||||||
|         let tagging: TagsFilter = mapping.if; |         let tagging: TagsFilter = mapping.if; | ||||||
|  | @ -354,12 +359,24 @@ export default class TagRenderingQuestion extends Combine { | ||||||
|             tagging = new And([tagging, ...mapping.addExtraTags]) |             tagging = new And([tagging, ...mapping.addExtraTags]) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |       | ||||||
|         return new FixedInputElement( |         return new FixedInputElement( | ||||||
|             new SubstitutedTranslation(mapping.then, tagsSource, state), |             TagRenderingQuestion.GenerateMappingContent(mapping, tagsSource, state)  , | ||||||
|             tagging, |             tagging, | ||||||
|             (t0, t1) => t1.isEquivalent(t0)); |             (t0, t1) => t1.isEquivalent(t0)); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     private static GenerateMappingContent(  mapping: { | ||||||
|  |         then: Translation, | ||||||
|  |         icon?: string | ||||||
|  |     }, tagsSource: UIEventSource<any>, state: FeaturePipelineState): BaseUIElement{ | ||||||
|  |         const text =  new SubstitutedTranslation(mapping.then, tagsSource, state) | ||||||
|  |         if (mapping.icon === undefined) { | ||||||
|  |             return text; | ||||||
|  |         } | ||||||
|  |         return new Combine([new Img(mapping.icon).SetClass("w-6 max-h-6 pr-2"), text]).SetClass("flex") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private static GenerateFreeform(state, configuration: TagRenderingConfig, applicableUnit: Unit, tags: UIEventSource<any>): InputElement<TagsFilter> { |     private static GenerateFreeform(state, configuration: TagRenderingConfig, applicableUnit: Unit, tags: UIEventSource<any>): InputElement<TagsFilter> { | ||||||
|         const freeform = configuration.freeform; |         const freeform = configuration.freeform; | ||||||
|         if (freeform === undefined) { |         if (freeform === undefined) { | ||||||
|  |  | ||||||
|  | @ -142,6 +142,33 @@ export class Translation extends BaseUIElement { | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      *  | ||||||
|  |      * Given a translation such as `{en: "How much of bicycle_types are rented here}` (which is this translation) | ||||||
|  |      * and a translation object `{ en: "electrical bikes" }`, plus the translation specification `bicycle_types`, will return  | ||||||
|  |      * a new translation: | ||||||
|  |      * `{en: "How much electrical bikes are rented here?"}` | ||||||
|  |      *  | ||||||
|  |      * @param translationObject | ||||||
|  |      * @param stringToReplace | ||||||
|  |      * @constructor | ||||||
|  |      */ | ||||||
|  |     public Fuse(translationObject: Translation, stringToReplace: string): Translation{ | ||||||
|  |         const translations = this.translations | ||||||
|  |         const newTranslations = {} | ||||||
|  |         for (const lang in translations) { | ||||||
|  |             const target = translationObject.textFor(lang) | ||||||
|  |             if(target === undefined){ | ||||||
|  |                 continue | ||||||
|  |             } | ||||||
|  |             if(typeof target !== "string"){ | ||||||
|  |                 throw "Invalid object in Translation.fuse: translationObject['"+lang+"'] is not a string, it is: "+JSON.stringify(target) | ||||||
|  |             } | ||||||
|  |             newTranslations[lang] = this.translations[lang].replaceAll(stringToReplace, target) | ||||||
|  |         } | ||||||
|  |         return new Translation(newTranslations) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public replace(a: string, b: string) { |     public replace(a: string, b: string) { | ||||||
|         if (a.startsWith("{") && a.endsWith("}")) { |         if (a.startsWith("{") && a.endsWith("}")) { | ||||||
|             a = a.substr(1, a.length - 2); |             a = a.substr(1, a.length - 2); | ||||||
|  |  | ||||||
|  | @ -2,11 +2,11 @@ import {FixedUiElement} from "../Base/FixedUiElement"; | ||||||
| import AllTranslationAssets from "../../AllTranslationAssets"; | import AllTranslationAssets from "../../AllTranslationAssets"; | ||||||
| import {Translation} from "./Translation"; | import {Translation} from "./Translation"; | ||||||
| import BaseUIElement from "../BaseUIElement"; | import BaseUIElement from "../BaseUIElement"; | ||||||
| 
 | import * as known_languages from "../../assets/generated/used_languages.json" | ||||||
| export default class Translations { | export default class Translations { | ||||||
| 
 | 
 | ||||||
|     static t = AllTranslationAssets.t; |     static t = AllTranslationAssets.t; | ||||||
| 
 |     private static knownLanguages = new Set(known_languages.languages) | ||||||
|     constructor() { |     constructor() { | ||||||
|         throw "Translations is static. If you want to intitialize a new translation, use the singular form" |         throw "Translations is static. If you want to intitialize a new translation, use the singular form" | ||||||
|     } |     } | ||||||
|  | @ -89,4 +89,11 @@ export default class Translations { | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     static isProbablyATranslation(transl: any) { | ||||||
|  |         if(typeof transl !== "object"){ | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // is a weird key found?
 | ||||||
|  |         return !Object.keys(transl).some(key => !this.knownLanguages.has(key)) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2975,32 +2975,14 @@ | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       "id": "payment-options", |       "id": "payment-options", | ||||||
|       "builtin": "payment-options", |       "builtin": "payment-options-advanced", | ||||||
|       "override": { |       "override": { | ||||||
|         "condition": { |         "condition": { | ||||||
|           "or": [ |           "or": [ | ||||||
|             "fee=yes", |             "fee=yes", | ||||||
|             "charge~*" |             "charge~*" | ||||||
|           ] |           ] | ||||||
|         }, |         } | ||||||
|         "mappings+": [ |  | ||||||
|           { |  | ||||||
|             "if": "payment:app=yes", |  | ||||||
|             "ifnot": "payment:app=no", |  | ||||||
|             "then": { |  | ||||||
|               "en": "Payment is done using a dedicated app", |  | ||||||
|               "nl": "Betalen via een app van het netwerk" |  | ||||||
|             } |  | ||||||
|           }, |  | ||||||
|           { |  | ||||||
|             "if": "payment:membership_card=yes", |  | ||||||
|             "ifnot": "payment:membership_card=no", |  | ||||||
|             "then": { |  | ||||||
|               "en": "Payment is done using a membership card", |  | ||||||
|               "nl": "Betalen via een lidkaart van het netwerk" |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         ] |  | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|  |  | ||||||
|  | @ -260,32 +260,14 @@ | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       "id": "payment-options", |       "id": "payment-options", | ||||||
|       "builtin": "payment-options", |       "builtin": "payment-options-advanced", | ||||||
|       "override": { |       "override": { | ||||||
|         "condition": { |         "condition": { | ||||||
|           "or": [ |           "or": [ | ||||||
|             "fee=yes", |             "fee=yes", | ||||||
|             "charge~*" |             "charge~*" | ||||||
|           ] |           ] | ||||||
|         }, |         } | ||||||
|         "mappings+": [ |  | ||||||
|           { |  | ||||||
|             "if": "payment:app=yes", |  | ||||||
|             "ifnot": "payment:app=no", |  | ||||||
|             "then": { |  | ||||||
|               "en": "Payment is done using a dedicated app", |  | ||||||
|               "nl": "Betalen via een app van het netwerk" |  | ||||||
|             } |  | ||||||
|           }, |  | ||||||
|           { |  | ||||||
|             "if": "payment:membership_card=yes", |  | ||||||
|             "ifnot": "payment:membership_card=no", |  | ||||||
|             "then": { |  | ||||||
|               "en": "Payment is done using a membership card", |  | ||||||
|               "nl": "Betalen via een lidkaart van het netwerk" |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         ] |  | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|  |  | ||||||
|  | @ -31,6 +31,7 @@ | ||||||
|     "de": "Die Ebene zeigt Picknicktische an" |     "de": "Die Ebene zeigt Picknicktische an" | ||||||
|   }, |   }, | ||||||
|   "tagRenderings": [ |   "tagRenderings": [ | ||||||
|  |     "images", | ||||||
|     { |     { | ||||||
|       "question": { |       "question": { | ||||||
|         "en": "What material is this picnic table made of?", |         "en": "What material is this picnic table made of?", | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								assets/svg/cash.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								assets/svg/cash.svg
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| After Width: | Height: | Size: 6.3 KiB | 
|  | @ -141,6 +141,16 @@ | ||||||
|       "https://commons.wikimedia.org/wiki/File:Camera_font_awesome.svg" |       "https://commons.wikimedia.org/wiki/File:Camera_font_awesome.svg" | ||||||
|     ] |     ] | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "path": "cash.svg", | ||||||
|  |     "license": "CC-BY 3.0", | ||||||
|  |     "authors": [ | ||||||
|  |       "Online Web Fonts" | ||||||
|  |     ], | ||||||
|  |     "sources": [ | ||||||
|  |       "https://www.onlinewebfonts.com/icon/464494" | ||||||
|  |     ] | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "path": "checkbox-empty.svg", |     "path": "checkbox-empty.svg", | ||||||
|     "license": "CC0", |     "license": "CC0", | ||||||
|  | @ -1109,6 +1119,16 @@ | ||||||
|     "authors": [], |     "authors": [], | ||||||
|     "sources": [] |     "sources": [] | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "path": "smartphone.svg", | ||||||
|  |     "license": "CC-BY 3.0", | ||||||
|  |     "authors": [ | ||||||
|  |       "To Uyen" | ||||||
|  |     ], | ||||||
|  |     "sources": [ | ||||||
|  |       "https://commons.wikimedia.org/wiki/File:Smartphone_icon_-_Noun_Project_283536.svg" | ||||||
|  |     ] | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "path": "speech_bubble.svg", |     "path": "speech_bubble.svg", | ||||||
|     "license": "CC-BY 4.0", |     "license": "CC-BY 4.0", | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								assets/svg/smartphone.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								assets/svg/smartphone.svg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"> | ||||||
|  | <path d="m33.975 95h32.05c5.565 0 10.08-4.279 10.08-9.569v-70.855c0-5.285-4.513-9.576-10.07-9.576h-32.05c-5.564 0-10.08 4.291-10.08 9.576v70.854c0 5.288 4.513 9.57 10.08 9.57m16.03-3.257c-2.493 0-4.506-2.02-4.506-4.498 0-2.489 2.01-4.502 4.506-4.502 2.487 0 4.494 2.01 4.494 4.502 0 2.481-2.01 4.498-4.494 4.498m-6.868-80.911h13.727c.556 0 1.01.383 1.01.852 0 .471-.452.854-1.01.854h-13.727c-.55 0-1.01-.383-1.01-.854-.0001-.469.454-.852 1.01-.852m-15.289 10.798c0-.794.675-1.438 1.508-1.438h41.29c.835 0 1.507.641 1.507 1.438v56.49c0 .791-.672 1.433-1.507 1.433h-41.29c-.833 0-1.508-.642-1.508-1.433v-56.49"/> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 702 B | 
|  | @ -558,6 +558,7 @@ | ||||||
|       { |       { | ||||||
|         "if": "payment:cash=yes", |         "if": "payment:cash=yes", | ||||||
|         "ifnot": "payment:cash=no", |         "ifnot": "payment:cash=no", | ||||||
|  |         "icon": "./assets/svg/cash.svg", | ||||||
|         "then": { |         "then": { | ||||||
|           "en": "Cash is accepted here", |           "en": "Cash is accepted here", | ||||||
|           "nl": "Cash geld wordt hier aanvaard", |           "nl": "Cash geld wordt hier aanvaard", | ||||||
|  | @ -579,6 +580,7 @@ | ||||||
|       { |       { | ||||||
|         "if": "payment:cards=yes", |         "if": "payment:cards=yes", | ||||||
|         "ifnot": "payment:cards=no", |         "ifnot": "payment:cards=no", | ||||||
|  |         "icon": "./assets/svg/payment_card.svg", | ||||||
|         "then": { |         "then": { | ||||||
|           "en": "Payment cards are accepted here", |           "en": "Payment cards are accepted here", | ||||||
|           "nl": "Betalen met bankkaarten kan hier", |           "nl": "Betalen met bankkaarten kan hier", | ||||||
|  | @ -599,6 +601,31 @@ | ||||||
|       } |       } | ||||||
|     ] |     ] | ||||||
|   }, |   }, | ||||||
|  |   "payment-options-advanced": { | ||||||
|  |     "builtin": "payment-options", | ||||||
|  |     "override": { | ||||||
|  |       "mappings+": [ | ||||||
|  |         { | ||||||
|  |           "if": "payment:app=yes", | ||||||
|  |           "ifnot": "payment:app=no", | ||||||
|  |           "icon": "./assets/svg/smartphone.svg", | ||||||
|  |           "then": { | ||||||
|  |             "en": "Payment is done using a dedicated app", | ||||||
|  |             "nl": "Betalen via een app van het netwerk" | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "if": "payment:membership_card=yes", | ||||||
|  |           "ifnot": "payment:membership_card=no", | ||||||
|  |           "icon": "./assets/svg/nfc_card.svg", | ||||||
|  |           "then": { | ||||||
|  |             "en": "Payment is done using a membership card", | ||||||
|  |             "nl": "Betalen via een lidkaart van het netwerk" | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       ] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|   "last_edit": { |   "last_edit": { | ||||||
|     "#": "Gives some metainfo about the last edit and who did edit it - rendering only", |     "#": "Gives some metainfo about the last edit and who did edit it - rendering only", | ||||||
|     "condition": "_last_edit:contributor~*", |     "condition": "_last_edit:contributor~*", | ||||||
|  |  | ||||||
|  | @ -171,19 +171,36 @@ | ||||||
|             { |             { | ||||||
|               "if": "rental=city_bike", |               "if": "rental=city_bike", | ||||||
|               "then": { |               "then": { | ||||||
|                 "en": "Normal city bikes can be rented here" |                 "en": "Normal city bikes can be rented here", | ||||||
|  |                 "nl": "Gewone stadsfietsen kunnen hier gehuurd worden" | ||||||
|               } |               } | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|               "if": "rental=ebike", |               "if": "rental=ebike", | ||||||
|               "then": { |               "then": { | ||||||
|                 "en": "Electrical bikes can be rented here" |                 "en": "Electrical bikes can be rented here", | ||||||
|  |                 "nl": "Elektrische fietsen kunnen hier gehuurd worden" | ||||||
|               } |               } | ||||||
|             }, |             }, | ||||||
|             { |             { | ||||||
|               "if": "rental=bmx", |               "if": "rental=bmx", | ||||||
|               "then": { |               "then": { | ||||||
|                 "en": "BMX bikes can be rented here" |                 "en": "BMX bikes can be rented here", | ||||||
|  |                 "nl": "BMX-fietsen kunnen hier gehuurd worden" | ||||||
|  |               } | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |               "if": "rental=mtb", | ||||||
|  |               "then": { | ||||||
|  |                 "en": "Mountainbikes can be rented here", | ||||||
|  |                 "nl": "Mountainbikes kunnen hier gehuurd worden" | ||||||
|  |               } | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |               "if": "rental=kid_bike", | ||||||
|  |               "then": { | ||||||
|  |                 "en": "Bikes for childs can be rented here", | ||||||
|  |                 "nl": "Kinderfietsen kunnen hier gehuurd worden" | ||||||
|               } |               } | ||||||
|             } |             } | ||||||
|           ] |           ] | ||||||
|  | @ -192,26 +209,70 @@ | ||||||
|           "rewrite": { |           "rewrite": { | ||||||
|             "sourceString": [ |             "sourceString": [ | ||||||
|               "bicycle_type", |               "bicycle_type", | ||||||
|               "bicycle_types" |               "type_plural" | ||||||
|             ], |             ], | ||||||
|             "into": [ |             "into": [ | ||||||
|               [ |               [ | ||||||
|                 "city_bike", |                 "city_bike", | ||||||
|                 "city bikes" |                 { | ||||||
|  |                   "en": "city bikes", | ||||||
|  |                   "nl": "Stadsfietsen" | ||||||
|  |                 } | ||||||
|               ], |               ], | ||||||
|               [ |               [ | ||||||
|                 "ebike", |                 "ebike", | ||||||
|                 "electrical bikes" |                 { | ||||||
|  |                   "en": "electrical bikes", | ||||||
|  |                   "nl": "elektrische fietsen" | ||||||
|  |                 } | ||||||
|               ], |               ], | ||||||
|               "bmx" |               [ | ||||||
|  |                 "kid_bike", | ||||||
|  |                 { | ||||||
|  |                   "en": "bikes for children", | ||||||
|  |                   "nl": "Kinderfietsen" | ||||||
|  |                 } | ||||||
|  |               ], | ||||||
|  |               [ | ||||||
|  |                 "bmx", | ||||||
|  |                 { | ||||||
|  |                   "en": "BMX bikes", | ||||||
|  |                   "nl": "BMX-fietsen" | ||||||
|  |                 } | ||||||
|  |               ], | ||||||
|  |               [ | ||||||
|  |                 "mtb", | ||||||
|  |                 { | ||||||
|  |                   "en": "mountainbike", | ||||||
|  |                   "nl": "mountainbike" | ||||||
|  |                 } | ||||||
|  |               ], | ||||||
|  |               [ | ||||||
|  |                 "bicycle_pannier", | ||||||
|  |                 { | ||||||
|  |                   "en": "bicycle panniers", | ||||||
|  |                   "nl": "Fietstassen" | ||||||
|  |                 } | ||||||
|  |               ] | ||||||
|             ] |             ] | ||||||
|           }, |           }, | ||||||
|           "renderings": [ |           "renderings": [ | ||||||
|             { |             { | ||||||
|  |               "id": "rental-capacity-bicycle-type", | ||||||
|  |               "group": "", | ||||||
|               "question": { |               "question": { | ||||||
|                 "en": "How much bicycle_type ", |                 "en": "How much type_plural can be rented here? ", | ||||||
|                 "nl": "Hoeveel " |                 "nl": "Hoeveel type_plural kunnen hier uitgeleend worden?" | ||||||
|               } |               }, | ||||||
|  |               "render": { | ||||||
|  |                 "en": "{capacity:bicycle_type} type_plural can be rented here", | ||||||
|  |                 "nl": "{capacity:bicycle_type} type_plural kunnen hier uitgeleend worden" | ||||||
|  |               }, | ||||||
|  |               "freeform": { | ||||||
|  |                 "key": "capacity:bicycle_type", | ||||||
|  |                 "type": "pnat" | ||||||
|  |               }, | ||||||
|  |               "condition": "rental~.*bicycle_type.*" | ||||||
|             } |             } | ||||||
|           ] |           ] | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -95,6 +95,10 @@ | ||||||
|                 "if": "theme=benches", |                 "if": "theme=benches", | ||||||
|                 "then": "./assets/themes/benches/bench_poi.svg" |                 "then": "./assets/themes/benches/bench_poi.svg" | ||||||
|               }, |               }, | ||||||
|  |               { | ||||||
|  |                 "if": "theme=bicycle_rental", | ||||||
|  |                 "then": "./assets/themes/bicycle_rental/logo.svg" | ||||||
|  |               }, | ||||||
|               { |               { | ||||||
|                 "if": "theme=bicyclelib", |                 "if": "theme=bicyclelib", | ||||||
|                 "then": "./assets/themes/bicyclelib/logo.svg" |                 "then": "./assets/themes/bicyclelib/logo.svg" | ||||||
|  |  | ||||||
|  | @ -62,10 +62,16 @@ | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|           "rewrite": { |           "rewrite": { | ||||||
|             "sourceString": "left|right", |             "sourceString": [ | ||||||
|  |               "left|right" | ||||||
|  |             ], | ||||||
|             "into": [ |             "into": [ | ||||||
|               "left", |               [ | ||||||
|               "right" |                 "left" | ||||||
|  |               ], | ||||||
|  |               [ | ||||||
|  |                 "right" | ||||||
|  |               ] | ||||||
|             ] |             ] | ||||||
|           }, |           }, | ||||||
|           "renderings": [ |           "renderings": [ | ||||||
|  |  | ||||||
|  | @ -14,6 +14,8 @@ import Title from "../UI/Base/Title"; | ||||||
| import Minimap from "../UI/Base/Minimap"; | import Minimap from "../UI/Base/Minimap"; | ||||||
| import {QueryParameters} from "../Logic/Web/QueryParameters"; | import {QueryParameters} from "../Logic/Web/QueryParameters"; | ||||||
| import QueryParameterDocumentation from "../UI/QueryParameterDocumentation"; | import QueryParameterDocumentation from "../UI/QueryParameterDocumentation"; | ||||||
|  | import ScriptUtils from "./ScriptUtils"; | ||||||
|  | import List from "../UI/Base/List"; | ||||||
| 
 | 
 | ||||||
| function WriteFile(filename, html: BaseUIElement, autogenSource: string[]): void { | function WriteFile(filename, html: BaseUIElement, autogenSource: string[]): void { | ||||||
| 
 | 
 | ||||||
|  | @ -50,6 +52,53 @@ WriteFile("./Docs/CalculatedTags.md", new Combine([new Title("Metatags", 1), | ||||||
| WriteFile("./Docs/SpecialInputElements.md", ValidatedTextField.HelpText(), ["ValidatedTextField.ts"]); | WriteFile("./Docs/SpecialInputElements.md", ValidatedTextField.HelpText(), ["ValidatedTextField.ts"]); | ||||||
| WriteFile("./Docs/BuiltinLayers.md", AllKnownLayouts.GenLayerOverviewText(), ["AllKnownLayers.ts"]) | WriteFile("./Docs/BuiltinLayers.md", AllKnownLayouts.GenLayerOverviewText(), ["AllKnownLayers.ts"]) | ||||||
| 
 | 
 | ||||||
|  | { | ||||||
|  |    var layers = ScriptUtils.getLayerFiles().map(f => f.parsed) | ||||||
|  |     var builtinsPerLayer= new Map<string, string[]>(); | ||||||
|  |     var layersUsingBuiltin = new Map<string /* Builtin */, string[]>(); | ||||||
|  |     for (const layer of layers) { | ||||||
|  |         if(layer.tagRenderings === undefined){ | ||||||
|  |             continue | ||||||
|  |         } | ||||||
|  |         const usedBuiltins : string[] = [] | ||||||
|  |         for (const tagRendering of layer.tagRenderings) { | ||||||
|  |             if(typeof tagRendering === "string"){ | ||||||
|  |                 usedBuiltins.push(tagRendering) | ||||||
|  |                 continue | ||||||
|  |             } | ||||||
|  |             if(tagRendering["builtin"] !== undefined){ | ||||||
|  |                 const builtins = tagRendering["builtin"] | ||||||
|  |                 if(typeof builtins === "string"){ | ||||||
|  |                     usedBuiltins.push(builtins) | ||||||
|  |                 }else{ | ||||||
|  |                     usedBuiltins.push(...builtins) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         for (const usedBuiltin of usedBuiltins) { | ||||||
|  |             var using = layersUsingBuiltin.get(usedBuiltin) | ||||||
|  |             if(using === undefined){ | ||||||
|  |                 layersUsingBuiltin.set(usedBuiltin, [layer.id]) | ||||||
|  |             }else{ | ||||||
|  |                 using.push(layer.id) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         builtinsPerLayer.set(layer.id, usedBuiltins) | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     const docs = new Combine([ | ||||||
|  |         new Title("Index of builtin TagRendering" ,1), | ||||||
|  |         new Title("Existing builtin tagrenderings", 2), | ||||||
|  |         ... Array.from(layersUsingBuiltin.entries()).map(([builtin, usedByLayers]) =>  | ||||||
|  |                 new Combine([ | ||||||
|  |                     new Title(builtin), | ||||||
|  |                     new List(usedByLayers) | ||||||
|  |                 ]).SetClass("flex flex-col") | ||||||
|  |             ) | ||||||
|  |     ]).SetClass("flex flex-col") | ||||||
|  |     WriteFile("./Docs/BuiltinIndex.md", docs, ["assets/layers/*.json"]) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| Minimap.createMiniMap = _ => { | Minimap.createMiniMap = _ => { | ||||||
|     console.log("Not creating a minimap, it is disabled"); |     console.log("Not creating a minimap, it is disabled"); | ||||||
|  | @ -58,12 +107,12 @@ Minimap.createMiniMap = _ => { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| const dummyLayout = new LayoutConfig({ | const dummyLayout = new LayoutConfig({ | ||||||
|     language: ["en"], |  | ||||||
|     id: ">theme<", |     id: ">theme<", | ||||||
|     maintainer: "pietervdvn", |     maintainer: "pietervdvn", | ||||||
|     version: "0", |     version: "0", | ||||||
|     title: "<theme>", |     title: {en:"<theme>"}, | ||||||
|     description: "A theme to generate docs with", |     description: "A theme to generate docs with", | ||||||
|  |     socialImage: "./assets/SocialImage.png", | ||||||
|     startLat: 0, |     startLat: 0, | ||||||
|     startLon: 0, |     startLon: 0, | ||||||
|     startZoom: 0, |     startZoom: 0, | ||||||
|  |  | ||||||
|  | @ -228,7 +228,7 @@ function compileTranslationsFromWeblate() { | ||||||
|  * @param objects |  * @param objects | ||||||
|  * @param target |  * @param target | ||||||
|  */ |  */ | ||||||
| function generateTranslationsObjectFrom(objects: { path: string, parsed: { id: string } }[], target: string) { | function generateTranslationsObjectFrom(objects: { path: string, parsed: { id: string } }[], target: string): string[] { | ||||||
|     const tr = new TranslationPart(); |     const tr = new TranslationPart(); | ||||||
| 
 | 
 | ||||||
|     for (const layerFile of objects) { |     for (const layerFile of objects) { | ||||||
|  | @ -257,6 +257,7 @@ function generateTranslationsObjectFrom(objects: { path: string, parsed: { id: s | ||||||
| 
 | 
 | ||||||
|         writeFileSync(`langs/${target}/${lang}.json`, json) |         writeFileSync(`langs/${target}/${lang}.json`, json) | ||||||
|     } |     } | ||||||
|  |     return langs | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -398,11 +399,14 @@ if (!themeOverwritesWeblate) { | ||||||
| } else { | } else { | ||||||
|     console.log("Ignore weblate") |     console.log("Ignore weblate") | ||||||
| } | } | ||||||
| generateTranslationsObjectFrom(ScriptUtils.getLayerFiles(), "layers") |  | ||||||
| generateTranslationsObjectFrom(ScriptUtils.getThemeFiles().filter(th => th.parsed.mustHaveLanguage === undefined), "themes") |  | ||||||
| 
 | 
 | ||||||
|  | const l1 = generateTranslationsObjectFrom(ScriptUtils.getLayerFiles(), "layers") | ||||||
|  | const l2 = generateTranslationsObjectFrom(ScriptUtils.getThemeFiles().filter(th => th.parsed.mustHaveLanguage === undefined), "themes") | ||||||
|  | const l3 = generateTranslationsObjectFrom([{path: questionsPath, parsed: questionsParsed}], "shared-questions") | ||||||
| 
 | 
 | ||||||
| generateTranslationsObjectFrom([{path: questionsPath, parsed: questionsParsed}], "shared-questions") | const usedLanguages = Utils.Dedup(l1.concat(l2).concat(l3)).filter(v => v !== "*") | ||||||
|  | usedLanguages.sort() | ||||||
|  | fs.writeFileSync("./assets/generated/used_languages.json", JSON.stringify({languages: usedLanguages})) | ||||||
| 
 | 
 | ||||||
| if (!themeOverwritesWeblate) { | if (!themeOverwritesWeblate) { | ||||||
| // Generates the core translations
 | // Generates the core translations
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue