Themes: add label support to questions.json; add opening hours for hospitals

This commit is contained in:
Pieter Vander Vennet 2023-05-23 00:34:26 +02:00
parent 151e648616
commit 41fdeb9cb5
4 changed files with 93 additions and 68 deletions

View file

@ -1,30 +1,18 @@
import { import {Concat, Conversion, DesugaringContext, DesugaringStep, Each, FirstOf, Fuse, On, SetDefault,} from "./Conversion"
Concat, import {LayerConfigJson} from "../Json/LayerConfigJson"
Conversion, import {TagRenderingConfigJson} from "../Json/TagRenderingConfigJson"
DesugaringContext, import {Utils} from "../../../Utils"
DesugaringStep,
Each,
FirstOf,
Fuse,
On,
SetDefault,
} from "./Conversion"
import { LayerConfigJson } from "../Json/LayerConfigJson"
import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
import { Utils } from "../../../Utils"
import RewritableConfigJson from "../Json/RewritableConfigJson" import RewritableConfigJson from "../Json/RewritableConfigJson"
import SpecialVisualizations from "../../../UI/SpecialVisualizations" import SpecialVisualizations from "../../../UI/SpecialVisualizations"
import Translations from "../../../UI/i18n/Translations" import Translations from "../../../UI/i18n/Translations"
import { Translation } from "../../../UI/i18n/Translation" import {Translation} from "../../../UI/i18n/Translation"
import tagrenderingconfigmeta from "../../../assets/tagrenderingconfigmeta.json" import tagrenderingconfigmeta from "../../../assets/tagrenderingconfigmeta.json"
import { AddContextToTranslations } from "./AddContextToTranslations" import {AddContextToTranslations} from "./AddContextToTranslations"
import FilterConfigJson from "../Json/FilterConfigJson" import FilterConfigJson from "../Json/FilterConfigJson"
import predifined_filters from "../../../assets/layers/filters/filters.json" import predifined_filters from "../../../assets/layers/filters/filters.json"
import { TagConfigJson } from "../Json/TagConfigJson" import {TagConfigJson} from "../Json/TagConfigJson"
import PointRenderingConfigJson from "../Json/PointRenderingConfigJson" import PointRenderingConfigJson from "../Json/PointRenderingConfigJson"
import LineRenderingConfigJson from "../Json/LineRenderingConfigJson" import LineRenderingConfigJson from "../Json/LineRenderingConfigJson"
import { type } from "os"
import exp from "constants"
class ExpandFilter extends DesugaringStep<LayerConfigJson> { class ExpandFilter extends DesugaringStep<LayerConfigJson> {
private static readonly predefinedFilters = ExpandFilter.load_filters() private static readonly predefinedFilters = ExpandFilter.load_filters()
@ -52,11 +40,11 @@ class ExpandFilter extends DesugaringStep<LayerConfigJson> {
context: string context: string
): { result: LayerConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } { ): { result: LayerConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } {
if (json.filter === undefined || json.filter === null) { if (json.filter === undefined || json.filter === null) {
return { result: json } // Nothing to change here return {result: json} // Nothing to change here
} }
if (json.filter["sameAs"] !== undefined) { if (json.filter["sameAs"] !== undefined) {
return { result: json } // Nothing to change here return {result: json} // Nothing to change here
} }
const newFilters: FilterConfigJson[] = [] const newFilters: FilterConfigJson[] = []
@ -72,9 +60,9 @@ class ExpandFilter extends DesugaringStep<LayerConfigJson> {
if (split.length > 2) { if (split.length > 2) {
errors.push( errors.push(
context + context +
": invalid filter name: " + ": invalid filter name: " +
filter + filter +
", expected `layername.filterid`" ", expected `layername.filterid`"
) )
} }
const layer = this._state.sharedLayers.get(split[0]) const layer = this._state.sharedLayers.get(split[0])
@ -124,6 +112,7 @@ class ExpandTagRendering extends Conversion<
TagRenderingConfigJson[] TagRenderingConfigJson[]
> { > {
private readonly _state: DesugaringContext private readonly _state: DesugaringContext
private readonly _tagRenderingsByLabel: Map<string, TagRenderingConfigJson[]>
private readonly _self: LayerConfigJson private readonly _self: LayerConfigJson
private readonly _options: { private readonly _options: {
/* If true, will copy the 'osmSource'-tags into the condition */ /* If true, will copy the 'osmSource'-tags into the condition */
@ -144,6 +133,17 @@ class ExpandTagRendering extends Conversion<
this._state = state this._state = state
this._self = self this._self = self
this._options = options this._options = options
this._tagRenderingsByLabel = new Map<string, TagRenderingConfigJson[]>()
for (const trconfig of state.tagRenderings.values()) {
for (const label of trconfig.labels ?? []) {
let withLabel = this._tagRenderingsByLabel.get(label)
if (withLabel === undefined) {
withLabel = []
this._tagRenderingsByLabel.set(label, withLabel)
}
withLabel.push(trconfig)
}
}
} }
convert( convert(
@ -161,14 +161,16 @@ class ExpandTagRendering extends Conversion<
} }
private lookup(name: string): TagRenderingConfigJson[] | undefined { private lookup(name: string): TagRenderingConfigJson[] | undefined {
const direct = this.directLookup(name) const direct = this.directLookup(name)
if (direct === undefined) { if (direct === undefined) {
return undefined return undefined
} }
const result: TagRenderingConfigJson[] = [] const result: TagRenderingConfigJson[] = []
for (const tagRenderingConfigJson of direct) { for (const tagRenderingConfigJson of direct) {
if (tagRenderingConfigJson["builtin"] !== undefined) { let nm: string | string[] | undefined = tagRenderingConfigJson["builtin"]
let nm: string | string[] = tagRenderingConfigJson["builtin"] if (nm !== undefined) {
let indirect: TagRenderingConfigJson[] let indirect: TagRenderingConfigJson[]
if (typeof nm === "string") { if (typeof nm === "string") {
indirect = this.lookup(nm) indirect = this.lookup(nm)
@ -196,6 +198,10 @@ class ExpandTagRendering extends Conversion<
if (state.tagRenderings.has(name)) { if (state.tagRenderings.has(name)) {
return [state.tagRenderings.get(name)] return [state.tagRenderings.get(name)]
} }
if(this._tagRenderingsByLabel.has(name)){
return this._tagRenderingsByLabel.get(name)
}
if (name.indexOf(".") < 0) { if (name.indexOf(".") < 0) {
return undefined return undefined
} }
@ -233,7 +239,7 @@ class ExpandTagRendering extends Conversion<
if (found.condition === undefined) { if (found.condition === undefined) {
found.condition = layer.source.osmTags found.condition = layer.source.osmTags
} else { } else {
found.condition = { and: [found.condition, layer.source.osmTags] } found.condition = {and: [found.condition, layer.source.osmTags]}
} }
} }
@ -270,18 +276,18 @@ class ExpandTagRendering extends Conversion<
warnings.push( warnings.push(
`${ctx}: A literal rendering was detected: ${tr} `${ctx}: A literal rendering was detected: ${tr}
Did you perhaps forgot to add a layer name as 'layername.${tr}'? ` + Did you perhaps forgot to add a layer name as 'layername.${tr}'? ` +
Array.from(state.sharedLayers.keys()).join(", ") Array.from(state.sharedLayers.keys()).join(", ")
) )
} }
if (this._options?.noHardcodedStrings && this._state.sharedLayers.size > 0) { if (this._options?.noHardcodedStrings && this._state.sharedLayers.size > 0) {
errors.push( errors.push(
ctx + ctx +
"Detected an invocation to a builtin tagRendering, but this tagrendering was not found: " + "Detected an invocation to a builtin tagRendering, but this tagrendering was not found: " +
tr + tr +
" \n Did you perhaps forget to add the layer as prefix, such as `icons." + " \n Did you perhaps forget to add the layer as prefix, such as `icons." +
tr + tr +
"`? " "`? "
) )
} }
@ -312,11 +318,11 @@ class ExpandTagRendering extends Conversion<
} }
errors.push( errors.push(
"At " + "At " +
ctx + ctx +
": an object calling a builtin can only have keys `builtin` or `override`, but a key with name `" + ": an object calling a builtin can only have keys `builtin` or `override`, but a key with name `" +
key + key +
"` was found. This won't be picked up! The full object is: " + "` was found. This won't be picked up! The full object is: " +
JSON.stringify(tr) JSON.stringify(tr)
) )
} }
@ -340,22 +346,22 @@ class ExpandTagRendering extends Conversion<
if (state.sharedLayers.size === 0) { if (state.sharedLayers.size === 0) {
warnings.push( warnings.push(
ctx + ctx +
": BOOTSTRAPPING. Rerun generate layeroverview. While reusing tagrendering: " + ": BOOTSTRAPPING. Rerun generate layeroverview. While reusing tagrendering: " +
name + name +
": layer " + ": layer " +
layerName + layerName +
" not found. Maybe you meant on of " + " not found. Maybe you meant on of " +
candidates.slice(0, 3).join(", ") candidates.slice(0, 3).join(", ")
) )
} else { } else {
errors.push( errors.push(
ctx + ctx +
": While reusing tagrendering: " + ": While reusing tagrendering: " +
name + name +
": layer " + ": layer " +
layerName + layerName +
" not found. Maybe you meant on of " + " not found. Maybe you meant on of " +
candidates.slice(0, 3).join(", ") candidates.slice(0, 3).join(", ")
) )
} }
continue continue
@ -367,11 +373,11 @@ class ExpandTagRendering extends Conversion<
candidates = Utils.sortedByLevenshteinDistance(name, candidates, (i) => i) candidates = Utils.sortedByLevenshteinDistance(name, candidates, (i) => i)
errors.push( errors.push(
ctx + ctx +
": The tagRendering with identifier " + ": The tagRendering with identifier " +
name + name +
" was not found.\n\tDid you mean one of " + " was not found.\n\tDid you mean one of " +
candidates.join(", ") + candidates.join(", ") +
"?\n(Hint: did you add a new label and are you trying to use this label at the same time? Run 'reset:layeroverview' first" "?\n(Hint: did you add a new label and are you trying to use this label at the same time? Run 'reset:layeroverview' first"
) )
continue continue
} }
@ -457,7 +463,7 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[
} }
if (typeof obj === "object") { if (typeof obj === "object") {
obj = { ...obj } obj = {...obj}
const isTr = targetIsTranslation && Translations.isProbablyATranslation(obj) const isTr = targetIsTranslation && Translations.isProbablyATranslation(obj)
@ -520,12 +526,12 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[
context: string context: string
): { result: T[]; errors?: string[]; warnings?: string[]; information?: string[] } { ): { result: T[]; errors?: string[]; warnings?: string[]; information?: string[] } {
if (json === null || json === undefined) { if (json === null || json === undefined) {
return { result: [] } return {result: []}
} }
if (json["rewrite"] === undefined) { if (json["rewrite"] === undefined) {
// not a rewrite // not a rewrite
return { result: [<T>json] } return {result: [<T>json]}
} }
const rewrite = <RewritableConfigJson<T>>json const rewrite = <RewritableConfigJson<T>>json
@ -565,7 +571,7 @@ export class ExpandRewrite<T> extends Conversion<T | RewritableConfigJson<T>, T[
ts.push(t) ts.push(t)
} }
return { result: ts } return {result: ts}
} }
} }
@ -849,7 +855,7 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson | LineRen
information?: string[] information?: string[]
} { } {
if (!json["iconBadges"]) { if (!json["iconBadges"]) {
return { result: json } return {result: json}
} }
const badgesJson = (<PointRenderingConfigJson>json).iconBadges const badgesJson = (<PointRenderingConfigJson>json).iconBadges
@ -860,7 +866,7 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson | LineRen
for (let i = 0; i < badgesJson.length; i++) { for (let i = 0; i < badgesJson.length; i++) {
const iconBadge: { if: TagConfigJson; then: string | TagRenderingConfigJson } = const iconBadge: { if: TagConfigJson; then: string | TagRenderingConfigJson } =
badgesJson[i] badgesJson[i]
const { errors, result, warnings } = this._expand.convert( const {errors, result, warnings} = this._expand.convert(
iconBadge.then, iconBadge.then,
context + ".iconBadges[" + i + "]" context + ".iconBadges[" + i + "]"
) )
@ -880,7 +886,7 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson | LineRen
} }
return { return {
result: { ...json, iconBadges }, result: {...json, iconBadges},
errors: errs, errors: errs,
warnings: warns, warnings: warns,
} }
@ -893,7 +899,7 @@ class PreparePointRendering extends Fuse<PointRenderingConfigJson | LineRenderin
"Prepares point renderings by expanding 'icon' and 'iconBadges'", "Prepares point renderings by expanding 'icon' and 'iconBadges'",
new On( new On(
"icon", "icon",
new FirstOf(new ExpandTagRendering(state, layer, { applyCondition: false })) new FirstOf(new ExpandTagRendering(state, layer, {applyCondition: false}))
), ),
new ExpandIconBadges(state, layer) new ExpandIconBadges(state, layer)
) )
@ -916,7 +922,7 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
new On( new On(
"titleIcons", "titleIcons",
(layer) => (layer) =>
new Concat(new ExpandTagRendering(state, layer, { noHardcodedStrings: true })) new Concat(new ExpandTagRendering(state, layer, {noHardcodedStrings: true}))
), ),
new ExpandFilter(state) new ExpandFilter(state)
) )

View file

@ -16,6 +16,8 @@ export interface TagRenderingConfigJson {
/** /**
* If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well. * 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. * The first tagRendering of a group will always be a sticky element.
*
* @deprecated
*/ */
group?: string group?: string

View file

@ -83,9 +83,23 @@
"ca": "Un pacient hospitalitzat és un pacient que roman diversos dies a la instal·lació" "ca": "Un pacient hospitalitzat és un pacient que roman diversos dies a la instal·lació"
} }
}, },
"phone", "contact",
"email", {
"website" "id": "oh-visitor",
"question": {
"en": "When are visitors allowed to visit?"
},
"questionHint": {
"en": "These are the regular visitor hours. Some wands have different visitor hours or might allow visitors in emergencies"
},
"freeform": {
"key": "opening_hours:visitors",
"type": "opening_hours"
},
"render": {
"en": "<h3>Opening hours for visitors</h3>Regular visitors are allowed at the following moments: {opening_hours_table(opening_hours:visitors)}<p class='subtle'>Some wands might have different opening hours. Many hospitals allow visits during emergencies too.</p>"
}
}
], ],
"mapRendering": [ "mapRendering": [
{ {
@ -103,4 +117,4 @@
"width": 1 "width": 1
} }
] ]
} }

View file

@ -113,6 +113,7 @@
"render": "{minimap(18, id): width:100%; height:8rem; border-radius:2rem; overflow: hidden; pointer-events: none;}" "render": "{minimap(18, id): width:100%; height:8rem; border-radius:2rem; overflow: hidden; pointer-events: none;}"
}, },
"phone": { "phone": {
"labels": ["contact"],
"question": { "question": {
"en": "What is the phone number of {title()}?", "en": "What is the phone number of {title()}?",
"nl": "Wat is het telefoonnummer van {title()}?", "nl": "Wat is het telefoonnummer van {title()}?",
@ -164,6 +165,7 @@
] ]
}, },
"email": { "email": {
"labels": ["contact"],
"render": "<a href='mailto:{email}' target='_blank'>{email}</a>", "render": "<a href='mailto:{email}' target='_blank'>{email}</a>",
"question": { "question": {
"nl": "Wat is het e-mailadres van {title()}?", "nl": "Wat is het e-mailadres van {title()}?",
@ -206,6 +208,7 @@
} }
}, },
"website": { "website": {
"labels": ["contact"],
"question": { "question": {
"en": "What is the website of {title()}?", "en": "What is the website of {title()}?",
"nl": "Wat is de website van {title()}?", "nl": "Wat is de website van {title()}?",