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
|
@ -2,6 +2,8 @@ import {Conversion, DesugaringContext, Fuse, OnEveryConcat, SetDefault} from "./
|
|||
import {LayerConfigJson} from "../Json/LayerConfigJson";
|
||||
import {TagRenderingConfigJson} from "../Json/TagRenderingConfigJson";
|
||||
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[]> {
|
||||
constructor() {
|
||||
|
@ -156,13 +158,36 @@ class ExpandGroupRewrite extends Conversion<{
|
|||
}
|
||||
let config = <{
|
||||
rewrite:
|
||||
{ sourceString: string; into: string[] }[];
|
||||
{ sourceString: string[]; into: (string | any)[][] };
|
||||
renderings: (string | { builtin: string; override: any } | TagRenderingConfigJson)[]
|
||||
}>json;
|
||||
|
||||
{
|
||||
const errors = []
|
||||
|
||||
const expectedLength = config.rewrite.sourceString.length
|
||||
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])
|
||||
|
||||
const subRenderingsRes = ExpandGroupRewrite.expandSubTagRenderings.convertAll(state, config.renderings, context);
|
||||
const subRenderings: TagRenderingConfigJson[] = [].concat(subRenderingsRes.result);
|
||||
}
|
||||
}
|
||||
|
||||
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 warnings = subRenderingsRes.warnings;
|
||||
|
||||
|
@ -170,22 +195,31 @@ class ExpandGroupRewrite extends Conversion<{
|
|||
const rewrittenPerGroup = new Map<string, TagRenderingConfigJson[]>()
|
||||
|
||||
// The actual rewriting
|
||||
for (const rewrite of config.rewrite) {
|
||||
const source = rewrite.sourceString;
|
||||
for (const target of rewrite.into) {
|
||||
const groupName = target;
|
||||
const trs: TagRenderingConfigJson[] = []
|
||||
const sourceStrings = config.rewrite.sourceString;
|
||||
for (const targets of config.rewrite.into) {
|
||||
const groupName = targets[0];
|
||||
if(typeof groupName !== "string"){
|
||||
throw "The first string of 'targets' should always be a string"
|
||||
}
|
||||
const trs: TagRenderingConfigJson[] = []
|
||||
|
||||
for (const tr of subRenderings) {
|
||||
trs.push(this.prepConfig(source, target, tr))
|
||||
for (const tr of subRenderings) {
|
||||
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)) {
|
||||
rewrittenPerGroup.get(groupName).push(...trs)
|
||||
rewritten.group = rewritten.group ?? groupName
|
||||
trs.push(rewritten)
|
||||
}
|
||||
|
||||
} else {
|
||||
rewrittenPerGroup.set(groupName, trs)
|
||||
if (rewrittenPerGroup.has(groupName)) {
|
||||
rewrittenPerGroup.get(groupName).push(...trs)
|
||||
} else {
|
||||
rewrittenPerGroup.set(groupName, trs)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +235,7 @@ class ExpandGroupRewrite extends Conversion<{
|
|||
rewrittenPerGroup.forEach((group, _) => {
|
||||
group.forEach(tr => {
|
||||
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 */
|
||||
private prepConfig(keyToRewrite: string, target: string, tr: TagRenderingConfigJson) {
|
||||
/* Used for left|right group creation and replacement.
|
||||
* 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) {
|
||||
if (typeof transl === "string") {
|
||||
// This is a simple string - we do a simple replace
|
||||
return transl.replace(keyToRewrite, target)
|
||||
}
|
||||
if (transl.map !== undefined) {
|
||||
// This is a list of items
|
||||
return transl.map(o => replaceRecursive(o))
|
||||
}
|
||||
|
||||
if (Translations.isProbablyATranslation(transl) && isTranslation) {
|
||||
return Translations.T(transl).Fuse(new Translation(target), keyToRewrite).translations
|
||||
}
|
||||
|
||||
transl = {...transl}
|
||||
for (const key in transl) {
|
||||
transl[key] = replaceRecursive(transl[key])
|
||||
|
@ -229,12 +273,7 @@ class ExpandGroupRewrite extends Conversion<{
|
|||
return transl
|
||||
}
|
||||
|
||||
const orig = tr;
|
||||
tr = replaceRecursive(tr)
|
||||
|
||||
tr.id = target + "-" + orig.id
|
||||
tr.group = target
|
||||
return tr
|
||||
return replaceRecursive(tr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -225,9 +225,9 @@ export interface LayerConfigJson {
|
|||
*/
|
||||
tagRenderings?: (string | { builtin: string, override: any } | TagRenderingConfigJson | {
|
||||
rewrite: {
|
||||
sourceString: string,
|
||||
into: string[]
|
||||
}[],
|
||||
sourceString: string[],
|
||||
into: (string | any)[][]
|
||||
},
|
||||
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
|
||||
*/
|
||||
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).
|
||||
*
|
||||
|
|
|
@ -41,7 +41,8 @@ export default class TagRenderingConfig {
|
|||
readonly mappings?: {
|
||||
readonly if: TagsFilter,
|
||||
readonly ifnot?: TagsFilter,
|
||||
readonly then: Translation
|
||||
readonly then: Translation,
|
||||
readonly icon: string,
|
||||
readonly hideInAnswer: boolean | TagsFilter
|
||||
readonly addExtraTags: Tag[]
|
||||
}[]
|
||||
|
@ -163,11 +164,16 @@ export default class TagRenderingConfig {
|
|||
} else if (mapping.hideInAnswer !== undefined) {
|
||||
hideInAnswer = TagUtils.Tag(mapping.hideInAnswer, `${context}.mapping[${i}].hideInAnswer`);
|
||||
}
|
||||
let icon = undefined;
|
||||
if(mapping.icon !== ""){
|
||||
icon = mapping.icon
|
||||
}
|
||||
const mp = {
|
||||
if: TagUtils.Tag(mapping.if, `${ctx}.if`),
|
||||
ifnot: (mapping.ifnot !== undefined ? TagUtils.Tag(mapping.ifnot, `${ctx}.ifnot`) : undefined),
|
||||
then: Translations.T(mapping.then, `${ctx}.then`),
|
||||
hideInAnswer: hideInAnswer,
|
||||
hideInAnswer,
|
||||
icon,
|
||||
addExtraTags: (mapping.addExtraTags ?? []).map((str, j) => TagUtils.SimpleTag(str, `${ctx}.addExtraTags[${j}]`))
|
||||
};
|
||||
if (this.question) {
|
||||
|
@ -329,18 +335,18 @@ export default class TagRenderingConfig {
|
|||
* @param tags
|
||||
* @constructor
|
||||
*/
|
||||
public GetRenderValues(tags: any): Translation[] {
|
||||
public GetRenderValues(tags: any): {then: Translation, icon?: string}[] {
|
||||
if (!this.multiAnswer) {
|
||||
return [this.GetRenderValue(tags)]
|
||||
return [this.GetRenderValueWithImage(tags)]
|
||||
}
|
||||
|
||||
// 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
|
||||
let freeformKeyUsed = this.freeform?.key === undefined;
|
||||
// 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) {
|
||||
return mapping.then;
|
||||
return mapping;
|
||||
}
|
||||
if (TagUtils.MatchesMultiAnswer(mapping.if, tags)) {
|
||||
if (!freeformKeyUsed) {
|
||||
|
@ -349,7 +355,7 @@ export default class TagRenderingConfig {
|
|||
freeformKeyUsed = true;
|
||||
}
|
||||
}
|
||||
return mapping.then;
|
||||
return mapping;
|
||||
}
|
||||
return undefined;
|
||||
}))
|
||||
|
@ -357,43 +363,42 @@ export default class TagRenderingConfig {
|
|||
|
||||
if (!freeformKeyUsed
|
||||
&& tags[this.freeform.key] !== undefined) {
|
||||
applicableMappings.push(this.render)
|
||||
applicableMappings.push({then: this.render})
|
||||
}
|
||||
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)
|
||||
* Not compatible with multiAnswer - use GetRenderValueS instead in that case
|
||||
* @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) {
|
||||
for (const mapping of this.mappings) {
|
||||
if (mapping.if === undefined) {
|
||||
return mapping.then;
|
||||
return mapping;
|
||||
}
|
||||
if (mapping.if.matchesProperties(tags)) {
|
||||
if (this.id === "uk_addresses_placename") {
|
||||
console.log("Matched", mapping.if, "with ", tags["addr:place"])
|
||||
}
|
||||
return mapping.then;
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.id === "questions") {
|
||||
return this.render
|
||||
if (this.id === "questions" ||
|
||||
this.freeform?.key === undefined ||
|
||||
tags[this.freeform.key] !== undefined
|
||||
) {
|
||||
return {then: this.render}
|
||||
}
|
||||
|
||||
if (this.freeform?.key === undefined) {
|
||||
return this.render;
|
||||
}
|
||||
|
||||
if (tags[this.freeform.key] !== undefined) {
|
||||
return this.render;
|
||||
}
|
||||
return defltValue;
|
||||
return {then: defltValue};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue