2020-11-06 01:58:26 +01:00
import { Translation } from "../../UI/i18n/Translation" ;
2021-08-07 23:11:34 +02:00
import { TagsFilter } from "../../Logic/Tags/TagsFilter" ;
import Translations from "../../UI/i18n/Translations" ;
2021-03-29 00:41:53 +02:00
import { TagUtils } from "../../Logic/Tags/TagUtils" ;
import { And } from "../../Logic/Tags/And" ;
2021-08-07 23:11:34 +02:00
import ValidatedTextField from "../../UI/Input/ValidatedTextField" ;
import { Utils } from "../../Utils" ;
2021-10-26 22:53:27 +02:00
import { Tag } from "../../Logic/Tags/Tag" ;
2022-01-14 19:34:00 +01:00
import BaseUIElement from "../../UI/BaseUIElement" ;
import Combine from "../../UI/Base/Combine" ;
import Title from "../../UI/Base/Title" ;
import Link from "../../UI/Base/Link" ;
import List from "../../UI/Base/List" ;
2022-02-28 17:17:38 +01:00
import { QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRenderingConfigJson" ;
2022-04-08 01:55:42 +02:00
import { FixedUiElement } from "../../UI/Base/FixedUiElement" ;
2020-10-27 01:01:34 +01:00
/ * * *
* The parsed version of TagRenderingConfigJSON
* Identical data , but with some methods and validation
* /
export default class TagRenderingConfig {
2022-02-11 04:28:11 +01:00
public readonly id : string ;
public readonly group : string ;
public readonly render? : Translation ;
public readonly question? : Translation ;
public readonly condition? : TagsFilter ;
2021-03-31 15:50:29 +02:00
2022-02-11 04:28:11 +01:00
public readonly configuration_warnings : string [ ] = [ ]
2020-10-27 01:01:34 +01:00
2022-02-11 04:28:11 +01:00
public readonly freeform ? : {
2021-03-31 15:50:29 +02:00
readonly key : string ,
readonly type : string ,
2022-02-07 01:57:15 +01:00
readonly placeholder : Translation ,
2021-03-31 15:50:29 +02:00
readonly addExtraTags : TagsFilter [ ] ;
2021-07-11 15:44:17 +02:00
readonly inline : boolean ,
2021-07-20 01:33:58 +02:00
readonly default ? : string ,
readonly helperArgs ? : ( string | number | boolean ) [ ]
2020-10-27 01:01:34 +01:00
} ;
2022-02-08 02:23:38 +01:00
public readonly multiAnswer : boolean ;
2020-10-27 01:01:34 +01:00
2022-02-08 02:23:38 +01:00
public readonly mappings ? : {
2021-02-20 16:48:42 +01:00
readonly if : TagsFilter ,
readonly ifnot? : TagsFilter ,
2022-01-29 02:45:59 +01:00
readonly then : Translation ,
readonly icon : string ,
2022-02-17 23:54:14 +01:00
readonly iconClass : string
2021-02-20 16:48:42 +01:00
readonly hideInAnswer : boolean | TagsFilter
2021-10-26 22:53:27 +02:00
readonly addExtraTags : Tag [ ]
2020-10-27 01:01:34 +01:00
} [ ]
2022-02-08 02:23:38 +01:00
public readonly labels : string [ ]
2022-01-26 21:40:38 +01:00
2022-02-28 17:17:38 +01:00
constructor ( json : string | QuestionableTagRenderingConfigJson , context? : string ) {
2021-11-14 18:01:48 +01:00
if ( json === undefined ) {
throw "Initing a TagRenderingConfig with undefined in " + context ;
}
2020-12-08 23:44:34 +01:00
if ( json === "questions" ) {
// Very special value
this . render = null ;
this . question = null ;
this . condition = null ;
2021-11-07 18:37:42 +01:00
this . id = "questions"
this . group = ""
return ;
2020-12-08 23:44:34 +01:00
}
2021-11-07 16:34:51 +01:00
if ( typeof json === "number" ) {
2021-12-05 02:06:14 +01:00
json = "" + json
2021-10-22 01:07:32 +02:00
}
2021-11-07 16:34:51 +01:00
2022-04-01 12:51:55 +02:00
let translationKey = context ;
if ( json [ "id" ] !== undefined ) {
const layerId = context . split ( "." ) [ 0 ]
if ( json [ "source" ] ) {
let src = json [ "source" ] + ":"
if ( json [ "source" ] === "shared-questions" ) {
src += "shared_questions."
}
translationKey = ` ${ src } ${ json [ "id" ] ? ? "" } `
} else {
translationKey = ` layers: ${ layerId } .tagRenderings. ${ json [ "id" ] ? ? "" } `
}
}
2021-11-07 16:34:51 +01:00
2020-10-27 01:01:34 +01:00
if ( typeof json === "string" ) {
2022-04-01 12:51:55 +02:00
this . render = Translations . T ( json , translationKey + ".render" ) ;
2020-10-27 01:01:34 +01:00
this . multiAnswer = false ;
return ;
}
2021-01-08 03:57:18 +01:00
2021-11-07 16:34:51 +01:00
2021-12-21 18:35:31 +01:00
this . id = json . id ? ? "" ; // Some tagrenderings - especially for the map rendering - don't need an ID
2021-12-05 02:06:14 +01:00
if ( this . id . match ( /^[a-zA-Z0-9 ()?\/=:;,_-]*$/ ) === null ) {
throw "Invalid ID in " + context + ": an id can only contain [a-zA-Z0-0_-] as characters. The offending id is: " + this . id
2021-11-11 17:14:03 +01:00
}
2021-12-05 02:06:14 +01:00
2021-10-22 18:53:07 +02:00
this . group = json . group ? ? "" ;
2022-02-08 02:23:38 +01:00
this . labels = json . labels ? ? [ ]
2022-04-01 12:51:55 +02:00
this . render = Translations . T ( json . render , translationKey + ".render" ) ;
this . question = Translations . T ( json . question , translationKey + ".question" ) ;
2021-10-19 03:00:57 +02:00
this . condition = TagUtils . Tag ( json . condition ? ? { "and" : [ ] } , ` ${ context } .condition ` ) ;
2020-10-27 01:01:34 +01:00
if ( json . freeform ) {
2021-06-22 00:29:07 +02:00
2021-11-07 16:34:51 +01:00
if ( json . freeform . addExtraTags !== undefined && json . freeform . addExtraTags . map === undefined ) {
2021-09-09 20:26:12 +02:00
throw ` Freeform.addExtraTags should be a list of strings - not a single string (at ${ context } ) `
}
2022-02-11 04:28:11 +01:00
const type = json . freeform . type ? ? "string"
let placeholder = Translations . T ( json . freeform . placeholder )
if ( placeholder === undefined ) {
const typeDescription = Translations . t . validation [ type ] ? . description
placeholder = Translations . T ( json . freeform . key + " (" + type + ")" )
if ( typeDescription !== undefined ) {
2022-04-01 12:51:55 +02:00
placeholder = placeholder . Subs ( { [ type ] : typeDescription } )
2022-02-11 04:28:11 +01:00
}
}
2020-10-27 01:01:34 +01:00
this . freeform = {
key : json.freeform.key ,
2022-02-11 04:28:11 +01:00
type ,
placeholder ,
2020-10-27 01:01:34 +01:00
addExtraTags : json.freeform.addExtraTags?.map ( ( tg , i ) = >
2021-08-07 23:11:34 +02:00
TagUtils . Tag ( tg , ` ${ context } .extratag[ ${ i } ] ` ) ) ? ? [ ] ,
2021-07-11 15:44:17 +02:00
inline : json.freeform.inline ? ? false ,
2021-07-20 01:33:58 +02:00
default : json . freeform . default ,
helperArgs : json.freeform.helperArgs
2021-06-27 19:21:31 +02:00
2020-10-27 01:01:34 +01:00
}
2021-04-09 02:57:06 +02:00
if ( json . freeform [ "extraTags" ] !== undefined ) {
2021-03-31 15:50:29 +02:00
throw ` Freeform.extraTags is defined. This should probably be 'freeform.addExtraTag' (at ${ context } ) `
}
if ( this . freeform . key === undefined || this . freeform . key === "" ) {
2021-03-10 20:18:05 +01:00
throw ` Freeform.key is undefined or the empty string - this is not allowed; either fill out something or remove the freeform block alltogether. Error in ${ context } `
}
2021-08-07 23:11:34 +02:00
if ( json . freeform [ "args" ] !== undefined ) {
2021-07-29 00:29:29 +02:00
throw ` Freeform.args is defined. This should probably be 'freeform.helperArgs' (at ${ context } ) `
}
2021-12-05 02:06:14 +01:00
if ( json . freeform . key === "questions" ) {
if ( this . id !== "questions" ) {
2021-11-12 01:44:13 +01:00
throw ` If you use a freeform key 'questions', the ID must be 'questions' too to trigger the special behaviour. The current id is ' ${ this . id } ' (at ${ context } ) `
}
}
2021-06-27 19:21:31 +02:00
2022-02-12 02:53:41 +01:00
if ( ! ValidatedTextField . ForType ( this . freeform . key ) === undefined ) {
2022-02-11 20:56:54 +01:00
const knownKeys = ValidatedTextField . AvailableTypes ( ) . join ( ", " ) ;
2021-04-18 14:24:30 +02:00
throw ` Freeform.key ${ this . freeform . key } is an invalid type. Known keys are ${ knownKeys } `
2020-10-27 01:01:34 +01:00
}
2021-03-31 15:50:29 +02:00
if ( this . freeform . addExtraTags ) {
2021-03-10 20:18:05 +01:00
const usedKeys = new And ( this . freeform . addExtraTags ) . usedKeys ( ) ;
2021-03-31 15:50:29 +02:00
if ( usedKeys . indexOf ( this . freeform . key ) >= 0 ) {
2021-03-10 20:18:05 +01:00
throw ` The freeform key ${ this . freeform . key } will be overwritten by one of the extra tags, as they use the same key too. This is in ${ context } ` ;
}
}
2020-10-27 01:01:34 +01:00
}
this . multiAnswer = json . multiAnswer ? ? false
if ( json . mappings ) {
2021-03-31 15:50:29 +02:00
2021-06-22 00:29:07 +02:00
if ( ! Array . isArray ( json . mappings ) ) {
throw "Tagrendering has a 'mappings'-object, but expected a list (" + context + ")"
2021-04-10 03:50:44 +02:00
}
2021-03-31 15:50:29 +02:00
2020-10-27 01:01:34 +01:00
this . mappings = json . mappings . map ( ( mapping , i ) = > {
2022-04-01 12:51:55 +02:00
const ctx = ` ${ translationKey } .mappings. ${ i } `
2020-10-27 01:01:34 +01:00
if ( mapping . then === undefined ) {
2021-10-26 22:53:27 +02:00
throw ` ${ ctx } : Invalid mapping: if without body `
2021-02-20 16:48:42 +01:00
}
if ( mapping . ifnot !== undefined && ! this . multiAnswer ) {
2021-10-26 22:53:27 +02:00
throw ` ${ ctx } : Invalid mapping: ifnot defined, but the tagrendering is not a multianswer `
2020-10-27 01:01:34 +01:00
}
2021-06-22 00:29:07 +02:00
if ( mapping . if === undefined ) {
2021-10-26 22:53:27 +02:00
throw ` ${ ctx } : Invalid mapping: "if" is not defined, but the tagrendering is not a multianswer `
2021-05-17 17:10:54 +02:00
}
2021-06-22 00:29:07 +02:00
if ( typeof mapping . if !== "string" && mapping . if [ "length" ] !== undefined ) {
2021-10-26 22:53:27 +02:00
throw ` ${ ctx } : Invalid mapping: "if" is defined as an array. Use {"and": <your conditions>} or {"or": <your conditions>} instead `
}
2021-11-07 16:34:51 +01:00
if ( mapping . addExtraTags !== undefined && this . multiAnswer ) {
2021-10-26 22:53:27 +02:00
throw ` ${ ctx } : Invalid mapping: got a multi-Answer with addExtraTags; this is not allowed `
2021-05-17 17:10:54 +02:00
}
2021-06-22 00:29:07 +02:00
2021-01-06 01:11:07 +01:00
let hideInAnswer : boolean | TagsFilter = false ;
2020-12-08 23:44:34 +01:00
if ( typeof mapping . hideInAnswer === "boolean" ) {
2020-12-07 03:02:50 +01:00
hideInAnswer = mapping . hideInAnswer ;
2020-12-08 23:44:34 +01:00
} else if ( mapping . hideInAnswer !== undefined ) {
2021-08-07 23:11:34 +02:00
hideInAnswer = TagUtils . Tag ( mapping . hideInAnswer , ` ${ context } .mapping[ ${ i } ].hideInAnswer ` ) ;
2020-12-07 03:02:50 +01:00
}
2022-01-29 02:45:59 +01:00
let icon = undefined ;
2022-02-17 23:54:14 +01:00
let iconClass = "small"
if ( mapping . icon !== undefined ) {
if ( typeof mapping . icon === "string" && mapping . icon !== "" ) {
icon = mapping . icon
} else {
icon = mapping . icon [ "path" ]
iconClass = mapping . icon [ "class" ] ? ? iconClass
}
2022-01-29 02:45:59 +01:00
}
2021-02-20 16:48:42 +01:00
const mp = {
2021-10-26 22:53:27 +02:00
if : TagUtils . Tag ( mapping . if , ` ${ ctx } .if ` ) ,
ifnot : ( mapping . ifnot !== undefined ? TagUtils . Tag ( mapping . ifnot , ` ${ ctx } .ifnot ` ) : undefined ) ,
2021-10-28 00:13:18 +02:00
then : Translations.T ( mapping . then , ` ${ ctx } .then ` ) ,
2022-01-29 02:45:59 +01:00
hideInAnswer ,
icon ,
2022-02-17 23:54:14 +01:00
iconClass ,
2021-11-07 16:34:51 +01:00
addExtraTags : ( mapping . addExtraTags ? ? [ ] ) . map ( ( str , j ) = > TagUtils . SimpleTag ( str , ` ${ ctx } .addExtraTags[ ${ j } ] ` ) )
2020-10-27 01:01:34 +01:00
} ;
2021-02-20 16:48:42 +01:00
if ( this . question ) {
2021-03-14 01:40:35 +01:00
if ( hideInAnswer !== true && mp . if !== undefined && ! mp . if . isUsableAsAnswer ( ) ) {
2021-02-20 16:48:42 +01:00
throw ` ${ context } .mapping[ ${ i } ].if: This value cannot be used to answer a question, probably because it contains a regex or an OR. Either change it or set 'hideInAnswer' `
}
if ( hideInAnswer !== true && ! ( mp . ifnot ? . isUsableAsAnswer ( ) ? ? true ) ) {
throw ` ${ context } .mapping[ ${ i } ].ifnot: This value cannot be used to answer a question, probably because it contains a regex or an OR. Either change it or set 'hideInAnswer' `
}
}
return mp ;
2020-10-27 01:01:34 +01:00
} ) ;
}
if ( this . question && this . freeform ? . key === undefined && this . mappings === undefined ) {
2021-02-20 16:48:42 +01:00
throw ` ${ context } : A question is defined, but no mappings nor freeform (key) are. The question is ${ this . question . txt } at ${ context } `
2020-10-27 01:01:34 +01:00
}
2021-02-20 16:48:42 +01:00
2021-11-11 17:14:03 +01:00
if ( this . id === "questions" && this . render !== undefined ) {
for ( const ln in this . render . translations ) {
2021-12-05 02:06:14 +01:00
const txt : string = this . render . translations [ ln ]
if ( txt . indexOf ( "{questions}" ) >= 0 ) {
2021-11-11 17:14:03 +01:00
continue
}
throw ` ${ context } : The rendering for language ${ ln } does not contain {questions}. This is a bug, as this rendering should include exactly this to trigger those questions to be shown! `
}
2021-12-05 02:06:14 +01:00
if ( this . freeform ? . key !== undefined && this . freeform ? . key !== "questions" ) {
2021-11-12 01:44:13 +01:00
throw ` ${ context } : If the ID is questions to trigger a question box, the only valid freeform value is 'questions' as well. Set freeform to questions or remove the freeform all together `
}
2021-11-11 17:14:03 +01:00
}
2021-11-10 18:42:31 +01:00
if ( this . freeform ) {
2021-12-05 02:06:14 +01:00
if ( this . render === undefined ) {
2021-11-10 18:42:31 +01:00
throw ` ${ context } : Detected a freeform key without rendering... Key: ${ this . freeform . key } in ${ context } `
}
for ( const ln in this . render . translations ) {
2021-12-05 02:06:14 +01:00
const txt : string = this . render . translations [ ln ]
if ( txt === "" ) {
throw context + " Rendering for language " + ln + " is empty"
2021-11-10 18:42:31 +01:00
}
2021-12-05 02:06:14 +01:00
if ( txt . indexOf ( "{" + this . freeform . key + "}" ) >= 0 ) {
2021-11-10 18:42:31 +01:00
continue
}
2021-12-05 02:06:14 +01:00
if ( txt . indexOf ( "{" + this . freeform . key + ":" ) >= 0 ) {
2021-11-12 01:44:13 +01:00
continue
}
2021-12-05 02:06:14 +01:00
if ( txt . indexOf ( "{canonical(" + this . freeform . key + ")" ) >= 0 ) {
2021-11-10 18:42:31 +01:00
continue
}
2021-12-05 02:06:14 +01:00
if ( this . freeform . type === "opening_hours" && txt . indexOf ( "{opening_hours_table(" ) >= 0 ) {
2021-11-10 18:42:31 +01:00
continue
}
2021-12-05 02:06:14 +01:00
if ( this . freeform . type === "wikidata" && txt . indexOf ( "{wikipedia(" + this . freeform . key ) >= 0 ) {
2021-11-10 18:42:31 +01:00
continue
}
2021-12-05 02:06:14 +01:00
if ( this . freeform . key === "wikidata" && txt . indexOf ( "{wikipedia()" ) >= 0 ) {
2021-11-10 18:42:31 +01:00
continue
}
throw ` ${ context } : The rendering for language ${ ln } does not contain the freeform key { ${ this . freeform . key } }. This is a bug, as this rendering should show exactly this freeform key! \ nThe rendering is ${ txt } `
2021-12-05 02:06:14 +01:00
2021-11-10 18:42:31 +01:00
}
}
2021-03-31 15:50:29 +02:00
if ( this . render && this . question && this . freeform === undefined ) {
2021-03-26 00:14:17 +01:00
throw ` ${ context } : Detected a tagrendering which takes input without freeform key in ${ context } ; the question is ${ this . question . txt } `
2021-03-10 12:55:39 +01:00
}
2021-03-31 15:50:29 +02:00
if ( ! json . multiAnswer && this . mappings !== undefined && this . question !== undefined ) {
2021-03-14 01:40:35 +01:00
let keys = [ ]
2021-03-31 15:50:29 +02:00
for ( let i = 0 ; i < this . mappings . length ; i ++ ) {
2021-03-14 01:40:35 +01:00
const mapping = this . mappings [ i ] ;
2021-03-31 15:50:29 +02:00
if ( mapping . if === undefined ) {
2021-03-14 01:40:35 +01:00
throw ` ${ context } .mappings[ ${ i } ].if is undefined `
}
keys . push ( . . . mapping . if . usedKeys ( ) )
}
keys = Utils . Dedup ( keys )
2021-03-31 15:50:29 +02:00
for ( let i = 0 ; i < this . mappings . length ; i ++ ) {
2021-03-14 01:40:35 +01:00
const mapping = this . mappings [ i ] ;
2021-03-31 15:50:29 +02:00
if ( mapping . hideInAnswer ) {
2021-03-14 01:40:35 +01:00
continue
}
2021-03-31 15:50:29 +02:00
2021-03-14 01:40:35 +01:00
const usedKeys = mapping . if . usedKeys ( ) ;
for ( const expectedKey of keys ) {
2021-03-31 15:50:29 +02:00
if ( usedKeys . indexOf ( expectedKey ) < 0 ) {
2021-03-14 01:40:35 +01:00
const msg = ` ${ context } .mappings[ ${ i } ]: This mapping only defines values for ${ usedKeys . join ( ', ' ) } , but it should also give a value for ${ expectedKey } `
2021-03-14 20:14:51 +01:00
this . configuration_warnings . push ( msg )
2021-03-14 01:40:35 +01:00
}
}
}
}
2020-10-27 01:01:34 +01:00
2021-02-20 16:48:42 +01:00
if ( this . question !== undefined && json . multiAnswer ) {
2020-10-27 01:01:34 +01:00
if ( ( this . mappings ? . length ? ? 0 ) === 0 ) {
2021-02-20 16:48:42 +01:00
throw ` ${ context } MultiAnswer is set, but no mappings are defined `
}
let allKeys = [ ] ;
let allHaveIfNot = true ;
for ( const mapping of this . mappings ) {
if ( mapping . hideInAnswer ) {
continue ;
}
if ( mapping . ifnot === undefined ) {
allHaveIfNot = false ;
}
allKeys = allKeys . concat ( mapping . if . usedKeys ( ) ) ;
}
allKeys = Utils . Dedup ( allKeys ) ;
if ( allKeys . length > 1 && ! allHaveIfNot ) {
throw ` ${ context } : A multi-answer is defined, which generates values over multiple keys. Please define ifnot-tags too on every mapping `
2020-10-27 01:01:34 +01:00
}
}
}
2021-03-13 17:25:44 +01:00
/ * *
* Returns true if it is known or not shown , false if the question should be asked
* @constructor
* /
public IsKnown ( tags : any ) : boolean {
if ( this . condition &&
! this . condition . matchesProperties ( tags ) ) {
2021-11-10 18:42:31 +01:00
// Filtered away by the condition, so it is kindof known
2021-03-13 17:25:44 +01:00
return true ;
}
2021-03-31 15:50:29 +02:00
if ( this . multiAnswer ) {
2021-04-18 14:24:30 +02:00
for ( const m of this . mappings ? ? [ ] ) {
2021-03-31 15:50:29 +02:00
if ( TagUtils . MatchesMultiAnswer ( m . if , tags ) ) {
2021-03-13 17:25:44 +01:00
return true ;
}
}
const free = this . freeform ? . key
2021-03-31 15:50:29 +02:00
if ( free !== undefined ) {
2022-02-22 14:13:41 +01:00
const value = tags [ free ]
return value !== undefined && value !== ""
2021-03-13 17:25:44 +01:00
}
return false
}
if ( this . GetRenderValue ( tags ) !== undefined ) {
// This value is known and can be rendered
return true ;
}
return false ;
}
2021-11-07 16:34:51 +01:00
2021-06-14 02:39:23 +02:00
/ * *
* Gets all the render values . Will return multiple render values if 'multianswer' is enabled .
* The result will equal [ GetRenderValue ] if not 'multiAnswer'
* @param tags
* @constructor
* /
2022-02-17 23:54:14 +01:00
public GetRenderValues ( tags : any ) : { then : Translation , icon? : string , iconClass? : string } [ ] {
2021-06-22 00:29:07 +02:00
if ( ! this . multiAnswer ) {
2022-01-29 02:45:59 +01:00
return [ this . GetRenderValueWithImage ( tags ) ]
2021-06-14 02:39:23 +02:00
}
// 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
2022-03-14 20:45:17 +01:00
let freeformKeyDefined = this . freeform ? . key !== undefined ;
let usedFreeformValues = new Set < string > ( )
2021-06-14 02:39:23 +02:00
// We run over all the mappings first, to check if the mapping matches
2022-02-11 04:28:11 +01:00
const applicableMappings : { then : Translation , img? : string } [ ] = Utils . NoNull ( ( this . mappings ? ? [ ] ) ? . map ( mapping = > {
2021-06-14 02:39:23 +02:00
if ( mapping . if === undefined ) {
2022-01-29 02:45:59 +01:00
return mapping ;
2021-06-14 02:39:23 +02:00
}
if ( TagUtils . MatchesMultiAnswer ( mapping . if , tags ) ) {
2022-03-14 20:45:17 +01:00
if ( freeformKeyDefined && mapping . if . isUsableAsAnswer ( ) ) {
// THe freeform key is defined: what value does it use though?
// We mark the value to see if we have any leftovers
const value = mapping . if . asChange ( { } ) . find ( kv = > kv . k === this . freeform . key ) . v
usedFreeformValues . add ( value )
2021-06-14 02:39:23 +02:00
}
2022-01-29 02:45:59 +01:00
return mapping ;
2021-06-14 02:39:23 +02:00
}
return undefined ;
} ) )
2021-06-22 00:29:07 +02:00
2022-03-14 20:45:17 +01:00
if ( freeformKeyDefined && tags [ this . freeform . key ] !== undefined ) {
const freeformValues = tags [ this . freeform . key ] . split ( ";" )
const leftovers = freeformValues . filter ( v = > ! usedFreeformValues . has ( v ) )
for ( const leftover of leftovers ) {
2022-03-15 01:42:38 +01:00
applicableMappings . push ( { then :
this . render . replace ( "{" + this . freeform . key + "}" , leftover )
} )
2022-03-14 20:45:17 +01:00
}
2021-06-14 02:39:23 +02:00
}
2022-03-14 20:45:17 +01:00
2021-06-14 02:39:23 +02:00
return applicableMappings
}
2021-06-22 00:29:07 +02:00
2022-01-29 02:45:59 +01:00
public GetRenderValue ( tags : any , defltValue : any = undefined ) : Translation {
return this . GetRenderValueWithImage ( tags , defltValue ) . then
}
2022-02-11 04:28:11 +01:00
2020-10-27 01:01:34 +01:00
/ * *
* Gets the correct rendering value ( or undefined if not known )
2021-06-22 00:29:07 +02:00
* Not compatible with multiAnswer - use GetRenderValueS instead in that case
2020-10-27 01:01:34 +01:00
* @constructor
* /
2022-01-29 02:45:59 +01:00
public GetRenderValueWithImage ( tags : any , defltValue : any = undefined ) : { then : Translation , icon? : string } {
2020-10-27 01:01:34 +01:00
if ( this . mappings !== undefined && ! this . multiAnswer ) {
for ( const mapping of this . mappings ) {
if ( mapping . if === undefined ) {
2022-01-29 02:45:59 +01:00
return mapping ;
2020-10-27 01:01:34 +01:00
}
if ( mapping . if . matchesProperties ( tags ) ) {
2022-01-29 02:45:59 +01:00
return mapping ;
2020-10-27 01:01:34 +01:00
}
}
}
2022-01-29 02:45:59 +01:00
if ( this . id === "questions" ||
this . freeform ? . key === undefined ||
tags [ this . freeform . key ] !== undefined
) {
return { then : this.render }
2021-11-12 01:44:13 +01:00
}
2021-01-06 01:11:07 +01:00
2022-01-29 02:45:59 +01:00
return { then : defltValue } ;
2020-10-27 01:01:34 +01:00
}
2021-12-05 02:06:14 +01:00
/ * *
* Gets all translations that might be rendered in all languages
* USed for static analysis
* @constructor
* @private
* /
EnumerateTranslations ( ) : Translation [ ] {
const translations : Translation [ ] = [ ]
for ( const key in this ) {
2022-01-14 19:34:00 +01:00
if ( ! this . hasOwnProperty ( key ) ) {
2021-12-05 02:06:14 +01:00
continue ;
}
const o = this [ key ]
if ( o instanceof Translation ) {
translations . push ( o )
}
}
return translations ;
}
2022-01-14 19:34:00 +01:00
FreeformValues ( ) : { key : string , type ? : string , values? : string [ ] } {
try {
2021-08-07 23:11:34 +02:00
2022-01-14 19:34:00 +01:00
const key = this . freeform ? . key
2022-01-15 01:22:06 +01:00
const answerMappings = this . mappings ? . filter ( m = > m . hideInAnswer !== true )
2022-01-14 19:34:00 +01:00
if ( key === undefined ) {
2022-01-15 01:22:06 +01:00
let values : { k : string , v : string } [ ] [ ] = Utils . NoNull ( answerMappings ? . map ( m = > m . if . asChange ( { } ) ) ? ? [ ] )
2022-01-14 19:34:00 +01:00
if ( values . length === 0 ) {
return ;
}
const allKeys = values . map ( arr = > arr . map ( o = > o . k ) )
let common = allKeys [ 0 ] ;
for ( const keyset of allKeys ) {
common = common . filter ( item = > keyset . indexOf ( item ) >= 0 )
}
const commonKey = common [ 0 ]
if ( commonKey === undefined ) {
return undefined ;
}
return {
key : commonKey ,
values : Utils.NoNull ( values . map ( arr = > arr . filter ( item = > item . k === commonKey ) [ 0 ] ? . v ) )
}
}
2022-01-15 01:22:06 +01:00
let values = Utils . NoNull ( answerMappings ? . map ( m = > m . if . asChange ( { } ) . filter ( item = > item . k === key ) [ 0 ] ? . v ) ? ? [ ] )
2022-01-14 19:34:00 +01:00
if ( values . length === undefined ) {
values = undefined
}
return {
key ,
type : this . freeform . type ,
values
}
} catch ( e ) {
console . error ( "Could not create FreeformValues for tagrendering" , this . id )
return undefined
}
}
GenerateDocumentation ( ) : BaseUIElement {
let withRender : ( BaseUIElement | string ) [ ] = [ ] ;
if ( this . freeform ? . key !== undefined ) {
withRender = [
` This rendering asks information about the property ` ,
Link . OsmWiki ( this . freeform . key ) ,
` \ nThis is rendered with \` ${ this . render . txt } \` `
]
}
let mappings : BaseUIElement = undefined ;
if ( this . mappings !== undefined ) {
mappings = new List (
2022-01-15 01:22:06 +01:00
this . mappings . map ( m = > {
let txt = "**" + m . then . txt + "** corresponds with " + m . if . asHumanString ( true , false , { } ) ;
2022-01-26 21:40:38 +01:00
if ( m . hideInAnswer === true ) {
2022-01-15 01:22:06 +01:00
txt += "_This option cannot be chosen as answer_"
}
2022-01-26 21:40:38 +01:00
if ( m . ifnot !== undefined ) {
txt += "Unselecting this answer will add " + m . ifnot . asHumanString ( true , false , { } )
2022-01-15 01:22:06 +01:00
}
return txt ;
}
2022-01-14 19:34:00 +01:00
)
)
}
2022-04-08 01:55:42 +02:00
let condition : BaseUIElement = undefined
if ( this . condition !== undefined && ! this . condition ? . matchesProperties ( { } ) ) {
condition = new Combine ( [ "Only visible if" ,
new FixedUiElement ( this . condition . asHumanString ( false , false , { } )
) . SetClass ( "code" )
, "is shown" ] )
}
2022-01-14 19:34:00 +01:00
return new Combine ( [
new Title ( this . id , 3 ) ,
this . question !== undefined ? "The question is **" + this . question . txt + "**" : "_This tagrendering has no question and is thus read-only_" ,
new Combine ( withRender ) ,
2022-04-08 01:55:42 +02:00
mappings ,
condition
2022-01-14 19:34:00 +01:00
] ) . SetClass ( "flex-col" ) ;
}
2020-10-27 01:01:34 +01:00
}