diff --git a/Models/ThemeConfig/Json/LayerConfigJson.ts b/Models/ThemeConfig/Json/LayerConfigJson.ts index 09e8284a4a..aa822f8ec5 100644 --- a/Models/ThemeConfig/Json/LayerConfigJson.ts +++ b/Models/ThemeConfig/Json/LayerConfigJson.ts @@ -196,9 +196,15 @@ export interface LayerConfigJson { * * A special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox. * + * At last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings. + * This is mainly create questions for a 'left' and a 'right' side of the road. + * These will be grouped and questions will be asked together */ tagRenderings?: (string | {builtin: string, override: any} | TagRenderingConfigJson | { - leftRightKeys: string[], + rewrite: { + sourceString: string, + into: string[] + }[], renderings: (string | {builtin: string, override: any} | TagRenderingConfigJson)[] }) [], diff --git a/Models/ThemeConfig/Json/TagRenderingConfigJson.ts b/Models/ThemeConfig/Json/TagRenderingConfigJson.ts index c2aa3d3238..456c693b5d 100644 --- a/Models/ThemeConfig/Json/TagRenderingConfigJson.ts +++ b/Models/ThemeConfig/Json/TagRenderingConfigJson.ts @@ -13,8 +13,8 @@ export interface TagRenderingConfigJson { id?: string, /** - * Optional: this can group questions together in one question box. - * Written by 'left-right'-keys automatically + * If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well. + * The first tagRendering of a group will always be a sticky element. */ group?: string @@ -173,7 +173,5 @@ export interface TagRenderingConfigJson { * If this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer` */ ifnot?: AndOrTagConfigJson | string - }[] - } \ No newline at end of file diff --git a/Models/ThemeConfig/LayerConfig.ts b/Models/ThemeConfig/LayerConfig.ts index 6518caca94..7099705a79 100644 --- a/Models/ThemeConfig/LayerConfig.ts +++ b/Models/ThemeConfig/LayerConfig.ts @@ -207,7 +207,7 @@ export default class LayerConfig extends WithContextLoader { this.tagRenderings = this.ExtractLayerTagRenderings(json) - const missingIds = json.tagRenderings?.filter(tr => typeof tr !== "string" && tr["builtin"] === undefined && tr["id"] === undefined && tr["leftRightKeys"] === undefined) ?? []; + const missingIds = json.tagRenderings?.filter(tr => typeof tr !== "string" && tr["builtin"] === undefined && tr["id"] === undefined && tr["rewrite"] === undefined) ?? []; if (missingIds.length > 0 && official) { console.error("Some tagRenderings of", this.id, "are missing an id:", missingIds) @@ -277,39 +277,41 @@ export default class LayerConfig extends WithContextLoader { } const normalTagRenderings: (string | { builtin: string, override: any } | TagRenderingConfigJson)[] = [] - const leftRightRenderings: ({ leftRightKeys: string[], renderings: (string | { builtin: string, override: any } | TagRenderingConfigJson)[] })[] = [] + + + const renderingsToRewrite: ({ rewrite:{ + sourceString: string, + into: string[] + }, renderings: (string | { builtin: string, override: any } | TagRenderingConfigJson)[] })[] = [] for (let i = 0; i < json.tagRenderings.length; i++) { const tr = json.tagRenderings[i]; - const lrkDefined = tr["leftRightKeys"] !== undefined + const rewriteDefined = tr["rewrite"] !== undefined const renderingsDefined = tr["renderings"] - if (!lrkDefined && !renderingsDefined) { + if (!rewriteDefined && !renderingsDefined) { // @ts-ignore normalTagRenderings.push(tr) continue } - if (lrkDefined && renderingsDefined) { + if (rewriteDefined && renderingsDefined) { // @ts-ignore - leftRightRenderings.push(tr) + renderingsToRewrite.push(tr) continue } - throw `Error in ${this._context}.tagrenderings[${i}]: got a value which defines either \`leftRightKeys\` or \`renderings\`, but not both. Either define both or move the \`renderings\` out of this scope` + throw `Error in ${this._context}.tagrenderings[${i}]: got a value which defines either \`rewrite\` or \`renderings\`, but not both. Either define both or move the \`renderings\` out of this scope` } const allRenderings = this.ParseTagRenderings(normalTagRenderings, false); - if(leftRightRenderings.length === 0){ + if(renderingsToRewrite.length === 0){ return allRenderings } - const leftRenderings : TagRenderingConfig[] = [] - const rightRenderings : TagRenderingConfig[] = [] - - function prepConfig(target:string, tr: TagRenderingConfigJson){ + function prepConfig(keyToRewrite: string, target:string, tr: TagRenderingConfigJson){ function replaceRecursive(transl: string | any){ if(typeof transl === "string"){ - return transl.replace("left|right", target) + return transl.replace(keyToRewrite, target) } if(transl.map !== undefined){ return transl.map(o => replaceRecursive(o)) @@ -328,33 +330,34 @@ export default class LayerConfig extends WithContextLoader { tr.group = target return tr } - - - for (const leftRightRendering of leftRightRenderings) { - - const keysToRewrite = leftRightRendering.leftRightKeys - const tagRenderings = leftRightRendering.renderings - - const left = this.ParseTagRenderings(tagRenderings, false, tr => prepConfig("left", tr)) - const right = this.ParseTagRenderings(tagRenderings, false, tr => prepConfig("right", tr)) - - leftRenderings.push(...left) - rightRenderings.push(...right) + 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)){ + rewriteGroups.set(target, []) + } + rewriteGroups.get(target).push(... parsedRenderings) + } } - leftRenderings.push(new TagRenderingConfig({ - id: "questions", - group:"left", - }, "layerConfig.ts.leftQuestionBox")) - - rightRenderings.push(new TagRenderingConfig({ - id: "questions", - group:"right", - }, "layerConfig.ts.rightQuestionBox")) - allRenderings.push(...leftRenderings) - allRenderings.push(...rightRenderings) + rewriteGroups.forEach((group, groupName) => { + group.push(new TagRenderingConfig({ + id:"questions", + group:groupName + })) + }) + + rewriteGroups.forEach(group => { + allRenderings.push(...group) + }) return allRenderings; diff --git a/Models/ThemeConfig/WithContextLoader.ts b/Models/ThemeConfig/WithContextLoader.ts index 0cab6616c5..fea75511e2 100644 --- a/Models/ThemeConfig/WithContextLoader.ts +++ b/Models/ThemeConfig/WithContextLoader.ts @@ -47,7 +47,7 @@ export default class WithContextLoader { tagRenderings?: (string | { builtin: string, override: any } | TagRenderingConfigJson)[], readOnly = false, prepConfig: ((config: TagRenderingConfigJson) => TagRenderingConfigJson) = undefined - ) { + ) : TagRenderingConfig[]{ if (tagRenderings === undefined) { return []; } @@ -77,18 +77,17 @@ export default class WithContextLoader { continue; } - if (renderingJson["override"] !== undefined) { - let sharedJson = SharedTagRenderings.SharedTagRenderingJson.get(renderingId) - - if (sharedJson === undefined) { - const keys = Array.from(SharedTagRenderings.SharedTagRenderingJson.keys()); - throw `Predefined tagRendering ${renderingId} not found in ${context}.\n Try one of ${keys.join( - ", " - )}\n If you intent to output this text literally, use {\"render\": } instead"}`; - } - - renderingJson = Utils.Merge(renderingJson["override"], sharedJson) + let sharedJson = SharedTagRenderings.SharedTagRenderingJson.get(renderingId) + if (sharedJson === undefined) { + const keys = Array.from(SharedTagRenderings.SharedTagRenderingJson.keys()); + throw `Predefined tagRendering ${renderingId} not found in ${context}.\n Try one of ${keys.join( + ", " + )}\n If you intent to output this text literally, use {\"render\": } instead"}`; } + if (renderingJson["override"] !== undefined) { + sharedJson = Utils.Merge(renderingJson["override"], sharedJson) + } + renderingJson = sharedJson } diff --git a/UI/Input/LengthInput.ts b/UI/Input/LengthInput.ts index 4eb39d7e95..2875f43629 100644 --- a/UI/Input/LengthInput.ts +++ b/UI/Input/LengthInput.ts @@ -45,6 +45,7 @@ export default class LengthInput extends InputElement { background: this.background, allowMoving: false, location: this._location, + attribution:true, leafletOptions: { tap: true } diff --git a/UI/Popup/EditableTagRendering.ts b/UI/Popup/EditableTagRendering.ts index 2be62b01be..55cd7504de 100644 --- a/UI/Popup/EditableTagRendering.ts +++ b/UI/Popup/EditableTagRendering.ts @@ -71,7 +71,6 @@ export default class EditableTagRendering extends Toggle { editMode ) } - rendering.SetClass("block w-full break-word text-default m-1 p-1 border-b border-gray-200 mb-2 pb-2") return rendering; } diff --git a/UI/Popup/FeatureInfoBox.ts b/UI/Popup/FeatureInfoBox.ts index dde27d9c1b..ce30d851e3 100644 --- a/UI/Popup/FeatureInfoBox.ts +++ b/UI/Popup/FeatureInfoBox.ts @@ -5,7 +5,6 @@ import Combine from "../Base/Combine"; import TagRenderingAnswer from "./TagRenderingAnswer"; import State from "../../State"; import ScrollableFullScreen from "../Base/ScrollableFullScreen"; -import {Tag} from "../../Logic/Tags/Tag"; import Constants from "../../Models/Constants"; import SharedTagRenderings from "../../Customizations/SharedTagRenderings"; import BaseUIElement from "../BaseUIElement"; @@ -18,7 +17,6 @@ import {Translation} from "../i18n/Translation"; import {Utils} from "../../Utils"; import {SubstitutedTranslation} from "../SubstitutedTranslation"; import MoveWizard from "./MoveWizard"; -import {FixedUiElement} from "../Base/FixedUiElement"; export default class FeatureInfoBox extends ScrollableFullScreen { @@ -55,8 +53,8 @@ export default class FeatureInfoBox extends ScrollableFullScreen { layerConfig: LayerConfig): BaseUIElement { let questionBoxes: Map = new Map(); + const allGroupNames = Utils.Dedup(layerConfig.tagRenderings.map(tr => tr.group)) if (State.state.featureSwitchUserbadge.data) { - const allGroupNames = Utils.Dedup(layerConfig.tagRenderings.map(tr => tr.group)) for (const groupName of allGroupNames) { const questions = layerConfig.tagRenderings.filter(tr => tr.group === groupName) const questionBox = new QuestionBox(tags, questions, layerConfig.units); @@ -65,23 +63,45 @@ export default class FeatureInfoBox extends ScrollableFullScreen { } } - const renderings: BaseUIElement[] = layerConfig.tagRenderings.map(tr => { - if (tr.question === null || tr.id === "questions") { - console.log("Rendering is", tr) - // This is a question box! - const questionBox = questionBoxes.get(tr.group) - questionBoxes.delete(tr.group) - return questionBox; + const allRenderings = [] + for (let i = 0; i < allGroupNames.length; i++) { + const groupName = allGroupNames[i]; + + const trs = layerConfig.tagRenderings.filter(tr => tr.group === groupName) + const renderingsForGroup: BaseUIElement[] = [] + for (const tr of trs) { + if (tr.question === null || tr.id === "questions") { + // This is a question box! + const questionBox = questionBoxes.get(tr.group) + questionBoxes.delete(tr.group) + renderingsForGroup.push(questionBox) + } else { + const etr = new EditableTagRendering(tags, tr, layerConfig.units).SetClass("editable-tag-rendering") + + renderingsForGroup.push(etr) + } } - return new EditableTagRendering(tags, tr, layerConfig.units); - }); + let j = 0 + if (i !== 0) { + renderingsForGroup[0]?.SetStyle("position: sticky; top: -5px") + j = 1 + } + for (/* j = 0 or 1 */; j < renderingsForGroup.length; j++) { + renderingsForGroup[j].SetClass("block w-full break-word text-default m-1 p-1 border-b border-gray-200 mb-2 pb-2") + } + + + + allRenderings.push(...renderingsForGroup) + } + let editElements: BaseUIElement[] = [] questionBoxes.forEach(questionBox => { editElements.push(questionBox); }) - if(layerConfig.allowMove) { + if (layerConfig.allowMove) { editElements.push( new VariableUiElement(tags.map(tags => tags.id).map(id => { const feature = State.state.allElements.ContainingFeatures.get(id) @@ -115,7 +135,7 @@ export default class FeatureInfoBox extends ScrollableFullScreen { const hasMinimap = layerConfig.tagRenderings.some(tr => FeatureInfoBox.hasMinimap(tr)) if (!hasMinimap) { - renderings.push(new TagRenderingAnswer(tags, SharedTagRenderings.SharedTagRendering.get("minimap"))) + allRenderings.push(new TagRenderingAnswer(tags, SharedTagRenderings.SharedTagRendering.get("minimap"))) } editElements.push( @@ -140,7 +160,7 @@ export default class FeatureInfoBox extends ScrollableFullScreen { new VariableUiElement( State.state.featureSwitchIsDebugging.map(isDebugging => { if (isDebugging) { - const config: TagRenderingConfig = new TagRenderingConfig({render: "{all_tags()}"}, ""); + const config: TagRenderingConfig = new TagRenderingConfig({render: "{all_tags()}"}, ""); return new TagRenderingAnswer(tags, config, "all_tags") } }) @@ -155,9 +175,9 @@ export default class FeatureInfoBox extends ScrollableFullScreen { return new Combine(editElements).SetClass("flex flex-col") } )) - renderings.push(editors) + allRenderings.push(editors) - return new Combine(renderings).SetClass("block") + return new Combine(allRenderings).SetClass("block") } diff --git a/assets/themes/sidewalks/sidewalks.json b/assets/themes/sidewalks/sidewalks.json index 8e30b0a2b4..6167c6acc1 100644 --- a/assets/themes/sidewalks/sidewalks.json +++ b/assets/themes/sidewalks/sidewalks.json @@ -54,7 +54,10 @@ }, { - "leftRightKeys": "sidewalk:left|right", + "rewrite": { + "sourceString": "left|right", + "into": ["left","right"] + }, "renderings": [ { "id": "sidewalk_minimap",