forked from MapComplete/MapComplete
Themes: add label support to questions.json; add opening hours for hospitals
This commit is contained in:
parent
151e648616
commit
41fdeb9cb5
4 changed files with 93 additions and 68 deletions
|
@ -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)
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()}?",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue