forked from MapComplete/MapComplete
Feature: add 'onsoftDelete'-option for tagrenderings which will clear when a soft-delete is performed, apply this on pharmacies
This commit is contained in:
parent
34672075d4
commit
e5f0846edd
6 changed files with 186 additions and 102 deletions
|
@ -140,62 +140,15 @@
|
||||||
"pl": "Nazwa tej apteki to {name}",
|
"pl": "Nazwa tej apteki to {name}",
|
||||||
"es": "Esta farmacia se llama {name}",
|
"es": "Esta farmacia se llama {name}",
|
||||||
"uk": "Ця аптека називається {name}"
|
"uk": "Ця аптека називається {name}"
|
||||||
}
|
},
|
||||||
|
"onSoftDelete": [
|
||||||
|
"name="
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"opening_hours",
|
"opening_hours",
|
||||||
"contact",
|
"contact",
|
||||||
"payment-options",
|
"payment-options",
|
||||||
{
|
"wheelchair"
|
||||||
"id": "wheelchair",
|
|
||||||
"question": {
|
|
||||||
"en": "Is this pharmacy easy to access on a wheelchair?",
|
|
||||||
"de": "Ist die Apotheke für Rollstuhlfahrer leicht zugänglich?",
|
|
||||||
"nl": "Is het mogelijk om deze apotheek te bereiken met een rolstoel?",
|
|
||||||
"ca": "És fàcil accedir a aquesta farmàcia amb una cadira de rodes?",
|
|
||||||
"fr": "Cette pharmacie est-elle facilement accessible en chaise roulante ?",
|
|
||||||
"cs": "Je tato lékárna snadno přístupná na invalidním vozíku?",
|
|
||||||
"es": "¿Es esta farmacia de fácil acceso en silla de ruedas?"
|
|
||||||
},
|
|
||||||
"mappings": [
|
|
||||||
{
|
|
||||||
"if": "wheelchair=yes",
|
|
||||||
"then": {
|
|
||||||
"en": "This pharmacy is easy to access on a wheelchair",
|
|
||||||
"ca": "Aquesta farmàcia és fàcil d'accedir en una cadira de rodes",
|
|
||||||
"de": "Die Apotheke ist für Rollstuhlfahrer leicht zugänglich",
|
|
||||||
"nl": "Deze apotheek is makkelijk te bereiken met een rolstoel",
|
|
||||||
"fr": "Cette pharmacie est facile d'accès en chaise roulante",
|
|
||||||
"cs": "Tato lékárna je snadno přístupná na invalidním vozíku",
|
|
||||||
"pl": "Ta apteka jest łatwo dostępna na wózku",
|
|
||||||
"es": "Esta farmacia es de fácil acceso en silla de ruedas"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"if": "wheelchair=no",
|
|
||||||
"then": {
|
|
||||||
"en": "This pharmacy is hard to access on a wheelchair",
|
|
||||||
"de": "Die Apotheke ist für Rollstuhlfahrer nur schwer zugänglich",
|
|
||||||
"nl": "Deze apotheek is moeilijk te bereiken met een rolstoel",
|
|
||||||
"ca": "Aquesta farmàcia es difícil d'accedir amb una cadira de rodes",
|
|
||||||
"fr": "Cette pharmacie est difficilement accessible en chaise roulante",
|
|
||||||
"cs": "Tato lékárna je těžko přístupná na invalidním vozíku",
|
|
||||||
"es": "Esta farmacia es de difícil acceso en silla de ruedas"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"if": "wheelchair=limited",
|
|
||||||
"then": {
|
|
||||||
"en": "This pharmacy has limited access for wheelchair users",
|
|
||||||
"de": "Die Apotheke ist für Rollstuhlfahrer nur eingeschränkt zugänglich",
|
|
||||||
"nl": "Deze apotheek is bereikbaar met een rolstoel, maar het is niet makkelijk",
|
|
||||||
"ca": "Aquesta farmàcia té un accés limitat per a usuaris amb cadira de rodes",
|
|
||||||
"fr": "L'accès à cette pharmacie est limité en chaise roulante",
|
|
||||||
"cs": "Tato lékárna má omezený přístup pro vozíčkáře",
|
|
||||||
"es": "Esta farmacia tiene acceso limitado para usuarios de silla de ruedas"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"filter": [
|
"filter": [
|
||||||
{
|
{
|
||||||
|
@ -234,6 +187,13 @@
|
||||||
},
|
},
|
||||||
"open_now"
|
"open_now"
|
||||||
],
|
],
|
||||||
"deletion": true,
|
"deletion": {
|
||||||
|
"softDeletionTags": {
|
||||||
|
"and": [
|
||||||
|
"amenity=",
|
||||||
|
"fixme="
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"allowMove": true
|
"allowMove": true
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,7 +216,10 @@
|
||||||
"nl": "Pas telefoonnummer aan",
|
"nl": "Pas telefoonnummer aan",
|
||||||
"de": "Telefonnummer bearbeiten",
|
"de": "Telefonnummer bearbeiten",
|
||||||
"es": "Editar número de teléfono"
|
"es": "Editar número de teléfono"
|
||||||
}
|
},
|
||||||
|
"onSoftDelete": [
|
||||||
|
"phone="
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mastodon",
|
"id": "mastodon",
|
||||||
|
@ -234,7 +237,11 @@
|
||||||
"render": {
|
"render": {
|
||||||
"*": "{fediverse_link(contact:mastodon)}"
|
"*": "{fediverse_link(contact:mastodon)}"
|
||||||
},
|
},
|
||||||
"icon": "./assets/svg/mastodon.svg"
|
"icon": "./assets/svg/mastodon.svg",
|
||||||
|
"onSoftDelete": [
|
||||||
|
"contact:mastodon=",
|
||||||
|
"mastodon="
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "facebook",
|
"id": "facebook",
|
||||||
|
@ -263,7 +270,10 @@
|
||||||
"de": "<div class='subtle text-sm'>Facebook ist bekannt dafür, die psychische Gesundheit zu beeinträchtigen, die öffentliche Meinung zu manipulieren und Hass zu verursachen. Versuche, gesündere Alternativen zu nutzen.</div>",
|
"de": "<div class='subtle text-sm'>Facebook ist bekannt dafür, die psychische Gesundheit zu beeinträchtigen, die öffentliche Meinung zu manipulieren und Hass zu verursachen. Versuche, gesündere Alternativen zu nutzen.</div>",
|
||||||
"es": "<div class='subtle text-sm'>Se sabe que Facebook perjudica la salud mental, manipula la opinión pública y causa odio. Prueba alternativas más saludables</div>"
|
"es": "<div class='subtle text-sm'>Se sabe que Facebook perjudica la salud mental, manipula la opinión pública y causa odio. Prueba alternativas más saludables</div>"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"onSoftDelete": [
|
||||||
|
"contact:facebook="
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "osmlink",
|
"id": "osmlink",
|
||||||
|
@ -338,7 +348,11 @@
|
||||||
"nl": "Pas emailadres aan",
|
"nl": "Pas emailadres aan",
|
||||||
"de": "E-Mail Adresse bearbeiten",
|
"de": "E-Mail Adresse bearbeiten",
|
||||||
"es": "Editar dirección de correo electrónico"
|
"es": "Editar dirección de correo electrónico"
|
||||||
}
|
},
|
||||||
|
"onSoftDelete": [
|
||||||
|
"email=",
|
||||||
|
"contact:email="
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "website",
|
"id": "website",
|
||||||
|
@ -396,7 +410,11 @@
|
||||||
"de": "Webseite bearbeiten",
|
"de": "Webseite bearbeiten",
|
||||||
"pl": "Edytuj stronę internetową",
|
"pl": "Edytuj stronę internetową",
|
||||||
"es": "Editar sitio web"
|
"es": "Editar sitio web"
|
||||||
}
|
},
|
||||||
|
"onSoftDelete": [
|
||||||
|
"website=",
|
||||||
|
"contact:website="
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "wheelchair-access",
|
"id": "wheelchair-access",
|
||||||
|
@ -689,6 +707,9 @@
|
||||||
],
|
],
|
||||||
"filter": [
|
"filter": [
|
||||||
"filters.dogs"
|
"filters.dogs"
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"dog="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -820,6 +841,9 @@
|
||||||
],
|
],
|
||||||
"filter": [
|
"filter": [
|
||||||
"filters.open_now"
|
"filters.open_now"
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"opening_hours="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1003,6 +1027,9 @@
|
||||||
},
|
},
|
||||||
"if": "service:electricity=no"
|
"if": "service:electricity=no"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"service:electricity="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1108,6 +1135,12 @@
|
||||||
"filter": [
|
"filter": [
|
||||||
"filters.accepts_cash",
|
"filters.accepts_cash",
|
||||||
"filters.accepts_cards"
|
"filters.accepts_cards"
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"payment:cash=",
|
||||||
|
"payment:cards=",
|
||||||
|
"payment:payconiq=",
|
||||||
|
"payment:qr_code="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1189,6 +1222,11 @@
|
||||||
"cs": "Jsou zde přijímány kreditní karty"
|
"cs": "Jsou zde přijímány kreditní karty"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete+": [
|
||||||
|
"payment:coins=",
|
||||||
|
"payment:credit_cards=",
|
||||||
|
"payment:notes="
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1246,6 +1284,10 @@
|
||||||
"pl": "Płatność odbywa się za pomocą karty członkowskiej"
|
"pl": "Płatność odbywa się za pomocą karty członkowskiej"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete+": [
|
||||||
|
"payment:app=",
|
||||||
|
"payment:membership_card="
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1498,6 +1540,9 @@
|
||||||
},
|
},
|
||||||
"hideInAnswer": "_currency!~.*CHF.*"
|
"hideInAnswer": "_currency!~.*CHF.*"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"payment:coins:denominations="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1707,6 +1752,9 @@
|
||||||
},
|
},
|
||||||
"hideInAnswer": "_currency!~.*CHF.*"
|
"hideInAnswer": "_currency!~.*CHF.*"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"payment:notes:denominations="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1964,6 +2012,9 @@
|
||||||
"uk": "Розташований на першому підвальному поверсі"
|
"uk": "Розташований на першому підвальному поверсі"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"level="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2045,6 +2096,9 @@
|
||||||
"pl": "Palenie jest <b>dozwolone na zewnątrz</b>."
|
"pl": "Palenie jest <b>dozwolone na zewnątrz</b>."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"smoking="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2229,6 +2283,11 @@
|
||||||
],
|
],
|
||||||
"filter": [
|
"filter": [
|
||||||
"filters.has_internet"
|
"filters.has_internet"
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"internet=",
|
||||||
|
"internet_access:fee=",
|
||||||
|
"internet_access:ssid="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2310,6 +2369,11 @@
|
||||||
"uk": "Доступ до Інтернету в цьому місці безкоштовний тільки для клієнтів"
|
"uk": "Доступ до Інтернету в цьому місці безкоштовний тільки для клієнтів"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"internet=",
|
||||||
|
"internet_access:fee=",
|
||||||
|
"internet_access:ssid="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2372,7 +2436,12 @@
|
||||||
"ca": "El nom de la xarxa és <b>{internet_access:ssid}</b>",
|
"ca": "El nom de la xarxa és <b>{internet_access:ssid}</b>",
|
||||||
"pl": "Nazwa sieci to <b>{internet_access:ssid}</b>",
|
"pl": "Nazwa sieci to <b>{internet_access:ssid}</b>",
|
||||||
"uk": "Назва мережі: <b>{internet_access:ssid}</b>"
|
"uk": "Назва мережі: <b>{internet_access:ssid}</b>"
|
||||||
}
|
},
|
||||||
|
"onSoftDelete": [
|
||||||
|
"internet=",
|
||||||
|
"internet_access:fee=",
|
||||||
|
"internet_access:ssid="
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "luminous_or_lit",
|
"id": "luminous_or_lit",
|
||||||
|
@ -2579,6 +2648,9 @@
|
||||||
],
|
],
|
||||||
"filter": [
|
"filter": [
|
||||||
"filters.sugar_free"
|
"filters.sugar_free"
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"diet:suger_free="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2634,6 +2706,9 @@
|
||||||
],
|
],
|
||||||
"filter": [
|
"filter": [
|
||||||
"filters.lactose_free"
|
"filters.lactose_free"
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"diet:lactose_free="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2690,6 +2765,9 @@
|
||||||
],
|
],
|
||||||
"filter": [
|
"filter": [
|
||||||
"filters.gluten_free"
|
"filters.gluten_free"
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"diet:gluten_free="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2736,6 +2814,9 @@
|
||||||
"es": "Esta tienda no tiene oferta vegana"
|
"es": "Esta tienda no tiene oferta vegana"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"diet:vegan="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2965,6 +3046,9 @@
|
||||||
"es": "Cerrado durante el invierno"
|
"es": "Cerrado durante el invierno"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"seasonal="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3011,6 +3095,9 @@
|
||||||
"es": "Esta instalación no ofrece ducha"
|
"es": "Esta instalación no ofrece ducha"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"shower="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3053,6 +3140,9 @@
|
||||||
"uk": "Не є частиною великого бренду"
|
"uk": "Не є частиною великого бренду"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"onSoftDelete": [
|
||||||
|
"brand="
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3080,4 +3170,4 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"allowMove": false
|
"allowMove": false
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson"
|
||||||
import key_counts from "../../assets/key_totals.json"
|
import key_counts from "../../assets/key_totals.json"
|
||||||
|
|
||||||
import { ConversionContext } from "../../Models/ThemeConfig/Conversion/ConversionContext"
|
import { ConversionContext } from "../../Models/ThemeConfig/Conversion/ConversionContext"
|
||||||
import { TagsFilterClosed, UploadableTag } from "./TagTypes"
|
import { FlatTag, TagsFilterClosed, UploadableTag } from "./TagTypes"
|
||||||
|
|
||||||
type Tags = Record<string, string>
|
type Tags = Record<string, string>
|
||||||
|
|
||||||
|
@ -504,6 +504,14 @@ export class TagUtils {
|
||||||
* regex.matchesProperties({maxspeed: "50 mph"}) // => true
|
* regex.matchesProperties({maxspeed: "50 mph"}) // => true
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
public static Tag(
|
||||||
|
json: string,
|
||||||
|
context?: string | ConversionContext
|
||||||
|
): FlatTag;
|
||||||
|
public static Tag(
|
||||||
|
json: TagConfigJson,
|
||||||
|
context?: string | ConversionContext
|
||||||
|
): TagsFilterClosed;
|
||||||
public static Tag(
|
public static Tag(
|
||||||
json: TagConfigJson,
|
json: TagConfigJson,
|
||||||
context: string | ConversionContext = ""
|
context: string | ConversionContext = ""
|
||||||
|
|
|
@ -321,7 +321,7 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
|
||||||
editButtonAriaLabel?: Translatable
|
editButtonAriaLabel?: Translatable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What labels should be applied on this tagRendering?
|
* question: What labels should be applied on this tagRendering?
|
||||||
*
|
*
|
||||||
* A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer
|
* A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer
|
||||||
*
|
*
|
||||||
|
@ -330,4 +330,9 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
|
||||||
* - "description": this label is a description used in the search
|
* - "description": this label is a description used in the search
|
||||||
*/
|
*/
|
||||||
labels?: string[]
|
labels?: string[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* question: What tags should be applied when the object is soft-deleted?
|
||||||
|
*/
|
||||||
|
onSoftDelete?: string[]
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { Feature } from "geojson"
|
||||||
import MarkdownUtils from "../../Utils/MarkdownUtils"
|
import MarkdownUtils from "../../Utils/MarkdownUtils"
|
||||||
import { UploadableTag } from "../../Logic/Tags/TagTypes"
|
import { UploadableTag } from "../../Logic/Tags/TagTypes"
|
||||||
import LayerConfig from "./LayerConfig"
|
import LayerConfig from "./LayerConfig"
|
||||||
|
import ComparingTag from "../../Logic/Tags/ComparingTag"
|
||||||
|
|
||||||
export interface Mapping {
|
export interface Mapping {
|
||||||
readonly if: UploadableTag
|
readonly if: UploadableTag
|
||||||
|
@ -80,12 +81,14 @@ export default class TagRenderingConfig {
|
||||||
public readonly labels: string[]
|
public readonly labels: string[]
|
||||||
public readonly classes: string[] | undefined
|
public readonly classes: string[] | undefined
|
||||||
|
|
||||||
|
public readonly onSoftDelete?: ReadonlyArray<UploadableTag>
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
config:
|
config:
|
||||||
| string
|
| string
|
||||||
| TagRenderingConfigJson
|
| TagRenderingConfigJson
|
||||||
| (QuestionableTagRenderingConfigJson & { questionHintIsMd?: boolean }),
|
| (QuestionableTagRenderingConfigJson & { questionHintIsMd?: boolean }),
|
||||||
context?: string
|
context?: string,
|
||||||
) {
|
) {
|
||||||
let json = <string | QuestionableTagRenderingConfigJson>config
|
let json = <string | QuestionableTagRenderingConfigJson>config
|
||||||
if (json === undefined) {
|
if (json === undefined) {
|
||||||
|
@ -142,9 +145,22 @@ export default class TagRenderingConfig {
|
||||||
this.questionhint = Translations.T(json.questionHint, translationKey + ".questionHint")
|
this.questionhint = Translations.T(json.questionHint, translationKey + ".questionHint")
|
||||||
this.questionHintIsMd = json["questionHintIsMd"] ?? false
|
this.questionHintIsMd = json["questionHintIsMd"] ?? false
|
||||||
this.description = Translations.T(json.description, translationKey + ".description")
|
this.description = Translations.T(json.description, translationKey + ".description")
|
||||||
|
if(json.onSoftDelete && !Array.isArray(json.onSoftDelete)){
|
||||||
|
throw context+".onSoftDelete Not an array: "+typeof json.onSoftDelete
|
||||||
|
}
|
||||||
|
this.onSoftDelete = json.onSoftDelete?.map(t => {
|
||||||
|
const tag = TagUtils.Tag(t, context)
|
||||||
|
if (tag instanceof RegexTag) {
|
||||||
|
throw context+".onSoftDelete Invalid onSoftDelete: cannot upload tag " + t
|
||||||
|
}
|
||||||
|
if (tag instanceof ComparingTag) {
|
||||||
|
throw context+".onSoftDelete Invalid onSoftDelete: cannot upload tag " + t
|
||||||
|
}
|
||||||
|
return tag
|
||||||
|
})
|
||||||
this.editButtonAriaLabel = Translations.T(
|
this.editButtonAriaLabel = Translations.T(
|
||||||
json.editButtonAriaLabel,
|
json.editButtonAriaLabel,
|
||||||
translationKey + ".editButtonAriaLabel"
|
translationKey + ".editButtonAriaLabel",
|
||||||
)
|
)
|
||||||
|
|
||||||
this.condition = TagUtils.Tag(json.condition ?? { and: [] }, `${context}.condition`)
|
this.condition = TagUtils.Tag(json.condition ?? { and: [] }, `${context}.condition`)
|
||||||
|
@ -160,7 +176,7 @@ export default class TagRenderingConfig {
|
||||||
}
|
}
|
||||||
this.metacondition = TagUtils.Tag(
|
this.metacondition = TagUtils.Tag(
|
||||||
json.metacondition ?? { and: [] },
|
json.metacondition ?? { and: [] },
|
||||||
`${context}.metacondition`
|
`${context}.metacondition`,
|
||||||
)
|
)
|
||||||
if (json.freeform) {
|
if (json.freeform) {
|
||||||
if (
|
if (
|
||||||
|
@ -178,7 +194,7 @@ export default class TagRenderingConfig {
|
||||||
}, perhaps you meant ${Utils.sortedByLevenshteinDistance(
|
}, perhaps you meant ${Utils.sortedByLevenshteinDistance(
|
||||||
json.freeform.key,
|
json.freeform.key,
|
||||||
<any>Validators.availableTypes,
|
<any>Validators.availableTypes,
|
||||||
(s) => <any>s
|
(s) => <any>s,
|
||||||
)}`
|
)}`
|
||||||
}
|
}
|
||||||
const type: ValidatorType = <any>json.freeform.type ?? "string"
|
const type: ValidatorType = <any>json.freeform.type ?? "string"
|
||||||
|
@ -200,7 +216,7 @@ export default class TagRenderingConfig {
|
||||||
placeholder,
|
placeholder,
|
||||||
addExtraTags:
|
addExtraTags:
|
||||||
json.freeform.addExtraTags?.map((tg, i) =>
|
json.freeform.addExtraTags?.map((tg, i) =>
|
||||||
TagUtils.ParseUploadableTag(tg, `${context}.extratag[${i}]`)
|
TagUtils.ParseUploadableTag(tg, `${context}.extratag[${i}]`),
|
||||||
) ?? [],
|
) ?? [],
|
||||||
inline: json.freeform.inline ?? false,
|
inline: json.freeform.inline ?? false,
|
||||||
default: json.freeform.default,
|
default: json.freeform.default,
|
||||||
|
@ -266,8 +282,8 @@ export default class TagRenderingConfig {
|
||||||
context,
|
context,
|
||||||
this.multiAnswer,
|
this.multiAnswer,
|
||||||
this.question !== undefined,
|
this.question !== undefined,
|
||||||
commonIconSize
|
commonIconSize,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
this.mappings = []
|
this.mappings = []
|
||||||
|
@ -293,7 +309,7 @@ export default class TagRenderingConfig {
|
||||||
for (const expectedKey of keys) {
|
for (const expectedKey of keys) {
|
||||||
if (usedKeys.indexOf(expectedKey) < 0) {
|
if (usedKeys.indexOf(expectedKey) < 0) {
|
||||||
const msg = `${context}.mappings[${i}]: This mapping only defines values for ${usedKeys.join(
|
const msg = `${context}.mappings[${i}]: This mapping only defines values for ${usedKeys.join(
|
||||||
", "
|
", ",
|
||||||
)}, but it should also give a value for ${expectedKey}`
|
)}, but it should also give a value for ${expectedKey}`
|
||||||
this.configuration_warnings.push(msg)
|
this.configuration_warnings.push(msg)
|
||||||
}
|
}
|
||||||
|
@ -340,7 +356,7 @@ export default class TagRenderingConfig {
|
||||||
context: string,
|
context: string,
|
||||||
multiAnswer?: boolean,
|
multiAnswer?: boolean,
|
||||||
isQuestionable?: boolean,
|
isQuestionable?: boolean,
|
||||||
commonSize: string = "small"
|
commonSize: string = "small",
|
||||||
): Mapping {
|
): Mapping {
|
||||||
const ctx = `${translationKey}.mappings.${i}`
|
const ctx = `${translationKey}.mappings.${i}`
|
||||||
if (mapping.if === undefined) {
|
if (mapping.if === undefined) {
|
||||||
|
@ -349,7 +365,7 @@ export default class TagRenderingConfig {
|
||||||
if (mapping.then === undefined) {
|
if (mapping.then === undefined) {
|
||||||
if (mapping["render"] !== undefined) {
|
if (mapping["render"] !== undefined) {
|
||||||
throw `${ctx}: Invalid mapping: no 'then'-clause found. You might have typed 'render' instead of 'then', change it in ${JSON.stringify(
|
throw `${ctx}: Invalid mapping: no 'then'-clause found. You might have typed 'render' instead of 'then', change it in ${JSON.stringify(
|
||||||
mapping
|
mapping,
|
||||||
)}`
|
)}`
|
||||||
}
|
}
|
||||||
throw `${ctx}: Invalid mapping: no 'then'-clause found in ${JSON.stringify(mapping)}`
|
throw `${ctx}: Invalid mapping: no 'then'-clause found in ${JSON.stringify(mapping)}`
|
||||||
|
@ -360,7 +376,7 @@ export default class TagRenderingConfig {
|
||||||
|
|
||||||
if (mapping["render"] !== undefined) {
|
if (mapping["render"] !== undefined) {
|
||||||
throw `${ctx}: Invalid mapping: a 'render'-key is present, this is probably a bug: ${JSON.stringify(
|
throw `${ctx}: Invalid mapping: a 'render'-key is present, this is probably a bug: ${JSON.stringify(
|
||||||
mapping
|
mapping,
|
||||||
)}`
|
)}`
|
||||||
}
|
}
|
||||||
if (typeof mapping.if !== "string" && mapping.if["length"] !== undefined) {
|
if (typeof mapping.if !== "string" && mapping.if["length"] !== undefined) {
|
||||||
|
@ -371,8 +387,8 @@ export default class TagRenderingConfig {
|
||||||
throw `${ctx}.addExtraTags: expected a list, but got a ${typeof mapping.addExtraTags}`
|
throw `${ctx}.addExtraTags: expected a list, but got a ${typeof mapping.addExtraTags}`
|
||||||
}
|
}
|
||||||
if (mapping.addExtraTags !== undefined && multiAnswer) {
|
if (mapping.addExtraTags !== undefined && multiAnswer) {
|
||||||
const usedKeys = mapping.addExtraTags?.flatMap((et) => TagUtils.Tag(et).usedKeys())
|
const usedKeys = mapping.addExtraTags?.flatMap((et) => TagUtils.Tag(et, context).usedKeys())
|
||||||
if (usedKeys.some((key) => TagUtils.Tag(mapping.if).usedKeys().indexOf(key) > 0)) {
|
if (usedKeys.some((key) => TagUtils.Tag(mapping.if, context).usedKeys().indexOf(key) > 0)) {
|
||||||
throw `${ctx}: Invalid mapping: got a multi-Answer with addExtraTags which also modifies one of the keys; this is not allowed`
|
throw `${ctx}: Invalid mapping: got a multi-Answer with addExtraTags which also modifies one of the keys; this is not allowed`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -383,11 +399,11 @@ export default class TagRenderingConfig {
|
||||||
} else if (mapping.hideInAnswer !== undefined) {
|
} else if (mapping.hideInAnswer !== undefined) {
|
||||||
hideInAnswer = TagUtils.Tag(
|
hideInAnswer = TagUtils.Tag(
|
||||||
mapping.hideInAnswer,
|
mapping.hideInAnswer,
|
||||||
`${context}.mapping[${i}].hideInAnswer`
|
`${context}.mapping[${i}].hideInAnswer`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const addExtraTags = (mapping.addExtraTags ?? []).map((str, j) =>
|
const addExtraTags = (mapping.addExtraTags ?? []).map((str, j) =>
|
||||||
TagUtils.SimpleTag(str, `${ctx}.addExtraTags[${j}]`)
|
TagUtils.SimpleTag(str, `${ctx}.addExtraTags[${j}]`),
|
||||||
)
|
)
|
||||||
if (hideInAnswer === true && addExtraTags.length > 0) {
|
if (hideInAnswer === true && addExtraTags.length > 0) {
|
||||||
throw `${ctx}: Invalid mapping: 'hideInAnswer' is set to 'true', but 'addExtraTags' is enabled as well. This means that extra tags will be applied if this mapping is chosen as answer, but it cannot be chosen as answer. This either indicates a thought error or obsolete code that must be removed.`
|
throw `${ctx}: Invalid mapping: 'hideInAnswer' is set to 'true', but 'addExtraTags' is enabled as well. This means that extra tags will be applied if this mapping is chosen as answer, but it cannot be chosen as answer. This either indicates a thought error or obsolete code that must be removed.`
|
||||||
|
@ -483,7 +499,7 @@ export default class TagRenderingConfig {
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
public GetRenderValues(
|
public GetRenderValues(
|
||||||
tags: Record<string, string>
|
tags: Record<string, string>,
|
||||||
): { then: Translation; icon?: string; iconClass?: string }[] {
|
): { then: Translation; icon?: string; iconClass?: string }[] {
|
||||||
if (!this.multiAnswer) {
|
if (!this.multiAnswer) {
|
||||||
return [this.GetRenderValueWithImage(tags)]
|
return [this.GetRenderValueWithImage(tags)]
|
||||||
|
@ -506,7 +522,7 @@ export default class TagRenderingConfig {
|
||||||
return mapping
|
return mapping
|
||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (freeformKeyDefined && tags[this.freeform.key] !== undefined) {
|
if (freeformKeyDefined && tags[this.freeform.key] !== undefined) {
|
||||||
|
@ -514,7 +530,7 @@ export default class TagRenderingConfig {
|
||||||
applicableMappings
|
applicableMappings
|
||||||
?.flatMap((m) => m.if?.usedTags() ?? [])
|
?.flatMap((m) => m.if?.usedTags() ?? [])
|
||||||
?.filter((kv) => kv.key === this.freeform.key)
|
?.filter((kv) => kv.key === this.freeform.key)
|
||||||
?.map((kv) => kv.value)
|
?.map((kv) => kv.value),
|
||||||
)
|
)
|
||||||
|
|
||||||
const freeformValues = tags[this.freeform.key].split(";")
|
const freeformValues = tags[this.freeform.key].split(";")
|
||||||
|
@ -523,7 +539,7 @@ export default class TagRenderingConfig {
|
||||||
applicableMappings.push({
|
applicableMappings.push({
|
||||||
then: new TypedTranslation<object>(
|
then: new TypedTranslation<object>(
|
||||||
this.render.replace("{" + this.freeform.key + "}", leftover).translations,
|
this.render.replace("{" + this.freeform.key + "}", leftover).translations,
|
||||||
this.render.context
|
this.render.context,
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -541,7 +557,7 @@ export default class TagRenderingConfig {
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
public GetRenderValueWithImage(
|
public GetRenderValueWithImage(
|
||||||
tags: Record<string, string>
|
tags: Record<string, string>,
|
||||||
): { then: TypedTranslation<any>; icon?: string; iconClass?: string } | undefined {
|
): { then: TypedTranslation<any>; icon?: string; iconClass?: string } | undefined {
|
||||||
if (this.condition !== undefined) {
|
if (this.condition !== undefined) {
|
||||||
if (!this.condition.matchesProperties(tags)) {
|
if (!this.condition.matchesProperties(tags)) {
|
||||||
|
@ -610,7 +626,7 @@ export default class TagRenderingConfig {
|
||||||
const answerMappings = this.mappings?.filter((m) => m.hideInAnswer !== true)
|
const answerMappings = this.mappings?.filter((m) => m.hideInAnswer !== true)
|
||||||
if (key === undefined) {
|
if (key === undefined) {
|
||||||
const values: { k: string; v: string }[][] = Utils.NoNull(
|
const values: { k: string; v: string }[][] = Utils.NoNull(
|
||||||
answerMappings?.map((m) => m.if.asChange({})) ?? []
|
answerMappings?.map((m) => m.if.asChange({})) ?? [],
|
||||||
)
|
)
|
||||||
if (values.length === 0) {
|
if (values.length === 0) {
|
||||||
return
|
return
|
||||||
|
@ -628,15 +644,15 @@ export default class TagRenderingConfig {
|
||||||
return {
|
return {
|
||||||
key: commonKey,
|
key: commonKey,
|
||||||
values: Utils.NoNull(
|
values: Utils.NoNull(
|
||||||
values.map((arr) => arr.filter((item) => item.k === commonKey)[0]?.v)
|
values.map((arr) => arr.filter((item) => item.k === commonKey)[0]?.v),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let values = Utils.NoNull(
|
let values = Utils.NoNull(
|
||||||
answerMappings?.map(
|
answerMappings?.map(
|
||||||
(m) => m.if.asChange({}).filter((item) => item.k === key)[0]?.v
|
(m) => m.if.asChange({}).filter((item) => item.k === key)[0]?.v,
|
||||||
) ?? []
|
) ?? [],
|
||||||
)
|
)
|
||||||
if (values.length === undefined) {
|
if (values.length === undefined) {
|
||||||
values = undefined
|
values = undefined
|
||||||
|
@ -700,7 +716,7 @@ export default class TagRenderingConfig {
|
||||||
freeformValue: string | undefined,
|
freeformValue: string | undefined,
|
||||||
singleSelectedMapping: number,
|
singleSelectedMapping: number,
|
||||||
multiSelectedMapping: boolean[] | undefined,
|
multiSelectedMapping: boolean[] | undefined,
|
||||||
currentProperties: Record<string, string>
|
currentProperties: Record<string, string>,
|
||||||
): UploadableTag {
|
): UploadableTag {
|
||||||
if (typeof freeformValue === "string") {
|
if (typeof freeformValue === "string") {
|
||||||
freeformValue = freeformValue?.trim()
|
freeformValue = freeformValue?.trim()
|
||||||
|
@ -775,7 +791,7 @@ export default class TagRenderingConfig {
|
||||||
new And([
|
new And([
|
||||||
new Tag(this.freeform.key, freeformValue),
|
new Tag(this.freeform.key, freeformValue),
|
||||||
...(this.freeform.addExtraTags ?? []),
|
...(this.freeform.addExtraTags ?? []),
|
||||||
])
|
]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const and = TagUtils.FlattenMultiAnswer([...selectedMappings, ...unselectedMappings])
|
const and = TagUtils.FlattenMultiAnswer([...selectedMappings, ...unselectedMappings])
|
||||||
|
@ -845,11 +861,11 @@ export default class TagRenderingConfig {
|
||||||
}
|
}
|
||||||
const msgs: string[] = [
|
const msgs: string[] = [
|
||||||
icon +
|
icon +
|
||||||
" " +
|
" " +
|
||||||
"*" +
|
"*" +
|
||||||
m.then.textFor(lang) +
|
m.then.textFor(lang) +
|
||||||
"* is shown if with " +
|
"* is shown if with " +
|
||||||
m.if.asHumanString(true, false, {}),
|
m.if.asHumanString(true, false, {}),
|
||||||
]
|
]
|
||||||
|
|
||||||
if (m.hideInAnswer === true) {
|
if (m.hideInAnswer === true) {
|
||||||
|
@ -858,11 +874,11 @@ export default class TagRenderingConfig {
|
||||||
if (m.ifnot !== undefined) {
|
if (m.ifnot !== undefined) {
|
||||||
msgs.push(
|
msgs.push(
|
||||||
"Unselecting this answer will add " +
|
"Unselecting this answer will add " +
|
||||||
m.ifnot.asHumanString(true, false, {})
|
m.ifnot.asHumanString(true, false, {}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return msgs.join(". ")
|
return msgs.join(". ")
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -871,7 +887,7 @@ export default class TagRenderingConfig {
|
||||||
const conditionAsLink = (<TagsFilter>this.condition.optimize()).asHumanString(
|
const conditionAsLink = (<TagsFilter>this.condition.optimize()).asHumanString(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
{}
|
{},
|
||||||
)
|
)
|
||||||
condition =
|
condition =
|
||||||
"This tagrendering is only visible in the popup if the following condition is met: " +
|
"This tagrendering is only visible in the popup if the following condition is met: " +
|
||||||
|
@ -905,7 +921,7 @@ export default class TagRenderingConfig {
|
||||||
this.metacondition,
|
this.metacondition,
|
||||||
this.condition,
|
this.condition,
|
||||||
this.freeform?.key ? new RegexTag(this.freeform?.key, /.*/) : undefined,
|
this.freeform?.key ? new RegexTag(this.freeform?.key, /.*/) : undefined,
|
||||||
this.invalidValues
|
this.invalidValues,
|
||||||
)
|
)
|
||||||
for (const m of this.mappings ?? []) {
|
for (const m of this.mappings ?? []) {
|
||||||
tags.push(m.if)
|
tags.push(m.if)
|
||||||
|
@ -927,7 +943,7 @@ export default class TagRenderingConfig {
|
||||||
*/
|
*/
|
||||||
public removeToSetUnknown(
|
public removeToSetUnknown(
|
||||||
partOfLayer: LayerConfig,
|
partOfLayer: LayerConfig,
|
||||||
currentTags: Record<string, string>
|
currentTags: Record<string, string>,
|
||||||
): string[] | undefined {
|
): string[] | undefined {
|
||||||
if (!partOfLayer?.source || !currentTags) {
|
if (!partOfLayer?.source || !currentTags) {
|
||||||
return
|
return
|
||||||
|
@ -975,7 +991,7 @@ export class TagRenderingConfigUtils {
|
||||||
public static withNameSuggestionIndex(
|
public static withNameSuggestionIndex(
|
||||||
config: TagRenderingConfig,
|
config: TagRenderingConfig,
|
||||||
tags: UIEventSource<Record<string, string>>,
|
tags: UIEventSource<Record<string, string>>,
|
||||||
feature?: Feature
|
feature?: Feature,
|
||||||
): Store<TagRenderingConfig> {
|
): Store<TagRenderingConfig> {
|
||||||
const isNSI = NameSuggestionIndex.supportedTypes().indexOf(config.freeform?.key) >= 0
|
const isNSI = NameSuggestionIndex.supportedTypes().indexOf(config.freeform?.key) >= 0
|
||||||
if (!isNSI) {
|
if (!isNSI) {
|
||||||
|
@ -993,8 +1009,8 @@ export class TagRenderingConfigUtils {
|
||||||
tags,
|
tags,
|
||||||
country.split(";"),
|
country.split(";"),
|
||||||
center,
|
center,
|
||||||
{ sortByFrequency: true }
|
{ sortByFrequency: true },
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
return extraMappings.map((extraMappings) => {
|
return extraMappings.map((extraMappings) => {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
import AccordionSingle from "../../Flowbite/AccordionSingle.svelte"
|
import AccordionSingle from "../../Flowbite/AccordionSingle.svelte"
|
||||||
import Trash from "@babeard/svelte-heroicons/mini/Trash"
|
import Trash from "@babeard/svelte-heroicons/mini/Trash"
|
||||||
import Invalid from "../../../assets/svg/Invalid.svelte"
|
import Invalid from "../../../assets/svg/Invalid.svelte"
|
||||||
|
import { And } from "../../../Logic/Tags/And"
|
||||||
|
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
export let deleteConfig: DeleteConfig
|
export let deleteConfig: DeleteConfig
|
||||||
|
@ -60,10 +61,14 @@
|
||||||
const changedProperties = TagUtils.changeAsProperties(selectedTags.asChange(tags?.data ?? {}))
|
const changedProperties = TagUtils.changeAsProperties(selectedTags.asChange(tags?.data ?? {}))
|
||||||
const deleteReason = changedProperties[DeleteConfig.deleteReasonKey]
|
const deleteReason = changedProperties[DeleteConfig.deleteReasonKey]
|
||||||
if (deleteReason) {
|
if (deleteReason) {
|
||||||
|
const softDeletionTags= new And([deleteConfig.softDeletionTags,
|
||||||
|
...layer.tagRenderings.flatMap(tr => tr.onSoftDelete ?? [])
|
||||||
|
])
|
||||||
|
|
||||||
// This is a proper, hard deletion
|
// This is a proper, hard deletion
|
||||||
actionToTake = new DeleteAction(
|
actionToTake = new DeleteAction(
|
||||||
featureId,
|
featureId,
|
||||||
deleteConfig.softDeletionTags,
|
softDeletionTags,
|
||||||
{
|
{
|
||||||
theme: state?.theme?.id ?? "unknown",
|
theme: state?.theme?.id ?? "unknown",
|
||||||
specialMotivation: deleteReason,
|
specialMotivation: deleteReason,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue