Merge develop

This commit is contained in:
Pieter Vander Vennet 2023-11-27 16:05:41 +01:00
commit d0ebd0e233
187 changed files with 1201 additions and 22352 deletions

View file

@ -123,6 +123,14 @@ export default class Constants {
"teardrop",
"triangle",
"crosshair",
"brick_wall_square",
"brick_wall_round",
"gps_arrow",
"checkmark",
"help",
"clock",
"invalid",
"close",
] as const
public static readonly defaultPinIcons: string[] = <any>Constants._defaultPinIcons

View file

@ -9,14 +9,16 @@ import { RasterLayerProperties } from "./RasterLayerProperties"
export class AvailableRasterLayers {
public static EditorLayerIndex: (Feature<Polygon, EditorLayerIndexProperties> &
RasterLayerPolygon)[] = <any>editorlayerindex.features
public static globalLayers: RasterLayerPolygon[] = globallayers.layers.map(
(properties) =>
<RasterLayerPolygon>{
type: "Feature",
properties,
geometry: BBox.global.asGeometry(),
}
)
public static globalLayers: RasterLayerPolygon[] = globallayers.layers
.filter((properties) => properties.id !== "osm.carto" /*Added separately*/)
.map(
(properties) =>
<RasterLayerPolygon>{
type: "Feature",
properties,
geometry: BBox.global.asGeometry(),
}
)
public static readonly osmCartoProperties: RasterLayerProperties = {
id: "osm",
name: "OpenStreetMap",
@ -74,6 +76,7 @@ export class AvailableRasterLayers {
}
return GeoOperations.inside(lonlat, eliPolygon)
})
matching.unshift(AvailableRasterLayers.osmCarto)
matching.push(AvailableRasterLayers.maptilerDefaultLayer)
matching.push(...AvailableRasterLayers.globalLayers)
return matching

View file

@ -26,7 +26,7 @@ import predifined_filters from "../../../../assets/layers/filters/filters.json"
import { TagConfigJson } from "../Json/TagConfigJson"
import PointRenderingConfigJson, { IconConfigJson } from "../Json/PointRenderingConfigJson"
import ValidationUtils from "./ValidationUtils"
import { RenderingSpecification } from "../../../UI/SpecialVisualization"
import { RenderingSpecification, SpecialVisualization } from "../../../UI/SpecialVisualization"
import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
import { ConfigMeta } from "../../../UI/Studio/configMeta"
import LineRenderingConfigJson from "../Json/LineRenderingConfigJson"
@ -1193,6 +1193,34 @@ class ExpandMarkerRenderings extends DesugaringStep<IconConfigJson> {
}
}
export class AddRatingBadge extends DesugaringStep<LayerConfigJson> {
constructor() {
super(
"Adds the 'rating'-element if a reviews-element is used in the tagRenderings",
["titleIcons"],
"AddRatingBadge"
)
}
convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson {
if (!json.tagRenderings) {
return json
}
const specialVis: Exclude<RenderingSpecification, string>[] = <
Exclude<RenderingSpecification, string>[]
>ValidationUtils.getAllSpecialVisualisations(<any>json.tagRenderings).filter(
(rs) => typeof rs !== "string"
)
const funcs = new Set<string>(specialVis.map((rs) => rs.func.funcName))
if (funcs.has("list_reviews")) {
;(<(string | TagRenderingConfigJson)[]>json.titleIcons).push("icons.rating")
}
return json
}
}
export class PrepareLayer extends Fuse<LayerConfigJson> {
constructor(state: DesugaringContext) {
super(
@ -1218,6 +1246,7 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
(layer) => new Each(new PreparePointRendering(state, layer))
),
new SetDefault("titleIcons", ["icons.defaults"]),
new AddRatingBadge(),
new On(
"titleIcons",
(layer) =>

View file

@ -92,7 +92,7 @@ export class DoesImageExist extends DesugaringStep<string> {
return image
}
if (image.match(/[a-z]*/)) {
if (Svg.All[image + ".svg"] !== undefined) {
if (Constants.defaultPinIcons.indexOf(image) >= 0) {
// This is a builtin img, e.g. 'checkmark' or 'crosshair'
return image
}
@ -110,7 +110,7 @@ export class DoesImageExist extends DesugaringStep<string> {
)
} else if (!this.doesPathExist(image)) {
context.err(
`Image with path ${image} does not exist; it is used in ${context}.\n Check for typo's and missing directories in the path.`
`Image with path ${image} does not exist.\n Check for typo's and missing directories in the path.`
)
} else {
context.err(
@ -813,6 +813,12 @@ class MiscTagRenderingChecks extends DesugaringStep<TagRenderingConfigJson> {
)
}
if (Object.keys(json).length === 1 && typeof json["render"] === "string") {
context.warn(
`use the content directly instead of {render: ${JSON.stringify(json["render"])}}`
)
}
{
for (const key of ["question", "questionHint", "render"]) {
CheckTranslation.allowUndefined.convert(json[key], context.enter(key))

View file

@ -9,6 +9,12 @@ export default class ValidationUtils {
renderingConfigs: (TagRenderingConfigJson | QuestionableTagRenderingConfigJson)[]
): RenderingSpecification[] {
const visualisations: RenderingSpecification[] = []
if (!Array.isArray(renderingConfigs)) {
throw (
"Could not inspect renderingConfigs, not an array: " +
JSON.stringify(renderingConfigs)
)
}
for (const renderConfig of renderingConfigs) {
visualisations.push(...ValidationUtils.getSpecialVisualisationsWithArgs(renderConfig))
}

View file

@ -3,12 +3,10 @@ import TagRenderingConfig from "./TagRenderingConfig"
import { TagsFilter } from "../../Logic/Tags/TagsFilter"
import { TagUtils } from "../../Logic/Tags/TagUtils"
import { Utils } from "../../Utils"
import Svg from "../../Svg"
import WithContextLoader from "./WithContextLoader"
import { ImmutableStore, Store } from "../../Logic/UIEventSource"
import BaseUIElement from "../../UI/BaseUIElement"
import { FixedUiElement } from "../../UI/Base/FixedUiElement"
import Img from "../../UI/Base/Img"
import Combine from "../../UI/Base/Combine"
import { VariableUiElement } from "../../UI/Base/VariableUIElement"
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
@ -133,71 +131,23 @@ export default class PointRenderingConfig extends WithContextLoader {
context + ".rotationAlignment"
)
}
/**
* Given a single HTML spec (either a single image path OR "image_path_to_known_svg:fill-colour", returns a fixedUIElement containing that
* The element will fill 100% and be positioned absolutely with top:0 and left: 0
*/
private static FromHtmlSpec(htmlSpec: string, style: string, isBadge = false): BaseUIElement {
if (htmlSpec === undefined) {
return undefined
private static FromHtmlMulti(multiSpec: string, tags: Store<Record<string, string>>) {
const icons: IconConfig[] = []
for (const subspec of multiSpec.split(";")) {
const [icon, color] = subspec.split(":")
icons.push(new IconConfig({ icon, color }))
}
const match = htmlSpec.match(/([a-zA-Z0-9_]*):([^;]*)/)
if (match !== null && Svg.All[match[1] + ".svg"] !== undefined) {
const svg = Svg.All[match[1] + ".svg"] as string
const targetColor = match[2]
const img = new Img(
svg.replace(/(rgb\(0%,0%,0%\)|#000000|#000)/g, targetColor),
true
).SetStyle(style)
if (isBadge) {
img.SetClass("badge")
}
return img
} else if (Svg.All[htmlSpec + ".svg"] !== undefined) {
const svg = Svg.All[htmlSpec + ".svg"] as string
const img = new Img(svg, true).SetStyle(style)
if (isBadge) {
img.SetClass("badge")
}
return img
} else {
return new FixedUiElement(`<img src="${htmlSpec}" style="${style}" />`)
}
}
private static FromHtmlMulti(
multiSpec: string,
rotation: string,
isBadge: boolean,
defaultElement: BaseUIElement = undefined,
options?: {
noFullWidth?: boolean
}
) {
if (multiSpec === undefined) {
return defaultElement
}
const style = `width:100%;height:100%;transform: rotate( ${rotation} );display:block;position: absolute; top: 0; left: 0`
const htmlDefs = multiSpec.trim()?.split(";") ?? []
const elements = Utils.NoEmpty(htmlDefs).map((def) =>
PointRenderingConfig.FromHtmlSpec(def, style, isBadge)
return new SvelteUIElement(DynamicMarker, { marker: icons, tags }).SetClass(
"w-full h-full block absolute top-0 left-0"
)
if (elements.length === 0) {
return defaultElement
} else {
const combine = new Combine(elements).SetClass("relative block")
if (options?.noFullWidth) {
return combine
}
combine.SetClass("w-full h-full")
return combine
}
}
public GetBaseIcon(tags?: Record<string, string>): BaseUIElement {
return new SvelteUIElement(DynamicMarker, { config: this, tags: new ImmutableStore(tags) })
return new SvelteUIElement(DynamicMarker, {
marker: this.marker,
rotation: this.rotation,
tags: new ImmutableStore(tags),
})
}
public RenderIcon(
@ -249,9 +199,11 @@ export default class PointRenderingConfig extends WithContextLoader {
anchorH = -iconH / 2
}
const icon = new SvelteUIElement(DynamicMarker, { config: this, tags }).SetClass(
"w-full h-full"
)
const icon = new SvelteUIElement(DynamicMarker, {
marker: this.marker,
rotation: this.rotation,
tags,
}).SetClass("w-full h-full")
let badges = undefined
if (options?.includeBadges ?? true) {
badges = this.GetBadges(tags, options?.metatags)
@ -306,9 +258,9 @@ export default class PointRenderingConfig extends WithContextLoader {
}
return new VariableUiElement(
tags.map(
(tags) => {
(tagsData) => {
const badgeElements = this.iconBadges.map((badge) => {
if (!badge.if.matchesProperties(tags)) {
if (!badge.if.matchesProperties(tagsData)) {
// Doesn't match...
return undefined
}
@ -323,19 +275,23 @@ export default class PointRenderingConfig extends WithContextLoader {
}
const htmlDefs = Utils.SubstituteKeys(
badge.then.GetRenderValue(tags)?.txt,
tags
badge.then.GetRenderValue(tagsData)?.txt,
tagsData
)
if (htmlDefs.startsWith("<") && htmlDefs.endsWith(">")) {
// This is probably an HTML-element
return new FixedUiElement(Utils.SubstituteKeys(htmlDefs, tags))
return new FixedUiElement(Utils.SubstituteKeys(htmlDefs, tagsData))
.SetStyle("width: 1.5rem")
.SetClass("block")
}
if (!htmlDefs) {
return undefined
}
const badgeElement = PointRenderingConfig.FromHtmlMulti(
htmlDefs,
"0",
true
tags
)?.SetClass("block relative")
if (badgeElement === undefined) {
return undefined

View file

@ -19,6 +19,7 @@ import { Paragraph } from "../../UI/Base/Paragraph"
import Svg from "../../Svg"
import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
import Constants from "../Constants"
export interface Icon {}
@ -362,7 +363,7 @@ export default class TagRenderingConfig {
if (stripped.endsWith(".svg")) {
stripped = stripped.substring(0, stripped.length - 4)
}
if (Svg.All[stripped + ".svg"] !== undefined) {
if (Constants.defaultPinIcons.indexOf(stripped) >= 0) {
icon = "./assets/svg/" + mapping.icon
if (!icon.endsWith(".svg")) {
icon += ".svg"