From 4d5c250f8f15a538192d3ca554c32a471cf348d7 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Tue, 6 Apr 2021 18:17:07 +0200 Subject: [PATCH] Add HTML rendering options to icons --- Customizations/JSON/LayerConfig.ts | 56 +++++++++++++++---- Customizations/JSON/LayerConfigJson.ts | 3 + Logic/Tags/SubstitutingTag.ts | 4 +- UI/SubstitutedTranslation.ts | 40 ++++++------- .../public_bookcases/public_bookcases.json | 8 ++- 5 files changed, 77 insertions(+), 34 deletions(-) diff --git a/Customizations/JSON/LayerConfig.ts b/Customizations/JSON/LayerConfig.ts index 7d85a61..71011ce 100644 --- a/Customizations/JSON/LayerConfig.ts +++ b/Customizations/JSON/LayerConfig.ts @@ -17,6 +17,7 @@ import {SubstitutedTranslation} from "../../UI/SubstitutedTranslation"; import SourceConfig from "./SourceConfig"; import {TagsFilter} from "../../Logic/Tags/TagsFilter"; import {Tag} from "../../Logic/Tags/Tag"; +import SubstitutingTag from "../../Logic/Tags/SubstitutingTag"; export default class LayerConfig { @@ -218,11 +219,35 @@ export default class LayerConfig { this.dashArray = tr("dashArray", ""); - if(json["showIf"] !== undefined){ - throw "Invalid key on layerconfig "+this.id+": showIf. Did you mean 'isShown' instead?"; + if (json["showIf"] !== undefined) { + throw "Invalid key on layerconfig " + this.id + ": showIf. Did you mean 'isShown' instead?"; } } + /** + * Splits the parts of the icon, at ";" but makes sure that everything between "" and "" stays together + * @param template + * @constructor + * @private + */ + private static SplitParts(template: string): string[] { + const htmlParts = template.split(""); + const parts = [] + for (const htmlPart of htmlParts) { + if (htmlPart.indexOf("") >= 0) { + const subparts = htmlPart.split(""); + if (subparts.length != 2) { + throw "Invalid rendering with embedded html: " + htmlPart; + } + parts.push("html:" + subparts[0]); + parts.push(...subparts[1].split(";")) + } else { + parts.push(...htmlPart.split(";")) + } + } + return parts.filter(prt => prt != ""); + } + public CustomCodeSnippets(): string[] { if (this.calculatedTags === undefined) { return [] @@ -343,15 +368,16 @@ export default class LayerConfig { const iconUrlStatic = render(this.icon); const self = this; const mappedHtml = tags.map(tgs => { - // What do you mean, 'tgs' is never read? - // It is read implicitly in the 'render' method - const iconUrl = render(self.icon); - const rotation = render(self.rotation, "0deg"); - - let htmlParts: UIElement[] = []; - let sourceParts = iconUrl.split(";"); - function genHtmlFromString(sourcePart: string): UIElement { + console.log("Got source part ", sourcePart) + if (sourcePart.indexOf("html:") == 0) { + // We use ยง as a replacement for ; + const html = sourcePart.substring("html:".length) + const inner = new FixedUiElement(SubstitutingTag.substituteString(html, tgs)).SetClass("block w-min text-center") + const outer = new Combine([inner]).SetClass("flex flex-col items-center") + return outer; + } + const style = `width:100%;height:100%;transform: rotate( ${rotation} );display:block;position: absolute; top: 0; left: 0`; let html: UIElement = new FixedUiElement(``); const match = sourcePart.match(/([a-zA-Z0-9_]*):([^;]*)/) @@ -365,6 +391,14 @@ export default class LayerConfig { } + // What do you mean, 'tgs' is never read? + // It is read implicitly in the 'render' method + const iconUrl = render(self.icon); + const rotation = render(self.rotation, "0deg"); + + let htmlParts: UIElement[] = []; + let sourceParts = LayerConfig.SplitParts(iconUrl); + for (const sourcePart of sourceParts) { htmlParts.push(genHtmlFromString(sourcePart)) } @@ -377,7 +411,7 @@ export default class LayerConfig { } if (iconOverlay.badge) { const badgeParts: UIElement[] = []; - const partDefs = iconOverlay.then.GetRenderValue(tgs).txt.split(";"); + const partDefs = LayerConfig.SplitParts(iconOverlay.then.GetRenderValue(tgs).txt); for (const badgePartStr of partDefs) { badgeParts.push(genHtmlFromString(badgePartStr)) diff --git a/Customizations/JSON/LayerConfigJson.ts b/Customizations/JSON/LayerConfigJson.ts index b21bb3f..b78cb5c 100644 --- a/Customizations/JSON/LayerConfigJson.ts +++ b/Customizations/JSON/LayerConfigJson.ts @@ -105,6 +105,9 @@ export interface LayerConfigJson { * As a result, on could use a generic pin, then overlay it with a specific icon. * To make things even more practical, one can use all svgs from the folder "assets/svg" and _substitute the color_ in it. * E.g. to draw a red pin, use "pin:#f00", to have a green circle with your icon on top, use `circle:#0f0;` + * + * Also note that one can specify to use HTML by entering some html between "" and "
{name}
" */ icon?: string | TagRenderingConfigJson; diff --git a/Logic/Tags/SubstitutingTag.ts b/Logic/Tags/SubstitutingTag.ts index 58591d5..567693c 100644 --- a/Logic/Tags/SubstitutingTag.ts +++ b/Logic/Tags/SubstitutingTag.ts @@ -18,11 +18,11 @@ export default class SubstitutingTag implements TagsFilter { this._value = value; } - private static substituteString(template: string, dict: any): string { + public static substituteString(template: string, dict: any): string { for (const k in dict) { template = template.replace(new RegExp("\\{" + k + "\\}", 'g'), dict[k]) } - return template; + return template.replace(/{.*}/g, ""); } asHumanString(linkToWiki: boolean, shorten: boolean, properties) { diff --git a/UI/SubstitutedTranslation.ts b/UI/SubstitutedTranslation.ts index cd132fd..4483887 100644 --- a/UI/SubstitutedTranslation.ts +++ b/UI/SubstitutedTranslation.ts @@ -9,7 +9,7 @@ import SpecialVisualizations from "./SpecialVisualizations"; import {Utils} from "../Utils"; export class SubstitutedTranslation extends UIElement { - private static cachedTranslations: + private static cachedTranslations: Map, SubstitutedTranslation>>> = new Map, SubstitutedTranslation>>>(); private readonly tags: UIEventSource; private readonly translation: Translation; @@ -34,39 +34,39 @@ export class SubstitutedTranslation extends UIElement { this.SetClass("w-full") } - private static GenerateMap(){ - return new Map, SubstitutedTranslation>() - } - private static GenerateSubCache(){ - return new Map, SubstitutedTranslation>>(); - } - public static construct( translation: Translation, tags: UIEventSource): SubstitutedTranslation { - - /* let cachedTranslations = Utils.getOrSetDefault(SubstitutedTranslation.cachedTranslations, SubstitutedTranslation.GenerateSubCache); - const innerMap = Utils.getOrSetDefault(cachedTranslations, translation, SubstitutedTranslation.GenerateMap); - const cachedTranslation = innerMap.get(tags); - if (cachedTranslation !== undefined) { - return cachedTranslation; - }*/ + /* let cachedTranslations = Utils.getOrSetDefault(SubstitutedTranslation.cachedTranslations, SubstitutedTranslation.GenerateSubCache); + const innerMap = Utils.getOrSetDefault(cachedTranslations, translation, SubstitutedTranslation.GenerateMap); + + const cachedTranslation = innerMap.get(tags); + if (cachedTranslation !== undefined) { + return cachedTranslation; + }*/ const st = new SubstitutedTranslation(translation, tags); - // innerMap.set(tags, st); + // innerMap.set(tags, st); return st; } public static SubstituteKeys(txt: string, tags: any) { for (const key in tags) { - // Poor mans replace all - txt = txt.split("{" + key + "}").join(tags[key]); + txt = txt.replace(new RegExp("{" + key + "}", "g"), tags[key]) } - return txt; + return txt.replace(/{.*}/g, ""); + } + + private static GenerateMap() { + return new Map, SubstitutedTranslation>() + } + + private static GenerateSubCache() { + return new Map, SubstitutedTranslation>>(); } InnerRender(): string { - if(this.content.length == 1){ + if (this.content.length == 1) { return this.content[0].Render(); } return new Combine(this.content).Render(); diff --git a/assets/layers/public_bookcases/public_bookcases.json b/assets/layers/public_bookcases/public_bookcases.json index c159920..8087a36 100644 --- a/assets/layers/public_bookcases/public_bookcases.json +++ b/assets/layers/public_bookcases/public_bookcases.json @@ -37,7 +37,13 @@ ] }, "icon": { - "render": "./assets/themes/bookcases/bookcase.svg" + "render": "./assets/themes/bookcases/bookcase.svg;", + "mappings": [ + { + "if": "name~*", + "then": "./assets/themes/bookcases/bookcase.svg;
{name}
" + } + ] }, "color": { "render": "#0000ff"