chore: automated housekeeping...

This commit is contained in:
Pieter Vander Vennet 2024-08-14 13:53:56 +02:00
parent f77570589d
commit 9b8a9337fd
111 changed files with 2911 additions and 1280 deletions

View file

@ -21,7 +21,7 @@
class={$classnames}
>
{#if $icon}
<Icon clss="w-4 h-4" icon={$icon}/>
{/if}
<Icon clss="w-4 h-4" icon={$icon} />
{/if}
{@html $text}
</a>

View file

@ -2,7 +2,7 @@ import { Utils } from "../../Utils"
import BaseUIElement from "../BaseUIElement"
/**
* @deprecated
*/
*/
export default class Img extends BaseUIElement {
private readonly _src: string
private readonly _rawSvg: boolean

View file

@ -12,14 +12,13 @@
export let cls = "m-0.5 p-0.5 sm:p-1 md:m-1"
export let enabled: Store<boolean> = new ImmutableStore(true)
export let arialabel: Translation = undefined
export let arialabelDynamic : Store<Translation> = new ImmutableStore(arialabel)
let arialabelString = arialabelDynamic.bind(tr => tr?.current)
export let arialabelDynamic: Store<Translation> = new ImmutableStore(arialabel)
let arialabelString = arialabelDynamic.bind((tr) => tr?.current)
export let htmlElem: UIEventSource<HTMLElement> = undefined
let _htmlElem: HTMLElement
$: {
htmlElem?.setData(_htmlElem)
}
</script>
<button

View file

@ -40,10 +40,7 @@
style={svelteElem.getStyle()}
/>
{:else}
<svelte:component
this={svelteElem?._svelteComponent}
{...svelteElem._props}
/>
<svelte:component this={svelteElem?._svelteComponent} {...svelteElem._props} />
{/if}
{:else}
<span bind:this={elem} />

View file

@ -21,14 +21,14 @@
{#if $txt}
{#if cls}
<span class={cls}>
<span lang={$lang}>
{@html Utils.purify($txt)}
<span class={cls}>
<span lang={$lang}>
{@html Utils.purify($txt)}
</span>
<WeblateLink context={t?.context} />
</span>
<WeblateLink context={t?.context} />
</span>
{:else}
<span lang={$lang}>
<span lang={$lang}>
{@html Utils.purify($txt)}
</span>
<WeblateLink context={t?.context} />

View file

@ -31,7 +31,7 @@
target="_blank"
tabindex="-1"
>
<LanguageIcon class="font-gray"/>
<LanguageIcon class="font-gray" />
</a>
{/if}
{/if}

View file

@ -52,7 +52,9 @@
{#if layout.official}
<a
class="flex"
href={"https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Themes/" + layout.id + ".md"}
href={"https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Themes/" +
layout.id +
".md"}
target="_blank"
>
<DocumentMagnifyingGlass class="h-6 w-6" />
@ -65,7 +67,7 @@
<a class="flex" href={Utils.OsmChaLinkFor(31, layout.id)}>
<DocumentChartBar class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({theme: layout.title})}/>
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({ theme: layout.title })} />
</a>
{/if}

View file

@ -16,7 +16,7 @@
import { TranslateIcon } from "@rgossiaux/svelte-heroicons/solid"
import Osm_logo from "../../assets/svg/Osm_logo.svelte"
import Generic_map from "../../assets/svg/Generic_map.svelte"
import { UserGroupIcon} from "@babeard/svelte-heroicons/solid"
import { UserGroupIcon } from "@babeard/svelte-heroicons/solid"
import Marker from "../Map/Marker.svelte"
export let state: SpecialVisualizationState

View file

@ -27,10 +27,7 @@
{:else if $pending.length === 1}
<Tr cls="alert" t={Translations.t.general.uploadPendingSingle} />
{:else if $pending.length > 1}
<Tr
cls="alert"
t={Translations.t.general.uploadPending.Subs({ count: $pending.length })}
/>
<Tr cls="alert" t={Translations.t.general.uploadPending.Subs({ count: $pending.length })} />
{/if}
{#each $errors as error}
@ -43,24 +40,19 @@
</button>
<ul>
{#each $pending as pending}
<li>
{#if pending.changes !== undefined}
Create {pending.type}/{pending.id} {JSON.stringify(TagUtils.KVObjtoProperties(pending.tags))}
Create {pending.type}/{pending.id}
{JSON.stringify(TagUtils.KVObjtoProperties(pending.tags))}
{:else}
Modify {pending.type}/{pending.id} {JSON.stringify(pending.tags)}
{/if}
{#if pending.type === "way" && pending.changes?.nodes}
{pending.changes.nodes.join(" ")}
{/if}
</li>
{/each}
</ul>
{/if}
</div>

View file

@ -17,11 +17,11 @@
export let highlightedRendering: UIEventSource<string> = undefined
export let tags: UIEventSource<Record<string, string>> = state?.featureProperties?.getStore(
selectedElement.properties.id,
selectedElement.properties.id
)
let isAddNew = tags.mapD(
(t) => t?.id?.startsWith(LastClickFeatureSource.newPointElementId) ?? false,
(t) => t?.id?.startsWith(LastClickFeatureSource.newPointElementId) ?? false
)
export let layer: LayerConfig
@ -32,29 +32,32 @@
onDestroy(
state.userRelatedState.preferencesAsTags.addCallbackAndRun((tags) => {
_metatags = tags
}),
})
)
}
let knownTagRenderings: Store<TagRenderingConfig[]> = tags.mapD((tgs) =>
layer?.tagRenderings?.filter(
(config) => {
if (mustMatchLabels !== undefined) {
if (!mustMatchLabels.has(config.id) && !config?.labels?.some(l => mustMatchLabels.has(l))) {
return false
}
} else if (dontMatchLabels) {
if (dontMatchLabels.has(config.id) || config?.labels?.some(l => dontMatchLabels.has(l))) {
return false
}
}
if (!config.IsKnown(tgs)) {
layer?.tagRenderings?.filter((config) => {
if (mustMatchLabels !== undefined) {
if (
!mustMatchLabels.has(config.id) &&
!config?.labels?.some((l) => mustMatchLabels.has(l))
) {
return false
}
return (config.condition?.matchesProperties(tgs) ?? true) &&
(config.metacondition?.matchesProperties({ ...tgs, ..._metatags }) ?? true)
},
),
} else if (dontMatchLabels) {
if (dontMatchLabels.has(config.id) || config?.labels?.some((l) => dontMatchLabels.has(l))) {
return false
}
}
if (!config.IsKnown(tgs)) {
return false
}
return (
(config.condition?.matchesProperties(tgs) ?? true) &&
(config.metacondition?.matchesProperties({ ...tgs, ..._metatags }) ?? true)
)
})
)
</script>

View file

@ -123,7 +123,7 @@
<Copyable {state} text={linkToShare} />
</div>
<div class="flex justify-center">
<img src={new Qr(linkToShare).toImageElement(125)} style="width: 125px"/>
<img src={new Qr(linkToShare).toImageElement(125)} style="width: 125px" />
</div>
<Tr t={tr.embedIntro} />

View file

@ -78,9 +78,12 @@
<div class="flex w-full flex-wrap sm:flex-nowrap">
<If condition={state.featureSwitches.featureSwitchGeolocation}>
<button disabled={!$gpsAvailable} class:disabled={!$gpsAvailable} class="flex w-full items-center gap-x-2" on:click={jumpToCurrentLocation}>
<button
disabled={!$gpsAvailable}
class:disabled={!$gpsAvailable}
class="flex w-full items-center gap-x-2"
on:click={jumpToCurrentLocation}
>
<GeolocationIndicator {state} />
<Tr t={$gpsExplanation} />
</button>

View file

@ -6,7 +6,7 @@
<Accordion>
<AccordionItem open={expanded} paddingDefault="p-0" inactiveClass="text-black">
<span slot="header" class="p-2 text-base w-full">
<span slot="header" class="w-full p-2 text-base">
<slot name="header" />
</span>
<div class="low-interaction rounded-b p-2">

View file

@ -17,7 +17,6 @@ export default class Toggle extends VariableUiElement {
super(isEnabled?.map((isEnabled) => (isEnabled ? showEnabled : showDisabled)))
this.isEnabled = isEnabled
}
}
/**
@ -34,5 +33,4 @@ export class ClickableToggle extends Toggle {
super(showEnabled, showDisabled, isEnabled)
this.isEnabled = isEnabled
}
}

View file

@ -148,7 +148,7 @@
<UserCircleIcon class={clss} {color} />
{:else if Utils.isEmoji(icon)}
<span style={`font-size: ${emojiHeight}px; line-height: ${emojiHeight}px`}>
{icon}
{icon}
</span>
{:else}
<img class={clss ?? "h-full w-full"} src={icon} aria-hidden="true" alt="" />

View file

@ -22,7 +22,7 @@ class SingleBackgroundHandler {
constructor(
map: Store<MLMap>,
targetLayer: RasterLayerPolygon,
background: UIEventSource<RasterLayerPolygon | undefined>,
background: UIEventSource<RasterLayerPolygon | undefined>
) {
this._targetLayer = targetLayer
this._map = map
@ -57,10 +57,9 @@ class SingleBackgroundHandler {
"Removing raster layer",
this._targetLayer.properties.id,
"map moved and not been used for",
SingleBackgroundHandler.DEACTIVATE_AFTER,
SingleBackgroundHandler.DEACTIVATE_AFTER
)
try {
if (map.getLayer(<string>this._targetLayer.properties.id)) {
map.removeLayer(<string>this._targetLayer.properties.id)
}
@ -157,7 +156,7 @@ class SingleBackgroundHandler {
"raster-opacity": 0,
},
},
addLayerBeforeId,
addLayerBeforeId
)
this.opacity.addCallbackAndRun((o) => {
try {
@ -175,14 +174,14 @@ class SingleBackgroundHandler {
private fadeOut() {
Stores.Chronic(
8,
() => this.opacity.data > 0 && this._deactivationTime !== undefined,
() => this.opacity.data > 0 && this._deactivationTime !== undefined
).addCallback((_) => this.opacity.setData(Math.max(0, this.opacity.data - this.fadeStep)))
}
private fadeIn() {
Stores.Chronic(
8,
() => this.opacity.data < 1.0 && this._deactivationTime === undefined,
() => this.opacity.data < 1.0 && this._deactivationTime === undefined
).addCallback((_) => this.opacity.setData(Math.min(1.0, this.opacity.data + this.fadeStep)))
}
}
@ -200,7 +199,7 @@ export default class RasterLayerHandler {
}
public static prepareSource(
layer: RasterLayerProperties,
layer: RasterLayerProperties
): RasterSourceSpecification | VectorSourceSpecification {
if (layer.type === "vector") {
const vs: VectorSourceSpecification = {

View file

@ -14,7 +14,7 @@
import TitledPanel from "../Base/TitledPanel.svelte"
import Loading from "../Base/Loading.svelte"
export let availableLayers: {store: Store<RasterLayerPolygon[]>}
export let availableLayers: { store: Store<RasterLayerPolygon[]> }
export let mapproperties: MapProperties
export let userstate: UserRelatedState
export let map: Store<MlMap>
@ -35,7 +35,7 @@
function availableForCategory(type: CategoryType): Store<RasterLayerPolygon[]> {
const keywords = categories[type]
return _availableLayers.mapD((available) =>
available.filter((layer) => keywords.indexOf(<EliCategory>layer.properties.category) >= 0),
available.filter((layer) => keywords.indexOf(<EliCategory>layer.properties.category) >= 0)
)
}
@ -57,7 +57,7 @@
<Tr slot="title" t={Translations.t.general.backgroundMap} />
{#if $_availableLayers?.length < 1}
<Loading />
{:else }
{:else}
<div class="grid h-full w-full grid-cols-1 gap-2 md:grid-cols-2">
<RasterLayerPicker
availableLayers={$photoLayers}

View file

@ -20,7 +20,11 @@
export let favourite: UIEventSource<string> | undefined = undefined
let rasterLayer = new UIEventSource<RasterLayerPolygon>(availableLayers[0])
let rasterLayerId = rasterLayer.sync(l => l?.properties?.id, [], id => availableLayers.find(l => l.properties.id === id))
let rasterLayerId = rasterLayer.sync(
(l) => l?.properties?.id,
[],
(id) => availableLayers.find((l) => l.properties.id === id)
)
rasterLayer.setData(availableLayers[0])
$: rasterLayer.setData(availableLayers[0])
@ -32,13 +36,13 @@
return
}
rasterLayer.setData(fav)
}),
})
)
onDestroy(
rasterLayer.addCallbackAndRunD((selected) => {
favourite?.setData(selected.properties.id)
}),
})
)
}
@ -52,7 +56,7 @@
} else {
rasterLayerOnMap.setData(undefined)
}
}),
})
)
}

View file

@ -1,14 +1,12 @@
<script lang="ts">
import { IdbLocalStorage } from "../../Logic/Web/IdbLocalStorage"
import { Utils } from "../../Utils"
function clearCaches(){
function clearCaches() {
IdbLocalStorage.clearAll()
Utils.download("./service-worker-clear")
}
export let msg : string
export let msg: string
</script>
<button on:click={() => clearCaches()} class="flex gap-x-2">

View file

@ -15,13 +15,12 @@
export let header: string
export let layer: LayerConfig
let headerTr = layer.tagRenderings.find(tr => tr.id === header)
let headerTr = layer.tagRenderings.find((tr) => tr.id === header)
</script>
<AccordionSingle>
<div slot="header">
<TagRenderingAnswer {tags} {layer} config={headerTr} {state} {selectedElement} />
</div>
<SelectedElementView mustMatchLabels={new Set(labels)} {state} {layer} {tags} {selectedElement}/>
<SelectedElementView mustMatchLabels={new Set(labels)} {state} {layer} {tags} {selectedElement} />
</AccordionSingle>

View file

@ -45,7 +45,7 @@
location: new UIEventSource({ lon, lat }),
minzoom: new UIEventSource($reason.minZoom),
rasterLayer: state.mapProperties.rasterLayer,
zoom: new UIEventSource($reason?.startZoom ?? 16)
zoom: new UIEventSource($reason?.startZoom ?? 16),
}
}
@ -71,7 +71,7 @@
<AccordionSingle>
<span slot="header" class="flex">
{#if moveWizardState.reasons.length === 1}
<Icon icon={moveWizardState.reasons[0].icon} clss="w-6 h-6"/>
<Icon icon={moveWizardState.reasons[0].icon} clss="w-6 h-6" />
<Tr t={Translations.T(moveWizardState.reasons[0].invitingText)} />
{:else}
<Move class="h-6 w-6" />
@ -87,7 +87,7 @@
currentStep = "pick_location"
}}
>
<Icon icon={reasonSpec.icon} clss="w-12 h-12"/>
<Icon icon={reasonSpec.icon} clss="w-12 h-12" />
<Tr t={Translations.T(reasonSpec.text)} />
</button>
{/each}

View file

@ -18,7 +18,6 @@
export let minzoom: number
export let zoomMoreMessage: string
let curZoom = state.mapProperties.zoom
const isClosed = tags.map((tags) => (tags["closed_at"] ?? "") !== "")
@ -29,7 +28,6 @@
tags.data["closed_at"] = new Date().toISOString()
tags.ping()
}
</script>
<LoginToggle {state}>
@ -37,7 +35,6 @@
<Tr t={t.loginToClose} />
</div>
{#if $isClosed}
<Tr cls="thanks" t={t.isClosed} />
{:else if minzoom <= $curZoom}
@ -50,5 +47,4 @@
{:else if zoomMoreMessage}
{zoomMoreMessage}
{/if}
</LoginToggle>

View file

@ -16,18 +16,14 @@
let [lon, lat] = GeoOperations.centerpointCoordinates(feature)
const includeLayout = window.location.pathname
.split("/")
.at(-1)
.startsWith("theme")
const layout = includeLayout
? "layout=" + state.layout.id + "&"
: ""
let id: Store<string> = tags.mapD(tags => tags.id)
let url = id.mapD(id => `${window.location.protocol}//${window.location.host}${window.location.pathname}?${layout}lat=${lat}&lon=${lon}&z=15` +
`#${id}`)
const includeLayout = window.location.pathname.split("/").at(-1).startsWith("theme")
const layout = includeLayout ? "layout=" + state.layout.id + "&" : ""
let id: Store<string> = tags.mapD((tags) => tags.id)
let url = id.mapD(
(id) =>
`${window.location.protocol}//${window.location.host}${window.location.pathname}?${layout}lat=${lat}&lon=${lon}&z=15` +
`#${id}`
)
function toggleSize() {
if (size.data !== bigSize) {
@ -42,5 +38,9 @@
<!-- Not yet uploaded, doesn't have a fixed ID -->
<Loading />
{:else}
<img on:click={() => toggleSize()} src={new Qr($url).toImageElement($size)} style={`width: ${$size}px; height: ${$size}px`} />
<img
on:click={() => toggleSize()}
src={new Qr($url).toImageElement($size)}
style={`width: ${$size}px; height: ${$size}px`}
/>
{/if}

View file

@ -31,7 +31,8 @@
*/
export let notForLabels: string[] | undefined = undefined
const _notForLabels = new Set(notForLabels)
let showAllQuestionsAtOnce : Store<boolean>= state.userRelatedState?.showAllQuestionsAtOnce ?? new ImmutableStore(false)
let showAllQuestionsAtOnce: Store<boolean> =
state.userRelatedState?.showAllQuestionsAtOnce ?? new ImmutableStore(false)
function allowed(labels: string[]) {
if (onlyForLabels?.length > 0 && !labels.some((l) => _onlyForLabels.has(l))) {

View file

@ -32,19 +32,18 @@
onDestroy(
tags.addCallbackD((tags) => {
const knownNow = config.IsKnown(tags)
if(!knownNow){
if (!knownNow) {
editMode = true
return
}
if(knownNow && !knownAtTheStart) {
if (knownNow && !knownAtTheStart) {
// Some other question might have set this to 'known', so we close the 'editMode'
editMode = false
// well, not really 'known at the start', but it is known at this point in time, so it should not set 'editMode' to false automatically anymore
knownAtTheStart = true
}
}),
})
)
}

View file

@ -306,7 +306,8 @@
let hideMappingsUnlessSearchedFor =
config.mappings.length > 8 && config.mappings.some((m) => m.priorityIf !== undefined)
$: question = config.question
$: hideMappingsUnlessSearchedFor = config.mappings.length > 8 && config.mappings.some((m) => m.priorityIf !== undefined)
$: hideMappingsUnlessSearchedFor =
config.mappings.length > 8 && config.mappings.some((m) => m.priorityIf !== undefined)
if (state?.osmConnection) {
onDestroy(
@ -362,7 +363,7 @@
/>
</div>
{#if hideMappingsUnlessSearchedFor}
<div class="m-1 rounded border border-dashed border-black p-1 px-2 flex items-center">
<div class="m-1 flex items-center rounded border border-dashed border-black p-1 px-2">
<Tr t={Translations.t.general.mappingsAreHidden} />
</div>
{/if}

View file

@ -1,8 +1,6 @@
import { RenderingSpecification, SpecialVisualization } from "./SpecialVisualization"
export default class SpecialVisualisationUtils {
/**
*
* For a given string, returns a specification what parts are fixed and what parts are special renderings.
@ -27,7 +25,7 @@ export default class SpecialVisualisationUtils {
public static constructSpecification(
template: string,
specialVisualisations: Map<string, SpecialVisualization>,
extraMappings: SpecialVisualization[] = [],
extraMappings: SpecialVisualization[] = []
): RenderingSpecification[] {
if (template === "") {
return []
@ -36,15 +34,13 @@ export default class SpecialVisualisationUtils {
if (template["type"] !== undefined) {
console.trace(
"Got a non-expanded template while constructing the specification, it still has a 'special-key':",
template,
template
)
throw "Got a non-expanded template while constructing the specification"
}
// Note: the '.*?' in the regex reads as 'any character, but in a non-greedy way'
const matched = template.match(
new RegExp(`(.*){\([a-zA-Z_]+\)\\((.*?)\\)(:.*)?}(.*)`, "s"),
)
const matched = template.match(new RegExp(`(.*){\([a-zA-Z_]+\)\\((.*?)\\)(:.*)?}(.*)`, "s"))
if (matched === null) {
// IF we end up here, no changes have to be made - except to remove any resting {}
return [template]
@ -52,11 +48,11 @@ export default class SpecialVisualisationUtils {
const fName = matched[2]
let knownSpecial = specialVisualisations.get(fName)
if(!knownSpecial && extraMappings?.length > 0){
knownSpecial = extraMappings.find(em => em.funcName === fName)
if (!knownSpecial && extraMappings?.length > 0) {
knownSpecial = extraMappings.find((em) => em.funcName === fName)
}
if(!knownSpecial){
throw "Didn't find a special visualisation: "+fName+" in "+template
if (!knownSpecial) {
throw "Didn't find a special visualisation: " + fName + " in " + template
}
// Always a boring string
@ -64,13 +60,12 @@ export default class SpecialVisualisationUtils {
const argument: string =
matched[3] /* .trim() // We don't trim, as spaces might be relevant, e.g. "what is ... of {title()}"*/
const style: string = matched[4]?.substring(1) ?? ""
const partAfter: RenderingSpecification[] = SpecialVisualisationUtils.constructSpecification(
matched[5],
specialVisualisations,
extraMappings,
)
const partAfter: RenderingSpecification[] =
SpecialVisualisationUtils.constructSpecification(
matched[5],
specialVisualisations,
extraMappings
)
const args: string[] = knownSpecial.args.map((arg) => arg.defaultValue ?? "")
if (argument.length > 0) {
@ -92,12 +87,10 @@ export default class SpecialVisualisationUtils {
func: knownSpecial,
}
partAfter.unshift(element)
if(partBefore.length > 0){
if (partBefore.length > 0) {
partAfter.unshift(partBefore)
}
return partAfter
}
private static undoEncoding(str: string) {

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,4 @@
<script lang="ts">
import Translations from "../i18n/Translations"
import type { ConfigMeta } from "./configMeta"
import Icon from "../Map/Icon.svelte"
@ -11,9 +10,7 @@
import QuestionPreview from "./QuestionPreview.svelte"
import SchemaBasedMultiType from "./SchemaBasedMultiType.svelte"
import { EditJsonState } from "./EditLayerState"
import type {
QuestionableTagRenderingConfigJson,
} from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
import type { QuestionableTagRenderingConfigJson } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
import { AccordionItem } from "flowbite-svelte"
export let state: EditJsonState<any>
@ -86,10 +83,10 @@
} catch (e) {
console.log(
"Warning: could not translate a title for " +
`${singular} ${i} with function ` +
schema.hints.title +
" and value " +
JSON.stringify(value),
`${singular} ${i} with function ` +
schema.hints.title +
" and value " +
JSON.stringify(value)
)
}
return Translations.T(`${singular} ${i}`)
@ -111,11 +108,10 @@
}
</script>
<AccordionItem open={$expanded} paddingDefault="p-0" inactiveClass="text-black m-0" >
<div slot="header" class="p-1 text-base w-full m-0 text-black">
<AccordionItem open={$expanded} paddingDefault="p-0" inactiveClass="text-black m-0">
<div slot="header" class="m-0 w-full p-1 text-base text-black">
{#if !isTagRenderingBlock}
<div class="flex items-center justify-between w-full">
<div class="flex w-full items-center justify-between">
<div class="m-0 flex">
{#if schema.hints.icon}
<Icon clss="w-6 h-6" icon={genIcon(value)} color={genColor(value)} />
@ -134,30 +130,30 @@
<button
class="h-fit w-fit rounded-full border border-black p-1"
on:click={() => {
del(i)
}}
del(i)
}}
>
<TrashIcon class="h-4 w-4" />
</button>
</div>
{:else if typeof value === "string"}
Builtin: <b>{value}</b>
{:else if value["builtin"]}
{:else if value["builtin"]}
reused tagrendering <span class="font-bold">{JSON.stringify(value["builtin"])}</span>
{:else}
<Tr cls="font-bold" t={Translations.T(value?.question ?? value?.render)} />
{/if}
</div>
<div class="normal-background p-2 border border-gray-300">
<div class="normal-background border border-gray-300 p-2">
{#if usesOverride}
This block uses an builtin/override construction and cannot be edited in Studio.
Edit the code directly
This block uses an builtin/override construction and cannot be edited in Studio. Edit the code
directly
{:else if isTagRenderingBlock}
<QuestionPreview {state} {path} {schema}>
<button
on:click={() => {
del(i)
}}
del(i)
}}
>
<TrashIcon class="h-4 w-4" />
Delete this question
@ -166,16 +162,16 @@
{#if i > 0}
<button
on:click={() => {
moveTo(i, 0)
}}
moveTo(i, 0)
}}
>
Move to front
</button>
<button
on:click={() => {
swap(i, i - 1)
}}
swap(i, i - 1)
}}
>
Move up
</button>
@ -183,29 +179,25 @@
{#if i + 1 < $currentValue.length}
<button
on:click={() => {
swap(i, i + 1)
}}
swap(i, i + 1)
}}
>
Move down
</button>
<button
on:click={() => {
moveTo(i, $currentValue.length - 1)
}}
moveTo(i, $currentValue.length - 1)
}}
>
Move to back
</button>
{/if}
</QuestionPreview>
{:else if schema.hints.types}
<SchemaBasedMultiType {state} path={[...path,i]} schema={schemaForMultitype()} />
<SchemaBasedMultiType {state} path={[...path, i]} schema={schemaForMultitype()} />
{:else}
{#each subparts as subpart}
<SchemaBasedInput
{state}
path={fusePath(subpart.path)}
schema={subpart}
/>
<SchemaBasedInput {state} path={fusePath(subpart.path)} schema={subpart} />
{/each}
{/if}
</div>

View file

@ -23,10 +23,9 @@
<div class="flex flex-col">
<div>
Deleting this layer will delete your version. If you clicked a layer made by someone else, their version will
remain.
If you ever accidentally delete a layer, contact Pietervdvn. He might have a backup
Deleting this layer will delete your version. If you clicked a layer made by someone else,
their version will remain. If you ever accidentally delete a layer, contact Pietervdvn. He
might have a backup
</div>
<NextButton clss="primary" on:click={() => deleteLayer()}>
@ -35,8 +34,5 @@
Do delete this {objectType}
</div>
</NextButton>
</div>
</AccordionSingle>

View file

@ -82,7 +82,7 @@
let highlightedItem: UIEventSource<HighlightedTagRendering> = state.highlightedItem
</script>
<div class="flex h-screen flex-col link-underline">
<div class="link-underline flex h-screen flex-col">
<div class="my-2 flex w-full flex-wrap justify-between">
<slot />
{#if $title === undefined}

View file

@ -54,7 +54,7 @@ export abstract class EditJsonState<T> {
* The EditLayerUI shows a 'schemaBasedInput' for this path to pop advanced questions out
*/
public readonly highlightedItem: UIEventSource<HighlightedTagRendering> = new UIEventSource(
undefined,
undefined
)
private sendingUpdates = false
private readonly _stores = new Map<string, UIEventSource<any>>()
@ -66,7 +66,7 @@ export abstract class EditJsonState<T> {
osmConnection: OsmConnection,
options?: {
expertMode?: UIEventSource<boolean>
},
}
) {
this.osmConnection = osmConnection
this.schema = schema
@ -93,14 +93,20 @@ export abstract class EditJsonState<T> {
await this.server.update(id, config, this.category)
})
this.messages = this.createMessagesStore()
}
public startSavingUpdates(enabled = true) {
this.sendingUpdates = enabled
this.register(["credits"], this.osmConnection.userDetails.mapD(u => u.name), false)
this.register(["credits:uid"], this.osmConnection.userDetails.mapD(u => u.uid), false)
this.register(
["credits"],
this.osmConnection.userDetails.mapD((u) => u.name),
false
)
this.register(
["credits:uid"],
this.osmConnection.userDetails.mapD((u) => u.uid),
false
)
if (enabled) {
this.configuration.ping()
}
@ -141,7 +147,7 @@ export abstract class EditJsonState<T> {
public register(
path: ReadonlyArray<string | number>,
value: Store<any>,
noInitialSync: boolean = true,
noInitialSync: boolean = true
): () => void {
const unsync = value.addCallback((v) => {
this.setValueAt(path, v)
@ -155,7 +161,7 @@ export abstract class EditJsonState<T> {
public getSchemaStartingWith(path: string[]) {
return this.schema.filter(
(sch) =>
!path.some((part, i) => !(sch.path.length > path.length && sch.path[i] === part)),
!path.some((part, i) => !(sch.path.length > path.length && sch.path[i] === part))
)
}
@ -173,11 +179,11 @@ export abstract class EditJsonState<T> {
}
public getSchema(path: (string | number)[]): ConfigMeta[] {
path = path.filter(p => typeof p === "string")
path = path.filter((p) => typeof p === "string")
const schemas = this.schema.filter(
(sch) =>
sch !== undefined &&
!path.some((part, i) => !(sch.path.length == path.length && sch.path[i] === part)),
!path.some((part, i) => !(sch.path.length == path.length && sch.path[i] === part))
)
if (schemas.length == 0) {
console.warn("No schemas found for path", path.join("."))
@ -267,12 +273,12 @@ class ContextRewritingStep<T> extends Conversion<LayerConfigJson, T> {
constructor(
state: DesugaringContext,
step: Conversion<LayerConfigJson, T>,
getTagRenderings: (t: T) => TagRenderingConfigJson[],
getTagRenderings: (t: T) => TagRenderingConfigJson[]
) {
super(
"When validating a layer, the tagRenderings are first expanded. Some builtin tagRendering-calls (e.g. `contact`) will introduce _multiple_ tagRenderings, causing the count to be off. This class rewrites the error messages to fix this",
[],
"ContextRewritingStep",
"ContextRewritingStep"
)
this._state = state
this._step = step
@ -282,7 +288,7 @@ class ContextRewritingStep<T> extends Conversion<LayerConfigJson, T> {
convert(json: LayerConfigJson, context: ConversionContext): T {
const converted = this._step.convert(json, context)
const originalIds = json.tagRenderings?.map(
(tr) => (<QuestionableTagRenderingConfigJson>tr)["id"],
(tr) => (<QuestionableTagRenderingConfigJson>tr)["id"]
)
if (!originalIds) {
return converted
@ -344,7 +350,7 @@ export default class EditLayerState extends EditJsonState<LayerConfigJson> {
schema: ConfigMeta[],
server: StudioServer,
osmConnection: OsmConnection,
options: { expertMode: UIEventSource<boolean> },
options: { expertMode: UIEventSource<boolean> }
) {
super(schema, server, "layers", osmConnection, options)
this.layout = {
@ -401,7 +407,7 @@ export default class EditLayerState extends EditJsonState<LayerConfigJson> {
return new ContextRewritingStep(
state,
new Pipe(new PrepareLayer(state), new ValidateLayer("dynamic", false, undefined, true)),
(t) => <TagRenderingConfigJson[]>t.raw.tagRenderings,
(t) => <TagRenderingConfigJson[]>t.raw.tagRenderings
)
}
@ -435,7 +441,7 @@ export default class EditLayerState extends EditJsonState<LayerConfigJson> {
}
protected async validate(
configuration: Partial<LayerConfigJson>,
configuration: Partial<LayerConfigJson>
): Promise<ConversionMessage[]> {
const layers = AllSharedLayers.getSharedLayersConfigs()
@ -465,18 +471,20 @@ export class EditThemeState extends EditJsonState<LayoutConfigJson> {
schema: ConfigMeta[],
server: StudioServer,
osmConnection: OsmConnection,
options: { expertMode: UIEventSource<boolean> },
options: { expertMode: UIEventSource<boolean> }
) {
super(schema, server, "themes", osmConnection, options)
this.setupFixers()
}
protected buildValidation(state: DesugaringContext): Conversion<LayoutConfigJson, any> {
return new Pipe(new PrevalidateTheme(),
return new Pipe(
new PrevalidateTheme(),
new Pipe(
new PrepareTheme(state),
new ValidateTheme(undefined, "", false, new Set(state.tagRenderings.keys())),
), true,
new ValidateTheme(undefined, "", false, new Set(state.tagRenderings.keys()))
),
true
)
}

View file

@ -5,9 +5,7 @@
import { ImmutableStore, Store } from "../../Logic/UIEventSource"
import TagRenderingEditable from "../Popup/TagRendering/TagRenderingEditable.svelte"
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
import type {
QuestionableTagRenderingConfigJson,
} from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.js"
import type { QuestionableTagRenderingConfigJson } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.js"
import type { TagRenderingConfigJson } from "../../Models/ThemeConfig/Json/TagRenderingConfigJson"
import FromHtml from "../Base/FromHtml.svelte"
import ShowConversionMessage from "./ShowConversionMessage.svelte"
@ -44,11 +42,12 @@
if (config["builtin"]) {
let override = ""
if (config["override"]) {
override = ". Some items are changed with an override. Editing this is not yet supported with Studio."
override =
". Some items are changed with an override. Editing this is not yet supported with Studio."
}
return new TagRenderingConfig({
render: {
"en": "This question reuses <b>" + JSON.stringify(config["builtin"]) + "</b>" + override,
en: "This question reuses <b>" + JSON.stringify(config["builtin"]) + "</b>" + override,
},
})
}
@ -69,10 +68,10 @@
<div class="flex">
<div class="m-4 flex w-full flex-col">
{#if $configJson.some(config => config["builtin"] !== undefined)}
<div class="interactive p-2 rounded-2xl">
This question uses an advanced 'builtin'+'override' construction in the source code.
Editing this with Studio is not supported.
{#if $configJson.some((config) => config["builtin"] !== undefined)}
<div class="interactive rounded-2xl p-2">
This question uses an advanced 'builtin'+'override' construction in the source code. Editing
this with Studio is not supported.
</div>
{:else}
<NextButton clss="primary" on:click={() => state.highlightedItem.setData({ path, schema })}>

View file

@ -9,14 +9,18 @@
export let state: EditLayerState | EditThemeState
let rawConfig = state.configuration.sync(f => JSON.stringify(f, null, " "), [], json => {
try {
return JSON.parse(json)
} catch (e) {
console.error("Could not parse", json)
return undefined
let rawConfig = state.configuration.sync(
(f) => JSON.stringify(f, null, " "),
[],
(json) => {
try {
return JSON.parse(json)
} catch (e) {
console.error("Could not parse", json)
return undefined
}
}
})
)
let container: HTMLDivElement
let monaco: typeof Monaco
@ -88,7 +92,7 @@
model = monaco?.editor?.createModel(
JSON.stringify(state.configuration.data, null, " "),
"json",
modelUri,
modelUri
)
} catch (e) {
console.error("Could not create model in MOnaco Editor", e)
@ -126,7 +130,7 @@
{:else}
<div bind:this={container} class="h-full w-full">
{#if !isLoaded}
<div class="h-full w-full flex items-center align-center">
<div class="align-center flex h-full w-full items-center">
<Loading />
</div>
{/if}

View file

@ -5,9 +5,7 @@
import { TrashIcon } from "@babeard/svelte-heroicons/mini"
import ShowConversionMessage from "./ShowConversionMessage.svelte"
import Markdown from "../Base/Markdown.svelte"
import type {
QuestionableTagRenderingConfigJson,
} from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
import type { QuestionableTagRenderingConfigJson } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
import CollapsedTagRenderingPreview from "./CollapsedTagRenderingPreview.svelte"
import { Accordion } from "flowbite-svelte"
@ -63,8 +61,6 @@
currentValue.data.splice(i, 1)
currentValue.ping()
}
</script>
<div class="pl-2">
@ -76,7 +72,9 @@
{#if $currentValue === undefined}
No array defined
{:else if !Array.isArray($currentValue)}
Not an array: {typeof $currentValue} {JSON.stringify(path)} {JSON.stringify($currentValue).slice(0,120)}
Not an array: {typeof $currentValue}
{JSON.stringify(path)}
{JSON.stringify($currentValue).slice(0, 120)}
{:else if $currentValue?.length === 0}
No values are defined
{#if $messages.length > 0}
@ -102,7 +100,16 @@
{:else}
<Accordion>
{#each $currentValue as value, i (value)}
<CollapsedTagRenderingPreview {state} {isTagRenderingBlock} {schema} {currentValue} {value} {i} {singular} path={fusePath(i)} />
<CollapsedTagRenderingPreview
{state}
{isTagRenderingBlock}
{schema}
{currentValue}
{value}
{i}
{singular}
path={fusePath(i)}
/>
{/each}
</Accordion>
{/if}

View file

@ -8,9 +8,10 @@
export let state: EditJsonState<any>
export let path: (string | number)[] = []
export let schema: ConfigMeta = state.getSchema(<any> path)[0]
export let schema: ConfigMeta = state.getSchema(<any>path)[0]
let expertMode = state.expertMode
</script>
{#if schema === undefined}
<div>ERROR: no schema found for {path.join(".")}</div>
{:else if (schema.hints?.group !== "expert" || $expertMode) && schema.hints.group !== "hidden"}

View file

@ -220,10 +220,7 @@
{#if chosenOption !== undefined}
{#each subSchemas as subschema}
{#if $expertMode || subschema.hints?.group !== "expert"}
<SchemaBasedInput
{state}
path={[...subpath, subschema?.path?.at(-1) ?? "???"]}
/>
<SchemaBasedInput {state} path={[...subpath, subschema?.path?.at(-1) ?? "???"]} />
{:else if window.location.hostname === "127.0.0.1"}
<span class="subtle">Omitted expert question {subschema.path.join(".")}</span>
{/if}

View file

@ -29,7 +29,7 @@
const store = state.getStoreFor(path)
let value = store.data
let hasSeenIntro = UIEventSource.asBoolean(
LocalStorageSource.Get("studio-seen-tagrendering-tutorial", "false"),
LocalStorageSource.Get("studio-seen-tagrendering-tutorial", "false")
)
onMount(() => {
if (!hasSeenIntro.data) {
@ -42,24 +42,24 @@
* Should only be enabled for 'tagrenderings' in the theme, if the source is OSM
*/
let allowQuestions: Store<boolean> = state.configuration.mapD(
(config) => path.at(0) === "tagRenderings" && config.source?.["geoJson"] === undefined,
(config) => path.at(0) === "tagRenderings" && config.source?.["geoJson"] === undefined
)
let mappingsBuiltin: MappingConfigJson[] = []
let perLabel: Record<string, MappingConfigJson> = {}
{ // Build the list of options that one can choose for builtin questions
const forbidden = new Set( ["ignore_docs","all_tags"])
{
// Build the list of options that one can choose for builtin questions
const forbidden = new Set(["ignore_docs", "all_tags"])
for (const tr of questions.tagRenderings) {
if(forbidden.has(tr.id)){
if (forbidden.has(tr.id)) {
continue
}
let description = tr["description"] ?? tr["question"] ?? "No description available"
description = description["en"] ?? description
if (tr["labels"]) {
const labels: string[] = tr["labels"]
if(labels.some(l => forbidden.has(l))){
if (labels.some((l) => forbidden.has(l))) {
continue
}
for (const label of labels) {
@ -129,7 +129,7 @@
const freeformSchemaAll = <ConfigMeta[]>(
questionableTagRenderingSchemaRaw.filter(
(schema) => schema.path.length == 2 && schema.path[0] === "freeform" && $allowQuestions,
(schema) => schema.path.length == 2 && schema.path[0] === "freeform" && $allowQuestions
)
)
let freeformSchema = $expertMode
@ -138,7 +138,7 @@
const missing: string[] = questionableTagRenderingSchemaRaw
.filter(
(schema) =>
schema.path.length >= 1 && !items.has(schema.path[0]) && !ignored.has(schema.path[0]),
schema.path.length >= 1 && !items.has(schema.path[0]) && !ignored.has(schema.path[0])
)
.map((schema) => schema.path.join("."))
console.log({ state })
@ -146,7 +146,14 @@
{#if typeof $store === "string"}
<div class="low-interaction flex">
<TagRenderingEditable config={configBuiltin} selectedElement={undefined} {state} {tags} editMode={true} clss="w-full" />
<TagRenderingEditable
config={configBuiltin}
selectedElement={undefined}
{state}
{tags}
editMode={true}
clss="w-full"
/>
<slot name="upper-right" />
</div>
{:else}

View file

@ -42,11 +42,13 @@
undefined,
"Used to complete the login"
)
const fakeUser = UIEventSource.asBoolean( QueryParameters.GetQueryParameter("fake-user", "Test switch for fake login"))
const fakeUser = UIEventSource.asBoolean(
QueryParameters.GetQueryParameter("fake-user", "Test switch for fake login")
)
let osmConnection = new OsmConnection({
oauth_token,
checkOnlineRegularly: true,
fakeUser: fakeUser.data
fakeUser: fakeUser.data,
})
const expertMode = UIEventSource.asBoolean(
osmConnection.GetPreference("studio-expert-mode", "false", {

View file

@ -124,11 +124,11 @@
state.mapProperties.installCustomKeyboardHandler(viewport)
let canZoomIn = mapproperties.maxzoom.map(
(mz) => mapproperties.zoom.data < mz,
[mapproperties.zoom],
[mapproperties.zoom]
)
let canZoomOut = mapproperties.minzoom.map(
(mz) => mapproperties.zoom.data > mz,
[mapproperties.zoom],
[mapproperties.zoom]
)
function updateViewport() {
@ -165,7 +165,7 @@
onDestroy(
rasterLayer.addCallbackAndRunD((l) => {
rasterLayerName = l.properties.name
}),
})
)
let previewedImage = state.previewedImage
@ -196,7 +196,7 @@
let openMapButton: UIEventSource<HTMLElement> = new UIEventSource<HTMLElement>(undefined)
let openMenuButton: UIEventSource<HTMLElement> = new UIEventSource<HTMLElement>(undefined)
let openCurrentViewLayerButton: UIEventSource<HTMLElement> = new UIEventSource<HTMLElement>(
undefined,
undefined
)
let _openNewElementButton: HTMLButtonElement
let openNewElementButton: UIEventSource<HTMLElement> = new UIEventSource<HTMLElement>(undefined)