Chore: linting

This commit is contained in:
Pieter Vander Vennet 2024-04-13 02:40:21 +02:00
parent 4625ad9a5c
commit 097141f944
307 changed files with 5346 additions and 2147 deletions

View file

@ -6,10 +6,10 @@
*/
export let selected: UIEventSource<boolean>
let _c: boolean = selected.data ?? true
let id = `checkbox-input-${Math.round(Math.random()*100000000)}`
let id = `checkbox-input-${Math.round(Math.random() * 100000000)}`
$: selected.set(_c)
selected.addCallbackD(s => {
_c = s
selected.addCallbackD((s) => {
_c = s
})
</script>

View file

@ -10,7 +10,7 @@
*/
const dispatch = createEventDispatcher()
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 enabled: Store<boolean> = new ImmutableStore(true)
export let arialabel: Translation = undefined
</script>
@ -18,7 +18,11 @@
on:click={(e) => dispatch("click", e)}
on:keydown
use:ariaLabel={arialabel}
class={twJoin("pointer-events-auto relative h-fit w-fit rounded-full", cls, $enabled ? "" : "disabled")}
class={twJoin(
"pointer-events-auto relative h-fit w-fit rounded-full",
cls,
$enabled ? "" : "disabled"
)}
>
<slot />
</button>

View file

@ -5,13 +5,9 @@
imgSize?: string
extraClasses?: string
} = {}
</script>
<button
class={twMerge(options.extraClasses, "secondary no-image-background")}
on:click
>
<button class={twMerge(options.extraClasses, "secondary no-image-background")} on:click>
<slot name="image" />
<slot name="message" />
</button>

View file

@ -22,7 +22,7 @@ export default class SvelteUIElement<
private readonly _props: Props
private readonly _events: Events
private readonly _slots: Slots
private tag : "div" | "span" = "div"
private tag: "div" | "span" = "div"
constructor(svelteElement, props?: Props, events?: Events, slots?: Slots) {
super()
@ -32,7 +32,7 @@ export default class SvelteUIElement<
this._slots = slots
}
public setSpan(){
public setSpan() {
this.tag = "span"
return this
}

View file

@ -1,49 +1,48 @@
<script lang="ts">
/**
* THe panel containing all filter- and layerselection options
*/
/**
* THe panel containing all filter- and layerselection options
*/
import OverlayToggle from "./OverlayToggle.svelte"
import Filterview from "./Filterview.svelte"
import ThemeViewState from "../../Models/ThemeViewState"
import Translations from "../i18n/Translations"
import Tr from "../Base/Tr.svelte"
import Filter from "../../assets/svg/Filter.svelte"
import OverlayToggle from "./OverlayToggle.svelte"
import Filterview from "./Filterview.svelte"
import ThemeViewState from "../../Models/ThemeViewState"
import Translations from "../i18n/Translations"
import Tr from "../Base/Tr.svelte"
import Filter from "../../assets/svg/Filter.svelte"
export let state: ThemeViewState
let layout = state.layout
let allEnabled : boolean
let allDisabled: boolean
function updateEnableState(){
allEnabled = true
allDisabled = true
state.layerState.filteredLayers.forEach((v) => {
if(!v.layerDef.name){
return
}
allEnabled &&= v.isDisplayed.data
allDisabled &&= !v.isDisplayed.data
})
}
updateEnableState()
export let state: ThemeViewState
let layout = state.layout
let allEnabled: boolean
let allDisabled: boolean
function updateEnableState() {
allEnabled = true
allDisabled = true
state.layerState.filteredLayers.forEach((v) => {
if(!v.layerDef.name){
return
}
v.isDisplayed.addCallbackD(_ => updateEnableState())
if (!v.layerDef.name) {
return
}
allEnabled &&= v.isDisplayed.data
allDisabled &&= !v.isDisplayed.data
})
function enableAll(doEnable: boolean){
state.layerState.filteredLayers.forEach((v) => {
if(!v.layerDef.name){
return
}
v.isDisplayed.setData(doEnable)
})
}
updateEnableState()
state.layerState.filteredLayers.forEach((v) => {
if (!v.layerDef.name) {
return
}
v.isDisplayed.addCallbackD((_) => updateEnableState())
})
function enableAll(doEnable: boolean) {
state.layerState.filteredLayers.forEach((v) => {
if (!v.layerDef.name) {
return
}
v.isDisplayed.setData(doEnable)
})
}
</script>
<div class="m-2 flex flex-col">
@ -59,12 +58,12 @@
highlightedLayer={state.guistate.highlightedLayerInFilters}
/>
{/each}
<div class="flex self-end mt-1">
<div class="mt-1 flex self-end">
<button class="small" class:disabled={allEnabled} on:click={() => enableAll(true)}>
<Tr t={Translations.t.general.filterPanel.enableAll}/>
<Tr t={Translations.t.general.filterPanel.enableAll} />
</button>
<button class="small" class:disabled={allDisabled} on:click={() => enableAll(false)}>
<Tr t={Translations.t.general.filterPanel.disableAll}/>
<button class="small" class:disabled={allDisabled} on:click={() => enableAll(false)}>
<Tr t={Translations.t.general.filterPanel.disableAll} />
</button>
</div>

View file

@ -66,7 +66,7 @@
/>
</If>
<Tr t={filteredLayer.layerDef.name}/>
<Tr t={filteredLayer.layerDef.name} />
{#if $zoomlevel < layer.minzoom}
<span class="alert">
@ -82,7 +82,7 @@
<!-- There are three (and a half) modes of filters: a single checkbox, a radio button/dropdown or with searchable fields -->
{#if filter.options.length === 1 && filter.options[0].fields.length === 0}
<Checkbox selected={getBooleanStateFor(filter)}>
<Tr t={filter.options[0].question}/>
<Tr t={filter.options[0].question} />
</Checkbox>
{/if}
@ -94,7 +94,7 @@
<Dropdown value={getStateFor(filter)}>
{#each filter.options as option, i}
<option value={i}>
<Tr t={option.question}/>
<Tr t={option.question} />
</option>
{/each}
</Dropdown>

View file

@ -41,7 +41,7 @@
let compass = Orientation.singleton.alpha
let relativeBearing: Store<{ distance: string; bearing: Translation }> = compass.mapD(
(compass) => {
if(!distanceToCurrentLocation.data){
if (!distanceToCurrentLocation.data) {
return undefined
}
const bearing: Translation =

View file

@ -8,7 +8,7 @@
import ShowDataLayer from "../Map/ShowDataLayer"
import type {
FeatureSource,
FeatureSourceForLayer
FeatureSourceForLayer,
} from "../../Logic/FeatureSource/FeatureSource"
import SnappingFeatureSource from "../../Logic/FeatureSource/Sources/SnappingFeatureSource"
import FeatureSourceMerger from "../../Logic/FeatureSource/Sources/FeatureSourceMerger"
@ -72,7 +72,7 @@
allowMoving: new UIEventSource<boolean>(true),
allowZooming: new UIEventSource<boolean>(true),
minzoom: new UIEventSource<number>(18),
rasterLayer: UIEventSource.feedFrom(state.mapProperties.rasterLayer)
rasterLayer: UIEventSource.feedFrom(state.mapProperties.rasterLayer),
}
state?.showCurrentLocationOn(map)
@ -82,7 +82,7 @@
if (featuresForLayer) {
new ShowDataLayer(map, {
layer: targetLayer,
features: featuresForLayer
features: featuresForLayer,
})
}
}
@ -99,7 +99,7 @@
new ShowDataLayer(map, {
layer: layer.layer.layerDef,
zoomToFeatures: false,
features: layer
features: layer,
})
}
const snappedLocation = new SnappingFeatureSource(
@ -110,28 +110,30 @@
maxDistance: maxSnapDistance ?? 15,
allowUnsnapped: true,
snappedTo,
snapLocation: value
snapLocation: value,
}
)
const withCorrectedAttributes = new StaticFeatureSource(
snappedLocation.features.mapD(feats => feats.map(f => {
const properties = {
...f.properties,
...presetPropertiesUnpacked
}
properties["_referencing_ways"] = f.properties["snapped-to"]
return ({
...f,
properties
snappedLocation.features.mapD((feats) =>
feats.map((f) => {
const properties = {
...f.properties,
...presetPropertiesUnpacked,
}
properties["_referencing_ways"] = f.properties["snapped-to"]
return {
...f,
properties,
}
})
}))
)
)
// The actual point to be created, snapped at the new location
new ShowDataLayer(map, {
layer: targetLayer,
features: withCorrectedAttributes
features: withCorrectedAttributes,
})
withCorrectedAttributes.features.addCallbackAndRunD(f => console.log("Snapped point is", f))
withCorrectedAttributes.features.addCallbackAndRunD((f) => console.log("Snapped point is", f))
}
</script>

View file

@ -22,8 +22,7 @@
arialabel={Translations.t.general.labels.background}
on:click={() => state.guistate.backgroundLayerSelectionIsOpened.setData(true)}
>
<StyleLoadingIndicator map={map ?? state.map} rasterLayer={state.mapProperties.rasterLayer} >
<StyleLoadingIndicator map={map ?? state.map} rasterLayer={state.mapProperties.rasterLayer}>
<Square3Stack3dIcon class="h-6 w-6" />
</StyleLoadingIndicator>
{#if !hideTooltip}

View file

@ -13,7 +13,7 @@
export let layer: LayerConfig
export let selectedElement: Feature
let tags: UIEventSource<Record<string, string>> = state.featureProperties.getStore(
selectedElement.properties.id,
selectedElement.properties.id
)
$: {
tags = state.featureProperties.getStore(selectedElement.properties.id)
@ -43,7 +43,7 @@
class="no-weblate title-icons links-as-button mr-2 flex flex-row flex-wrap items-center gap-x-0.5 pt-0.5 sm:pt-1"
>
{#each layer.titleIcons as titleIconConfig}
{#if (titleIconConfig.condition?.matchesProperties($tags) ?? true) && (titleIconConfig.metacondition?.matchesProperties({ ...$metatags, ...$tags }) ?? true) && titleIconConfig.IsKnown($tags)}
{#if (titleIconConfig.condition?.matchesProperties($tags) ?? true) && (titleIconConfig.metacondition?.matchesProperties( { ...$metatags, ...$tags } ) ?? true) && titleIconConfig.IsKnown($tags)}
<div class={titleIconConfig.renderIconClass ?? "flex h-8 w-8 items-center"}>
<TagRenderingAnswer
config={titleIconConfig}
@ -58,28 +58,33 @@
{/each}
{#if $isTesting || $isDebugging}
<a class="subtle" href="https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Layers/{layer.id}.md"
target="_blank" rel="noreferrer noopener ">{layer.id}</a>
<a
class="subtle"
href="https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Layers/{layer.id}.md"
target="_blank"
rel="noreferrer noopener "
>
{layer.id}
</a>
{/if}
</div>
</div>
{/if}
</div>
<slot name="close-button">
<button
class="mt-2 h-fit shrink-0 rounded-full border-none p-0"
on:click={() => state.selectedElement.setData(undefined)}
style="border: 0 !important; padding: 0 !important;"
use:ariaLabel={Translations.t.general.backToMap}
>
<XCircleIcon aria-hidden={true} class="h-8 w-8" />
</button>
<button
class="mt-2 h-fit shrink-0 rounded-full border-none p-0"
on:click={() => state.selectedElement.setData(undefined)}
style="border: 0 !important; padding: 0 !important;"
use:ariaLabel={Translations.t.general.backToMap}
>
<XCircleIcon aria-hidden={true} class="h-8 w-8" />
</button>
</slot>
</div>
<style>
:global(.title-icons a) {
display: block !important;
}
:global(.title-icons a) {
display: block !important;
}
</style>

View file

@ -20,19 +20,22 @@
selectedElement.properties.id
)
let layer: LayerConfig = selectedElement.properties.id === "settings" ? UserRelatedState.usersettingsConfig : state.layout.getMatchingLayer(tags.data)
let layer: LayerConfig =
selectedElement.properties.id === "settings"
? UserRelatedState.usersettingsConfig
: state.layout.getMatchingLayer(tags.data)
let stillMatches = tags.map(tags => !layer?.source?.osmTags || layer.source.osmTags?.matchesProperties(tags))
let stillMatches = tags.map(
(tags) => !layer?.source?.osmTags || layer.source.osmTags?.matchesProperties(tags)
)
let _metatags: Record<string, string>
if(state?.userRelatedState?.preferencesAsTags){
onDestroy(
state.userRelatedState.preferencesAsTags.addCallbackAndRun((tags) => {
_metatags = tags
}),
)
if (state?.userRelatedState?.preferencesAsTags) {
onDestroy(
state.userRelatedState.preferencesAsTags.addCallbackAndRun((tags) => {
_metatags = tags
})
)
}
let knownTagRenderings: Store<TagRenderingConfig[]> = tags.mapD((tgs) =>
@ -40,8 +43,8 @@
(config) =>
(config.condition?.matchesProperties(tgs) ?? true) &&
(config.metacondition?.matchesProperties({ ...tgs, ..._metatags }) ?? true) &&
config.IsKnown(tgs),
),
config.IsKnown(tgs)
)
)
</script>
@ -52,13 +55,12 @@
{:else if $tags._deleted === "yes"}
<div class="flex w-full flex-col p-2">
<div aria-live="assertive" class="alert flex items-center justify-center self-stretch">
<Delete_icon class="w-8 h-8 m-2" />
<Delete_icon class="m-2 h-8 w-8" />
<Tr t={Translations.t.delete.isDeleted} />
</div>
<BackButton clss="self-stretch mt-4" on:click={() => state.selectedElement.setData(undefined)}>
<Tr t={Translations.t.general.returnToTheMap} />
</BackButton>
</div>
{:else}
<div

View file

@ -71,10 +71,8 @@
</script>
<div class="flex flex-col">
<div class="flex justify-between items-start">
<div class="flex items-start justify-between">
<div class="flex flex-col">
<Tr t={tr.intro} />
<div class="flex">
{#if typeof navigator?.share === "function"}
@ -92,10 +90,10 @@
</div>
</div>
</div>
<ToSvelte construct={() => new Img(new Qr(linkToShare).toImageElement(125)).SetStyle(
"width: 125px"
)} />
<ToSvelte
construct={() => new Img(new Qr(linkToShare).toImageElement(125)).SetStyle("width: 125px")}
/>
</div>
<div class="flex justify-center">
@ -106,8 +104,7 @@
<Tr t={tr.embedIntro} />
<div class="flex flex-col interactive p-1">
<div class="interactive flex flex-col p-1">
<div class="literal-code m-1">
&lt;span class="literal-code iframe-code-block"&gt; <br />
&lt;iframe src="{linkToShare}"
@ -127,7 +124,7 @@
</label>
<label>
<input bind:checked={enableLogin} type="checkbox" id="share_enable_login"/>
<input bind:checked={enableLogin} type="checkbox" id="share_enable_login" />
<Tr t={tr.fsUserbadge} />
</label>
</div>

View file

@ -17,10 +17,9 @@ export default class StatisticsForLayerPanel extends VariableUiElement {
return new Loading("Loading data")
}
if (features.length === 0) {
return new Combine([
"No elements in view for layer ",
layer.id
]).SetClass("block")
return new Combine(["No elements in view for layer ", layer.id]).SetClass(
"block"
)
}
const els: BaseUIElement[] = []
const featuresForLayer = features

View file

@ -8,8 +8,8 @@ import { OsmFeature } from "../../Models/OsmFeature"
export interface TagRenderingChartOptions {
groupToOtherCutoff?: 3 | number
sort?: boolean,
hideUnkown?: boolean,
sort?: boolean
hideUnkown?: boolean
hideNotApplicable?: boolean
}
@ -21,8 +21,8 @@ export class StackedRenderingChart extends ChartJs {
period: "day" | "month"
groupToOtherCutoff?: 3 | number
// If given, take the sum of these fields to get the feature weight
sumFields?: string[],
hideUnknown?: boolean,
sumFields?: string[]
hideUnknown?: boolean
hideNotApplicable?: boolean
}
) {
@ -30,7 +30,7 @@ export class StackedRenderingChart extends ChartJs {
sort: true,
groupToOtherCutoff: options?.groupToOtherCutoff,
hideNotApplicable: options?.hideNotApplicable,
hideUnkown: options?.hideUnknown
hideUnkown: options?.hideUnknown,
})
if (labels === undefined || data === undefined) {
console.error(
@ -121,13 +121,13 @@ export class StackedRenderingChart extends ChartJs {
datasets.push({
data: countsPerDay,
backgroundColor,
label
label,
})
}
const perDayData = {
labels: trimmedDays,
datasets
datasets,
}
const config = <ChartConfiguration>{
@ -136,17 +136,17 @@ export class StackedRenderingChart extends ChartJs {
options: {
responsive: true,
legend: {
display: false
display: false,
},
scales: {
x: {
stacked: true
stacked: true,
},
y: {
stacked: true
}
}
}
stacked: true,
},
},
},
}
super(config)
}
@ -199,7 +199,7 @@ export default class TagRenderingChart extends Combine {
"rgba(255, 206, 86, 0.2)",
"rgba(75, 192, 192, 0.2)",
"rgba(153, 102, 255, 0.2)",
"rgba(255, 159, 64, 0.2)"
"rgba(255, 159, 64, 0.2)",
]
public static readonly borderColors = [
@ -208,7 +208,7 @@ export default class TagRenderingChart extends Combine {
"rgba(255, 206, 86, 1)",
"rgba(75, 192, 192, 1)",
"rgba(153, 102, 255, 1)",
"rgba(255, 159, 64, 1)"
"rgba(255, 159, 64, 1)",
]
/**
@ -244,12 +244,12 @@ export default class TagRenderingChart extends Combine {
const borderColor = [
TagRenderingChart.unkownBorderColor,
TagRenderingChart.otherBorderColor,
TagRenderingChart.notApplicableBorderColor
TagRenderingChart.notApplicableBorderColor,
]
const backgroundColor = [
TagRenderingChart.unkownColor,
TagRenderingChart.otherColor,
TagRenderingChart.notApplicableColor
TagRenderingChart.notApplicableColor,
]
while (borderColor.length < data.length) {
@ -281,17 +281,17 @@ export default class TagRenderingChart extends Combine {
backgroundColor,
borderColor,
borderWidth: 1,
label: undefined
}
]
label: undefined,
},
],
},
options: {
plugins: {
legend: {
display: !barchartMode
}
}
}
display: !barchartMode,
},
},
},
}
const chart = new ChartJs(config).SetClass(options?.chartclasses ?? "w-32 h-32")
@ -302,7 +302,7 @@ export default class TagRenderingChart extends Combine {
super([
options?.includeTitle ? tagRendering.question.Clone() ?? tagRendering.id : undefined,
chart
chart,
])
this.SetClass("block")
@ -402,15 +402,10 @@ export default class TagRenderingChart extends Combine {
labels.push("Other")
if (!options.hideNotApplicable) {
data.push(notApplicable)
labels.push(
"Not applicable"
)
labels.push("Not applicable")
}
data.push(...categoryCounts,
...otherData)
labels.push(
...(mappings?.map((m) => m.then.txt) ?? []),
...otherLabels)
data.push(...categoryCounts, ...otherData)
labels.push(...(mappings?.map((m) => m.then.txt) ?? []), ...otherLabels)
return { labels, data }
}

View file

@ -85,10 +85,8 @@
</script>
{#if theme.id !== personal.id || $unlockedPersonal}
<a
class={"w-full button text-ellipsis"}
href={$href}
> <img src={theme.icon} class="m-1 mr-2 block h-11 w-11 sm:m-2 sm:mr-4" alt="" />
<a class={"button w-full text-ellipsis"} href={$href}>
<img src={theme.icon} class="m-1 mr-2 block h-11 w-11 sm:m-2 sm:mr-4" alt="" />
<span class="flex flex-col overflow-hidden text-ellipsis">
<Tr t={title} />
@ -97,5 +95,6 @@
<Tr t={Translations.t.general.morescreen.enterToOpen} />
</span>
{/if}
</span></a>
</span>
</a>
{/if}

View file

@ -29,13 +29,13 @@
const splitpoint_style = new LayerConfig(
<LayerConfigJson>split_point,
"(BUILTIN) SplitRoadWizard.ts",
true,
true
)
const splitroad_style = new LayerConfig(
<LayerConfigJson>split_road,
"(BUILTIN) SplitRoadWizard.ts",
true,
true
)
/**
@ -105,7 +105,7 @@
})
</script>
<div class="h-full w-full relative">
<div class="relative h-full w-full">
<MaplibreMap {map} mapProperties={adaptor} />
<SmallZoomButtons {adaptor} />
</div>

View file

@ -38,7 +38,7 @@
tags.data,
{
theme: state.layout.id,
changeType: "import"
changeType: "import",
}
)
await state.changes.applyChanges(await change.CreateChangeDescriptions())
@ -47,43 +47,51 @@
let _country = $tags["_country"]
let mockPropertiesOsm = { id: feature.properties.id, [key]: $tags[key], _country }
let mockPropertiesExternal = { id: feature.properties.id, [key]: externalProperties[key], _country }
let trsWithKeys = layer.tagRenderings.filter(tr => {
const keys: string[] = [].concat(...tr.usedTags().map(t => t.usedKeys()))
let mockPropertiesExternal = {
id: feature.properties.id,
[key]: externalProperties[key],
_country,
}
let trsWithKeys = layer.tagRenderings.filter((tr) => {
const keys: string[] = [].concat(...tr.usedTags().map((t) => t.usedKeys()))
return keys.indexOf(key) >= 0
})
let renderingBoth = trsWithKeys.find(tr => tr.IsKnown(mockPropertiesOsm) && tr.IsKnown(mockPropertiesExternal))
let renderingExternal = renderingBoth ?? trsWithKeys.find(tr => tr.IsKnown(mockPropertiesExternal))
let renderingBoth = trsWithKeys.find(
(tr) => tr.IsKnown(mockPropertiesOsm) && tr.IsKnown(mockPropertiesExternal)
)
let renderingExternal =
renderingBoth ?? trsWithKeys.find((tr) => tr.IsKnown(mockPropertiesExternal))
let onOverwrite = false
const t = Translations.t.external
</script>
<div>
<div class="py-1 px-2 interactive flex w-full justify-between">
<div class="interactive flex w-full justify-between py-1 px-2">
<div class="flex flex-col">
<div>
{#if renderingExternal}
<TagRenderingAnswer tags={new UIEventSource(mockPropertiesExternal)} selectedElement={feature}
config={renderingExternal}
{layer} {state} />
<TagRenderingAnswer
tags={new UIEventSource(mockPropertiesExternal)}
selectedElement={feature}
config={renderingExternal}
{layer}
{state}
/>
{:else}
<div class="flex gap-x-1 items-center">
<b>{key}</b>{externalProperties[key]}
<div class="flex items-center gap-x-1">
<b>{key}</b>
{externalProperties[key]}
</div>
{/if}
</div>
{#if !readonly && ( $isTesting || $isDebug || $showTags === "yes" || $showTags === "always" || $showTags === "full")}
{#if !readonly && ($isTesting || $isDebug || $showTags === "yes" || $showTags === "always" || $showTags === "full")}
<div class="subtle text-sm">
{#if $tags[key] !== undefined}
<span>
OSM:
{key}={$tags[key]}
</span>
<span>
OSM:
{key}={$tags[key]}
</span>
{/if}
<span>
{key}= {externalProperties[key]}
@ -92,21 +100,20 @@
{/if}
</div>
{#if !readonly}
{#if currentStep === "init"}
<button class="small" on:click={() => apply(key)}
on:mouseover={() => onOverwrite = true}
on:focus={() => onOverwrite = true}
on:blur={() => onOverwrite = false}
on:mouseout={() => onOverwrite = false }
<button
class="small"
on:click={() => apply(key)}
on:mouseover={() => (onOverwrite = true)}
on:focus={() => (onOverwrite = true)}
on:blur={() => (onOverwrite = false)}
on:mouseout={() => (onOverwrite = false)}
>
{#if $tags[key]}
<Tr t={t.overwrite} />
{:else}
<Tr t={t.apply} />
{/if}
</button>
{:else if currentStep === "applying"}
@ -114,7 +121,6 @@
{:else if currentStep === "done"}
<div class="thanks">
<Tr t={t.done} />
</div>
{:else}
<div class="alert">
@ -122,22 +128,26 @@
</div>
{/if}
{/if}
</div>
{#if $tags[key] && $tags[key] !== externalProperties[key]}
<div class:glowing-shadow={onOverwrite}>
<span class="subtle">
<Tr t={t.currentInOsmIs} />
</span>
<span class="subtle">
<Tr t={t.currentInOsmIs} />
</span>
{#if renderingBoth}
<TagRenderingAnswer tags={new UIEventSource(mockPropertiesOsm)} selectedElement={feature} config={renderingBoth}
{layer} {state} />
<TagRenderingAnswer
tags={new UIEventSource(mockPropertiesOsm)}
selectedElement={feature}
config={renderingBoth}
{layer}
{state}
/>
{:else}
<div class="flex gap-x-2 items-center">
<b>{key}</b> {$tags[key]}
<div class="flex items-center gap-x-2">
<b>{key}</b>
{$tags[key]}
</div>
{/if}
</div>
{/if}
</div>

View file

@ -49,32 +49,30 @@
return osmProperties[k] === undefined && typeof externalProperties[k] === "string"
})
// let same = propertyKeysExternal.filter((key) => osmProperties[key] === externalProperties[key])
let different = propertyKeysExternal.filter(
(key) => {
if (key.startsWith("_")) {
return false
}
if (osmProperties[key] === undefined) {
return false
}
if (typeof externalProperties[key] !== "string") {
return false
}
if (osmProperties[key] === externalProperties[key]) {
return false
}
if (key === "website") {
const osmCanon = new URL(osmProperties[key]).toString()
const externalCanon = new URL(externalProperties[key]).toString()
if (osmCanon === externalCanon) {
return false
}
}
return true
let different = propertyKeysExternal.filter((key) => {
if (key.startsWith("_")) {
return false
}
)
if (osmProperties[key] === undefined) {
return false
}
if (typeof externalProperties[key] !== "string") {
return false
}
if (osmProperties[key] === externalProperties[key]) {
return false
}
if (key === "website") {
const osmCanon = new URL(osmProperties[key]).toString()
const externalCanon = new URL(externalProperties[key]).toString()
if (osmCanon === externalCanon) {
return false
}
}
return true
})
let currentStep: "init" | "applying_all" | "all_applied" = "init"
let applyAllHovered = false
@ -84,12 +82,13 @@
const tagsToApply = missing.map((k) => new Tag(k, externalProperties[k]))
const change = new ChangeTagAction(tags.data.id, new And(tagsToApply), tags.data, {
theme: state.layout.id,
changeType: "import"
changeType: "import",
})
await state.changes.applyChanges(await change.CreateChangeDescriptions())
currentStep = "all_applied"
}
</script>
{#if propertyKeysExternal.length === 0 && knownImages.size + unknownImages.length === 0}
<Tr cls="subtle" t={t.noDataLoaded} />
{:else if unknownImages.length === 0 && missing.length === 0 && different.length === 0}
@ -98,9 +97,9 @@
<Tr t={t.allIncluded} />
</div>
{:else}
<div class="low-interaction p-1 border-interactive">
<div class="low-interaction border-interactive p-1">
{#if !readonly}
<Tr t={t.loadedFrom.Subs({url: sourceUrl, source: sourceUrl})} />
<Tr t={t.loadedFrom.Subs({ url: sourceUrl, source: sourceUrl })} />
<h3>
<Tr t={t.conflicting.title} />
</h3>
@ -113,25 +112,41 @@
{#if different.length > 0}
{#each different as key}
<div class="mx-2 rounded-2xl">
<ComparisonAction {key} {state} {tags} {externalProperties} {layer} {feature} {readonly} />
<ComparisonAction
{key}
{state}
{tags}
{externalProperties}
{layer}
{feature}
{readonly}
/>
</div>
{/each}
{/if}
{#if missing.length > 0}
{#if currentStep === "init"}
{#each missing as key}
<div class:glowing-shadow={applyAllHovered} class="mx-2 rounded-2xl">
<ComparisonAction {key} {state} {tags} {externalProperties} {layer} {feature} {readonly} />
<ComparisonAction
{key}
{state}
{tags}
{externalProperties}
{layer}
{feature}
{readonly}
/>
</div>
{/each}
{#if !readonly && missing.length > 1}
<button on:click={() => applyAllMissing()}
on:mouseover={() => applyAllHovered = true}
on:focus={() => applyAllHovered = true}
on:blur={() => applyAllHovered = false}
on:mouseout={() => applyAllHovered = false }
<button
on:click={() => applyAllMissing()}
on:mouseover={() => (applyAllHovered = true)}
on:focus={() => (applyAllHovered = true)}
on:blur={() => (applyAllHovered = false)}
on:mouseout={() => (applyAllHovered = false)}
>
<Tr t={t.applyAll} />
</button>
@ -144,7 +159,6 @@
</div>
{/if}
{/if}
</div>
{#if unknownImages.length > 0}
@ -166,13 +180,13 @@
{tags}
{state}
image={{
pictureUrl: image,
provider: "Velopark",
thumbUrl: image,
details: undefined,
coordinates: undefined,
osmTags: { image },
}}
pictureUrl: image,
provider: "Velopark",
thumbUrl: image,
details: undefined,
coordinates: undefined,
osmTags: { image },
}}
{feature}
{layer}
/>
@ -181,10 +195,8 @@
{/if}
{#if externalProperties["_last_edit_timestamp"] !== undefined}
<span class="subtle text-sm">
External data has been last modified on {externalProperties["_last_edit_timestamp"]}
External data has been last modified on {externalProperties["_last_edit_timestamp"]}
</span>
{/if}
</div>
{/if}

View file

@ -1,34 +1,39 @@
<script lang="ts">
/**
* The comparison tool loads json-data from a speficied URL, eventually post-processes it
* and compares it with the current object
*/
import Loading from "../Base/Loading.svelte"
import type { SpecialVisualizationState } from "../SpecialVisualization"
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import ComparisonTable from "./ComparisonTable.svelte"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import type { Feature } from "geojson"
import type { OsmTags } from "../../Models/OsmFeature"
import Translations from "../i18n/Translations"
import Tr from "../Base/Tr.svelte"
/**
* The comparison tool loads json-data from a speficied URL, eventually post-processes it
* and compares it with the current object
*/
import Loading from "../Base/Loading.svelte"
import type { SpecialVisualizationState } from "../SpecialVisualization"
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import ComparisonTable from "./ComparisonTable.svelte"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import type { Feature } from "geojson"
import type { OsmTags } from "../../Models/OsmFeature"
import Translations from "../i18n/Translations"
import Tr from "../Base/Tr.svelte"
export let externalData: Store<{ success: {content: Record<string, string> } } | { error: string } | undefined | null /* null if no URL is found, undefined if loading*/>
export let state: SpecialVisualizationState
export let tags: UIEventSource<OsmTags>
export let layer: LayerConfig
export let feature: Feature
export let readonly = false
export let sourceUrl: Store<string>
export let externalData: Store<
| { success: { content: Record<string, string> } }
| { error: string }
| undefined
| null /* null if no URL is found, undefined if loading*/
>
export let state: SpecialVisualizationState
export let tags: UIEventSource<OsmTags>
export let layer: LayerConfig
export let feature: Feature
export let readonly = false
export let sourceUrl: Store<string>
</script>
{#if !$sourceUrl}
<!-- empty block -->
{:else if $externalData === undefined}
<Loading/>
<Loading />
{:else if $externalData["error"] !== undefined}
<div class="alert flex">
<Tr t={Translations.t.general.error}/>
<Tr t={Translations.t.general.error} />
{$externalData["error"]}
</div>
{:else if $externalData["success"] !== undefined}

View file

@ -13,10 +13,7 @@
export let extension: string
export let mimetype: string
export let construct: (
title: string,
status?: UIEventSource<string>
) => Promise<Blob | string>
export let construct: (title: string, status?: UIEventSource<string>) => Promise<Blob | string>
export let mainText: Translation
export let helperText: Translation
@ -28,7 +25,7 @@
let status: UIEventSource<string> = new UIEventSource<string>(undefined)
async function clicked() {
isExporting = true
const gpsLayer = state.layerState.filteredLayers.get(<PriviligedLayerType>"gps_location")
state.userRelatedState.preferencesAsTags.data["__showTimeSensitiveIcons"] = "no"
state.userRelatedState.preferencesAsTags.ping()

View file

@ -38,7 +38,7 @@
mapExtent: state.mapProperties.bounds.data,
width: maindiv.offsetWidth,
height: maindiv.offsetHeight,
noSelfIntersectingLines
noSelfIntersectingLines,
})
}
@ -46,13 +46,17 @@
let customHeight = LocalStorageSource.Get("custom-png-height", "20")
async function offerCustomPng(): Promise<Blob> {
console.log("Creating a custom size png with dimensions", customWidth.data + "mm *", customHeight.data + "mm")
console.log(
"Creating a custom size png with dimensions",
customWidth.data + "mm *",
customHeight.data + "mm"
)
const creator = new PngMapCreator(state, {
height: Number(customHeight.data), width: Number(customWidth.data)
height: Number(customHeight.data),
width: Number(customWidth.data),
})
return await creator.CreatePng("belowmap")
}
</script>
{#if $isLoading}
@ -123,25 +127,26 @@
{/each}
</div>
<div class="low-interaction p-2 mt-4">
<div class="low-interaction mt-4 p-2">
<h3 class="m-0 mb-2">
<Tr t={t.custom.title}/></h3>
<div class="flex">
<Tr t={t.custom.width} />
<ValidatedInput {state} type="pnat" value={customWidth} />
</div>
<div class="flex">
<Tr t={t.custom.height} />
<ValidatedInput {state} type="pnat" value={customHeight} />
</div>
<DownloadButton
mainText={t.custom.download.Subs({width: $customWidth, height: $customHeight})}
helperText={t.custom.downloadHelper}
extension="png"
construct={() => offerCustomPng()}
{state}
mimetype="image/png"
/>
<Tr t={t.custom.title} />
</h3>
<div class="flex">
<Tr t={t.custom.width} />
<ValidatedInput {state} type="pnat" value={customWidth} />
</div>
<div class="flex">
<Tr t={t.custom.height} />
<ValidatedInput {state} type="pnat" value={customHeight} />
</div>
<DownloadButton
mainText={t.custom.download.Subs({ width: $customWidth, height: $customHeight })}
helperText={t.custom.downloadHelper}
extension="png"
construct={() => offerCustomPng()}
{state}
mimetype="image/png"
/>
</div>
<Tr cls="link-underline" t={t.licenseInfo} />

View file

@ -38,7 +38,7 @@
</div>
{/if}
<div class="flex justify-between w-full gap-x-1">
<div class="flex w-full justify-between gap-x-1">
{#if $license.license !== undefined || $license.licenseShortName !== undefined}
<div>
{$license?.license ?? $license?.licenseShortName}
@ -58,8 +58,6 @@
{$license.date.toLocaleDateString()}
</div>
{/if}
</div>
</div>
{/if}

View file

@ -1,15 +1,13 @@
<script lang="ts">
import Tr from "../Base/Tr.svelte"
import Translations from "../i18n/Translations"
import { XCircleIcon } from "@babeard/svelte-heroicons/solid"
export let failed: number
const t = Translations.t.image
</script>
<div class="alert flex">
<div class="alert flex">
<div class="flex flex-col items-start">
{#if failed === 1}
<Tr t={t.upload.one.failed} />
@ -20,7 +18,7 @@
<Tr cls="text-xs" t={t.upload.failReasonsAdvanced} />
</div>
<button
class="mt-2 h-fit shrink-0 rounded-full border-none p-0 pointer-events-auto"
class="pointer-events-auto mt-2 h-fit shrink-0 rounded-full border-none p-0"
on:click
style="border: 0 !important; padding: 0 !important;"
>

View file

@ -29,7 +29,9 @@
</script>
{#if $debugging}
<div class="low-interaction">Started {$uploadStarted} Done {$uploadFinished} Retry {$retried} Err {$failed}</div>
<div class="low-interaction">
Started {$uploadStarted} Done {$uploadFinished} Retry {$retried} Err {$failed}
</div>
{/if}
{#if dismissed === $uploadStarted}
<!-- We don't show anything as we ignore this number of failed items-->
@ -39,18 +41,18 @@
<Tr cls="thanks" t={t.upload.one.done} />
{/if}
{:else if $failed === 1}
<UploadFailedMessage failed={$failed} on:click={() => dismissed = $failed}/>
<UploadFailedMessage failed={$failed} on:click={() => (dismissed = $failed)} />
{:else if $retried === 1}
<div class="alert">
<Loading>
<Tr t={t.upload.one.retrying} />
</Loading>
<Loading>
<Tr t={t.upload.one.retrying} />
</Loading>
</div>
{:else}
<div class="alert">
<Loading>
<Tr t={t.upload.one.uploading} />
</Loading>
<Loading>
<Tr t={t.upload.one.uploading} />
</Loading>
</div>
{/if}
{:else if $uploadStarted > 1}
@ -75,7 +77,6 @@
</Loading>
{/if}
{#if $failed > 0}
<UploadFailedMessage failed={$failed} on:click={() => dismissed = $failed}/>
<UploadFailedMessage failed={$failed} on:click={() => (dismissed = $failed)} />
{/if}
{/if}

View file

@ -67,7 +67,7 @@
if (!rangeIsShown) {
new ShowDataLayer(map, {
layer: new LayerConfig(<any> boundsdisplay),
layer: new LayerConfig(<any>boundsdisplay),
features: new StaticFeatureSource([
turf.circle(c, maxDistanceInMeters, {
units: "meters",
@ -84,7 +84,11 @@
<div class="min-h-32 relative h-full cursor-pointer overflow-hidden">
<div class="absolute top-0 left-0 h-full w-full cursor-pointer">
<MaplibreMap center={{ lng: initialCoordinate.lon, lat: initialCoordinate.lat }} {map} mapProperties={mla}/>
<MaplibreMap
center={{ lng: initialCoordinate.lon, lat: initialCoordinate.lat }}
{map}
mapProperties={mla}
/>
</div>
<div

View file

@ -64,13 +64,13 @@
update()
})
)
</script>
<div class="flex flex-col gap-y-1">
<div class="interactive m-1 mt-2 flex space-x-1 font-bold">
<span>
{prefix}
</span>
<span>
{prefix}
</span>
<select bind:value={$currentLang}>
{#each allLanguages as language}
<option value={language}>
@ -89,14 +89,18 @@
on:submit={() => dispatch("submit")}
/>
<span>
{postfix}
</span>
{postfix}
</span>
</div>
You have currently set translations for
<ul>
{#each Object.keys($translations) as l}
<li><button class="small" on:click={() => currentLang.setData(l)}><b>{l}:</b> {$translations[l]}</button></li>
<li>
<button class="small" on:click={() => currentLang.setData(l)}>
<b>{l}:</b>
{$translations[l]}
</button>
</li>
{/each}
</ul>
</div>

View file

@ -61,7 +61,7 @@ export default class InputHelpers {
mapProperties = { ...mapProperties, zoom: new UIEventSource<number>(zoom) }
}
if (!mapProperties.rasterLayer) {
/* mapProperties = {
/* mapProperties = {
...mapProperties, rasterLayer: properties?.mapProperties?.rasterLayer
}*/
}
@ -76,8 +76,11 @@ export default class InputHelpers {
const args = inputHelperOptions.args ?? []
const searchKey: string = <string>args[0] ?? "name"
const searchFor: string = searchKey.split(";").map(k => inputHelperOptions.feature?.properties[k]?.toLowerCase())
.find(foundValue => !!foundValue) ?? ""
const searchFor: string =
searchKey
.split(";")
.map((k) => inputHelperOptions.feature?.properties[k]?.toLowerCase())
.find((foundValue) => !!foundValue) ?? ""
let searchForValue: UIEventSource<string> = new UIEventSource(searchFor)
const options: any = args[1]
@ -125,7 +128,7 @@ export default class InputHelpers {
value,
searchText: searchForValue,
instanceOf,
notInstanceOf
notInstanceOf,
})
}
}

View file

@ -47,31 +47,31 @@
<LanguageIcon class="mr-1 h-4 w-4 shrink-0" aria-hidden="true" />
</label>
<Dropdown cls="max-w-full" value={assignTo} id="pick-language">
{#if preferredFiltered}
{#each preferredFiltered as language}
<option value={language} class="font-bold">
{native[language] ?? ""}
{#if language !== $current}
({language_translations[language]?.[$current] ?? language})
{/if}
</option>
{/each}
<option disabled />
{/if}
{#each availableLanguages.filter((l) => l !== "_context") as language}
<Dropdown cls="max-w-full" value={assignTo} id="pick-language">
{#if preferredFiltered}
{#each preferredFiltered as language}
<option value={language} class="font-bold">
{native[language] ?? ""}
{#if language !== $current}
{#if language_translations[language]?.[$current] !== undefined}
({language_translations[language]?.[$current] + " - " + language ?? language})
{:else}
({language})
{/if}
({language_translations[language]?.[$current] ?? language})
{/if}
</option>
{/each}
</Dropdown>
<option disabled />
{/if}
{#each availableLanguages.filter((l) => l !== "_context") as language}
<option value={language} class="font-bold">
{native[language] ?? ""}
{#if language !== $current}
{#if language_translations[language]?.[$current] !== undefined}
({language_translations[language]?.[$current] + " - " + language ?? language})
{:else}
({language})
{/if}
{/if}
</option>
{/each}
</Dropdown>
</form>
{/if}

View file

@ -51,5 +51,4 @@ export default class OpeningHoursValidator extends Validator {
])
)
}
}

View file

@ -45,7 +45,7 @@ export default class UrlValidator extends Validator {
"pk_medium",
"pk_campaign",
"pk_content",
"pk_kwd"
"pk_kwd",
]
for (const dontLike of blacklistedTrackingParams) {
url.searchParams.delete(dontLike.toLowerCase())

View file

@ -26,13 +26,13 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
"dragRotate",
"dragPan",
"keyboard",
"touchZoomRotate"
"touchZoomRotate",
]
private static maplibre_zoom_handlers = [
"scrollZoom",
"boxZoom",
"doubleClickZoom",
"touchZoomRotate"
"touchZoomRotate",
]
readonly location: UIEventSource<{ lon: number; lat: number }>
readonly zoom: UIEventSource<number>
@ -62,8 +62,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
if (!MapLibreAdaptor.pmtilesInited) {
maplibregl.addProtocol("pmtiles", new Protocol().tile)
MapLibreAdaptor.pmtilesInited = true
console.log("PM-tiles protocol added" +
"")
console.log("PM-tiles protocol added" + "")
}
this._maplibreMap = maplibreMap
@ -113,7 +112,6 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
}
maplibreMap.addCallbackAndRunD((map) => {
map.on("load", () => {
self.MoveMapToCurrentLoc(self.location.data)
self.SetZoom(self.zoom.data)
@ -216,9 +214,9 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
return {
map: mlmap,
ui: new SvelteUIElement(MaplibreMap, {
map: mlmap
map: mlmap,
}),
mapproperties: new MapLibreAdaptor(mlmap)
mapproperties: new MapLibreAdaptor(mlmap),
}
}
@ -286,7 +284,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
) {
const event = {
date: new Date(),
key: key
key: key,
}
for (let i = 0; i < this._onKeyNavigation.length; i++) {
@ -330,13 +328,19 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
rescaleIcons: number,
pixelRatio: number
) {
{
const allimages = element.getElementsByTagName("img")
for (const img of Array.from(allimages)) {
let isLoaded: boolean = false
while (!isLoaded) {
console.log("Waiting for image", img.src, "to load", img.complete, img.naturalWidth, img)
console.log(
"Waiting for image",
img.src,
"to load",
img.complete,
img.naturalWidth,
img
)
await Utils.waitFor(250)
isLoaded = img.complete && img.width > 0
}
@ -349,22 +353,31 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
element.style.transform = ""
const offset = style.match(/translate\(([-0-9]+)%, ?([-0-9]+)%\)/)
let labels =<HTMLElement[]> Array.from(element.getElementsByClassName("marker-label"))
const origLabelTransforms = labels.map(l => l.style.transform)
let labels = <HTMLElement[]>Array.from(element.getElementsByClassName("marker-label"))
const origLabelTransforms = labels.map((l) => l.style.transform)
// We save the original width (`w`) and height (`h`) in order to restore them later on
const w = element.style.width
const h = Number(element.style.height)
const targetW = Math.max(element.getBoundingClientRect().width * 4,
...labels.map(l => l.getBoundingClientRect().width))
const targetH = element.getBoundingClientRect().height +
Math.max(...labels.map(l => l.getBoundingClientRect().height * 2 /* A bit of buffer to catch eventual 'margin-top'*/))
const targetW = Math.max(
element.getBoundingClientRect().width * 4,
...labels.map((l) => l.getBoundingClientRect().width)
)
const targetH =
element.getBoundingClientRect().height +
Math.max(
...labels.map(
(l) =>
l.getBoundingClientRect().height *
2 /* A bit of buffer to catch eventual 'margin-top'*/
)
)
// Force a wider view for icon badges
element.style.width = targetW + "px"
// Force more height to include labels
element.style.height = targetH + "px"
element.classList.add("w-full", "flex", "flex-col", "items-center")
labels.forEach(l => {
labels.forEach((l) => {
l.style.transform = ""
})
await Utils.awaitAnimationFrame()
@ -386,13 +399,12 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
y *= pixelRatio
try {
const xdiff = img.width * rescaleIcons / 2
const xdiff = (img.width * rescaleIcons) / 2
drawOn.drawImage(img, x - xdiff, y, img.width * rescaleIcons, img.height * rescaleIcons)
} catch (e) {
console.log("Could not draw image because of", e)
}
element.classList.remove("w-full", "flex", "flex-col", "items-center")
}
/**
@ -461,7 +473,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
const bounds = map.getBounds()
const bbox = new BBox([
[bounds.getEast(), bounds.getNorth()],
[bounds.getWest(), bounds.getSouth()]
[bounds.getWest(), bounds.getSouth()],
])
if (this.bounds.data === undefined || !isSetup) {
this.bounds.setData(bbox)
@ -639,14 +651,14 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
type: "raster-dem",
url:
"https://api.maptiler.com/tiles/terrain-rgb/tiles.json?key=" +
Constants.maptilerApiKey
Constants.maptilerApiKey,
})
try {
while (!map?.isStyleLoaded()) {
await Utils.waitFor(250)
}
map.setTerrain({
source: id
source: id,
})
} catch (e) {
console.error(e)

View file

@ -25,7 +25,6 @@
let container: HTMLElement
let _map: Map
onMount(() => {
const { lon, lat } = mapProperties?.location?.data ?? { lon: 0, lat: 0 }
@ -33,7 +32,10 @@
const rasterLayer: RasterLayerProperties = mapProperties?.rasterLayer?.data?.properties
let styleUrl: string
if (rasterLayer?.type === "vector") {
styleUrl = rasterLayer?.style ?? rasterLayer?.url ?? AvailableRasterLayers.defaultBackgroundLayer.properties.url
styleUrl =
rasterLayer?.style ??
rasterLayer?.url ??
AvailableRasterLayers.defaultBackgroundLayer.properties.url
} else {
const defaultLayer = AvailableRasterLayers.defaultBackgroundLayer.properties
styleUrl = defaultLayer.style ?? defaultLayer.url
@ -48,13 +50,13 @@
center: { lng: lon, lat },
maxZoom: 24,
interactive: true,
attributionControl: false
attributionControl: false,
}
_map = new maplibre.Map(options)
window.requestAnimationFrame(() => {
_map.resize()
})
_map.on("load", function() {
_map.on("load", function () {
_map.resize()
const canvas = _map.getCanvas()
if (interactive) {

View file

@ -65,13 +65,12 @@
updateLocation()
window.setTimeout(updateLocation, 150)
window.setTimeout(updateLocation, 500)
}),
})
)
}
</script>
<div class="absolute w-full h-full flex items-center justify-center"
style="z-index: 100">
<div class="absolute flex h-full w-full items-center justify-center" style="z-index: 100">
<StyleLoadingIndicator map={altmap} />
</div>
<MaplibreMap {interactive} map={altmap} mapProperties={altproperties} />

View file

@ -109,8 +109,12 @@ class SingleBackgroundHandler {
const background = this._targetLayer.properties
console.debug("Enabling", background.id)
let addLayerBeforeId = "transit_pier" // this is the first non-landuse item in the stylesheet, we add the raster layer before the roads but above the landuse
if(!map.getLayer(addLayerBeforeId)){
console.warn("Layer", addLayerBeforeId,"not foundhttp://127.0.0.1:1234/theme.html?layout=cyclofix&z=14.8&lat=51.05282501324558&lon=3.720591622281745&layer-range=true")
if (!map.getLayer(addLayerBeforeId)) {
console.warn(
"Layer",
addLayerBeforeId,
"not foundhttp://127.0.0.1:1234/theme.html?layout=cyclofix&z=14.8&lat=51.05282501324558&lon=3.720591622281745&layer-range=true"
)
addLayerBeforeId = undefined
}
if (background.category === "osmbasedmap" || background.category === "map") {
@ -140,15 +144,15 @@ class SingleBackgroundHandler {
type: "raster",
source: background.id,
paint: {
"raster-opacity": 0
}
"raster-opacity": 0,
},
},
addLayerBeforeId
)
this.opacity.addCallbackAndRun((o) => {
try{
try {
map.setPaintProperty(background.id, "raster-opacity", o)
}catch (e) {
} catch (e) {
console.debug("Could not set raster-opacity of", background.id)
return true // This layer probably doesn't exist anymore, so we unregister
}
@ -185,11 +189,13 @@ export default class RasterLayerHandler {
})
}
public static prepareSource(layer: RasterLayerProperties): RasterSourceSpecification | VectorSourceSpecification {
public static prepareSource(
layer: RasterLayerProperties
): RasterSourceSpecification | VectorSourceSpecification {
if (layer.type === "vector") {
const vs: VectorSourceSpecification = {
type: "vector",
url: layer.url
url: layer.url,
}
return vs
}
@ -202,7 +208,7 @@ export default class RasterLayerHandler {
minzoom: layer["min_zoom"] ?? 1,
maxzoom: layer["max_zoom"] ?? 25,
// Bit of a hack, but seems to work
scheme: layer.url.includes("{-y}") ? "tms" : "xyz"
scheme: layer.url.includes("{-y}") ? "tms" : "xyz",
}
}
@ -216,7 +222,7 @@ export default class RasterLayerHandler {
"{width}": "" + size,
"{height}": "" + size,
"{zoom}": "{z}",
"{-y}": "{y}"
"{-y}": "{y}",
}
for (const key in toReplace) {

View file

@ -78,7 +78,7 @@
{#if hasLayers}
<form class="flex h-full w-full flex-col" on:submit|preventDefault={() => {}}>
<button tabindex="-1" on:click={() => apply()} class="m-0 h-full w-full cursor-pointer p-1">
<span class="pointer-events-none h-full w-full relative">
<span class="pointer-events-none relative h-full w-full">
<OverlayMap
interactive={false}
rasterLayer={rasterLayerOnMap}

View file

@ -154,7 +154,7 @@ class PointRenderingLayer {
if (this._onClick) {
const self = this
el.addEventListener("click", function(ev) {
el.addEventListener("click", function (ev) {
ev.preventDefault()
self._onClick(feature)
// Workaround to signal the MapLibreAdaptor to ignore this click
@ -200,7 +200,7 @@ class LineRenderingLayer {
"lineCap",
"offset",
"fill",
"fillColor"
"fillColor",
] as const
private static readonly lineConfigKeysColor = ["color", "fillColor"] as const
@ -264,8 +264,8 @@ class LineRenderingLayer {
"icon-rotation-alignment": "map",
"icon-pitch-alignment": "map",
"icon-image": imgId,
"icon-size": 0.055
}
"icon-size": 0.055,
},
}
const filter = img.if?.asMapboxExpression()
if (filter) {
@ -338,9 +338,9 @@ class LineRenderingLayer {
type: "geojson",
data: {
type: "FeatureCollection",
features
features,
},
promoteId: "id"
promoteId: "id",
})
const linelayer = this._layername + "_line"
const layer: AddLayerObject = {
@ -351,15 +351,15 @@ class LineRenderingLayer {
"line-color": ["feature-state", "color"],
"line-opacity": ["feature-state", "color-opacity"],
"line-width": ["feature-state", "width"],
"line-offset": ["feature-state", "offset"]
"line-offset": ["feature-state", "offset"],
},
layout: {
"line-cap": "round"
}
"line-cap": "round",
},
}
if (this._config.dashArray) {
layer.paint["line-dasharray"] = this._config.dashArray?.split(" ")?.map(s => Number(s)) ?? null
layer.paint["line-dasharray"] =
this._config.dashArray?.split(" ")?.map((s) => Number(s)) ?? null
}
map.addLayer(layer)
@ -393,8 +393,8 @@ class LineRenderingLayer {
layout: {},
paint: {
"fill-color": ["feature-state", "fillColor"],
"fill-opacity": ["feature-state", "fillColor-opacity"]
}
"fill-opacity": ["feature-state", "fillColor-opacity"],
},
})
if (this._onClick) {
map.on("click", polylayer, (e) => {
@ -425,7 +425,7 @@ class LineRenderingLayer {
this.currentSourceData = features
src.setData({
type: "FeatureCollection",
features: this.currentSourceData
features: this.currentSourceData,
})
}
}
@ -509,14 +509,14 @@ export default class ShowDataLayer {
layers.filter((l) => l.source !== null).map((l) => new FilteredLayer(l)),
features,
{
constructStore: (features, layer) => new SimpleFeatureSource(layer, features)
constructStore: (features, layer) => new SimpleFeatureSource(layer, features),
}
)
perLayer.forEach((fs) => {
new ShowDataLayer(mlmap, {
layer: fs.layer.layerDef,
features: fs,
...(options ?? {})
...(options ?? {}),
})
})
}
@ -529,12 +529,11 @@ export default class ShowDataLayer {
return new ShowDataLayer(map, {
layer: ShowDataLayer.rangeLayer,
features,
doShowLayer
doShowLayer,
})
}
public destruct() {
}
public destruct() {}
private zoomToCurrentFeatures(map: MlMap) {
if (this._options.zoomToFeatures) {
@ -543,7 +542,7 @@ export default class ShowDataLayer {
map.resize()
map.fitBounds(bbox.toLngLat(), {
padding: { top: 10, bottom: 10, left: 10, right: 10 },
animate: false
animate: false,
})
}
}
@ -552,11 +551,12 @@ export default class ShowDataLayer {
let { features, doShowLayer, fetchStore, selectedElement } = this._options
let onClick = this._options.onClick
if (!onClick && selectedElement) {
onClick = (this._options.layer.title === undefined
? undefined
: (feature: Feature) => {
selectedElement?.setData(feature)
})
onClick =
this._options.layer.title === undefined
? undefined
: (feature: Feature) => {
selectedElement?.setData(feature)
}
}
if (this._options.drawLines !== false) {
for (let i = 0; i < this._options.layer.lineRendering.length; i++) {

View file

@ -1,15 +1,16 @@
<script lang="ts">
import Translations from "../i18n/Translations.js";
import Min from "../../assets/svg/Min.svelte";
import MapControlButton from "../Base/MapControlButton.svelte";
import Plus from "../../assets/svg/Plus.svelte";
import type { MapProperties } from "../../Models/MapProperties"
import Translations from "../i18n/Translations.js"
import Min from "../../assets/svg/Min.svelte"
import MapControlButton from "../Base/MapControlButton.svelte"
import Plus from "../../assets/svg/Plus.svelte"
import type { MapProperties } from "../../Models/MapProperties"
export let adaptor: MapProperties
let canZoomIn = adaptor.maxzoom.map(mz => adaptor.zoom.data < mz, [adaptor.zoom] )
let canZoomOut = adaptor.minzoom.map(mz => adaptor.zoom.data > mz, [adaptor.zoom] )
export let adaptor: MapProperties
let canZoomIn = adaptor.maxzoom.map((mz) => adaptor.zoom.data < mz, [adaptor.zoom])
let canZoomOut = adaptor.minzoom.map((mz) => adaptor.zoom.data > mz, [adaptor.zoom])
</script>
<div class="absolute bottom-0 right-0 pointer-events-none flex flex-col">
<div class="pointer-events-none absolute bottom-0 right-0 flex flex-col">
<MapControlButton
enabled={canZoomIn}
cls="m-0.5 p-1"

View file

@ -10,24 +10,25 @@
* Optional. Only used for the 'global' change indicator so that it won't spin on pan/zoom but only when a change _actually_ occured
*/
export let rasterLayer: UIEventSource<any> = undefined
let didChange = undefined
onDestroy(rasterLayer?.addCallback(() => {
didChange = true
}) ??( () => {}))
onDestroy(Stores.Chronic(250).addCallback(
() => {
onDestroy(
rasterLayer?.addCallback(() => {
didChange = true
}) ?? (() => {})
)
onDestroy(
Stores.Chronic(250).addCallback(() => {
const mapIsLoading = !map.data?.isStyleLoaded()
isLoading = mapIsLoading && (didChange || rasterLayer === undefined)
if(didChange && !mapIsLoading){
if (didChange && !mapIsLoading) {
didChange = false
}
},
))
})
)
</script>
{#if isLoading}
<Loading cls="h-6 w-6" />
{:else}

View file

@ -32,7 +32,7 @@ export class OH {
th: 3,
fr: 4,
sa: 5,
su: 6
su: 6,
}
public static hhmm(h: number, m: number): string {
@ -143,7 +143,7 @@ export class OH {
const queue = ohs.map((oh) => {
if (oh.endHour === 0 && oh.endMinutes === 0) {
const newOh = {
...oh
...oh,
}
newOh.endHour = 24
return newOh
@ -211,7 +211,7 @@ export class OH {
startMinutes: startMinutes,
endHour: endHour,
endMinutes: endMinutes,
weekday: guard.weekday
weekday: guard.weekday,
})
doAddEntry = false
@ -279,7 +279,7 @@ export class OH {
startHour: start.hours,
startMinutes: start.minutes,
endHour: end.hours,
endMinutes: end.minutes
endMinutes: end.minutes,
}
}
@ -337,8 +337,8 @@ export class OH {
startHour: 0,
startMinutes: 0,
endHour: 24,
endMinutes: 0
}
endMinutes: 0,
},
]
)
}
@ -388,13 +388,13 @@ export class OH {
str = str.trim()
if (str.toLowerCase() === "ph off") {
return {
mode: "off"
mode: "off",
}
}
if (str.toLowerCase() === "ph open") {
return {
mode: "open"
mode: "open",
}
}
@ -410,7 +410,7 @@ export class OH {
return {
mode: " ",
start: OH.hhmm(timerange.startHour, timerange.startMinutes),
end: OH.hhmm(timerange.endHour, timerange.endMinutes)
end: OH.hhmm(timerange.endHour, timerange.endMinutes),
}
} catch (e) {
return null
@ -576,8 +576,8 @@ This list will be sorted
lon: tags._lon,
address: {
country_code: country.toLowerCase(),
state: undefined
}
state: undefined,
},
},
<any>{ tag_key: "opening_hours" }
)
@ -753,7 +753,7 @@ This list will be sorted
isOpen: iterator.getState(),
comment: iterator.getComment(),
startDate: iterator.getDate() as Date,
endDate: endDate // Should be overwritten by the next iteration
endDate: endDate, // Should be overwritten by the next iteration
}
prevValue = value
@ -891,7 +891,7 @@ This list will be sorted
startHour: timerange.startHour,
startMinutes: timerange.startMinutes,
endHour: timerange.endHour,
endMinutes: timerange.endMinutes
endMinutes: timerange.endMinutes,
})
} else {
ohs.push({
@ -899,14 +899,14 @@ This list will be sorted
startHour: timerange.startHour,
startMinutes: timerange.startMinutes,
endHour: 0,
endMinutes: 0
endMinutes: 0,
})
ohs.push({
weekday: (weekday + 1) % 7,
startHour: 0,
startMinutes: 0,
endHour: timerange.endHour,
endMinutes: timerange.endMinutes
endMinutes: timerange.endMinutes,
})
}
}
@ -967,7 +967,7 @@ export class ToTextualDescription {
"thursday",
"friday",
"saturday",
"sunday"
"sunday",
]
function addRange(start: number, end: number) {
@ -1025,7 +1025,7 @@ export class ToTextualDescription {
private static createRangeFor(range: OpeningRange): Translation {
return Translations.t.general.opening_hours.ranges.Subs({
starttime: ToTextualDescription.timeString(range.startDate),
endtime: ToTextualDescription.timeString(range.endDate)
endtime: ToTextualDescription.timeString(range.endDate),
})
}
@ -1037,7 +1037,7 @@ export class ToTextualDescription {
for (let i = 1; i < ranges.length; i++) {
tr = Translations.t.general.opening_hours.rangescombined.Subs({
range0: tr,
range1: ToTextualDescription.createRangeFor(ranges[i])
range1: ToTextualDescription.createRangeFor(ranges[i]),
})
}
return tr

View file

@ -365,7 +365,7 @@
</div>
</div>
{:else}
<Loading><Tr t={Translations.t.general.add.creating}/> </Loading>
<Loading><Tr t={Translations.t.general.add.creating} /></Loading>
{/if}
</div>
</LoginToggle>

View file

@ -4,7 +4,7 @@
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
export let tags: UIEventSource<Record<string, any>>
export let tagKeys = tags.map(tgs => tgs === undefined ? [] : Object.keys(tgs))
export let tagKeys = tags.map((tgs) => (tgs === undefined ? [] : Object.keys(tgs)))
export let layer: LayerConfig | undefined = undefined

View file

@ -110,7 +110,10 @@ class ApplyButton extends UIElement {
mla.allowZooming.setData(false)
mla.allowMoving.setData(false)
const previewMap = new SvelteUIElement(MaplibreMap, { mapProperties: mla, map: mlmap }).SetClass("h-48")
const previewMap = new SvelteUIElement(MaplibreMap, {
mapProperties: mla,
map: mlmap,
}).SetClass("h-48")
const features = this.target_feature_ids.map((id) =>
this.state.indexedFeatures.featuresById.data.get(id)

View file

@ -109,7 +109,11 @@ export class MinimapViz implements SpecialVisualization {
state.layout.layers
)
return new SvelteUIElement(MaplibreMap, { interactive: false, map: mlmap, mapProperties: mla })
return new SvelteUIElement(MaplibreMap, {
interactive: false,
map: mlmap,
mapProperties: mla,
})
.SetClass("h-40 rounded")
.SetStyle("overflow: hidden; pointer-events: none;")
}

View file

@ -1,5 +1,4 @@
<script lang="ts">
import { UIEventSource } from "../../Logic/UIEventSource"
import type { Feature, Point } from "geojson"
import type { SpecialVisualizationState } from "../SpecialVisualization"
@ -19,18 +18,26 @@
export let state: SpecialVisualizationState
export let id: WayId
const t = Translations.t.split
let step: "initial" | "loading_way" | "splitting" | "applying_split" | "has_been_split" | "deleted" = "initial"
let step:
| "initial"
| "loading_way"
| "splitting"
| "applying_split"
| "has_been_split"
| "deleted" = "initial"
// Contains the points on the road that are selected to split on - contains geojson points with extra properties such as 'location' with the distance along the linestring
let splitPoints = new UIEventSource<Feature<
Point,
{
id: number
index: number
dist: number
location: number
}
>[]>([])
let splitpointsNotEmpty = splitPoints.map(sp => sp.length > 0)
let splitPoints = new UIEventSource<
Feature<
Point,
{
id: number
index: number
dist: number
location: number
}
>[]
>([])
let splitpointsNotEmpty = splitPoints.map((sp) => sp.length > 0)
let osmWay: OsmWay
@ -54,7 +61,7 @@
{
theme: state?.layout?.id,
},
5,
5
)
await state.changes?.applyAction(splitAction)
// We throw away the old map and splitpoints, and create a new map from scratch
@ -64,10 +71,8 @@
state.selectedElement?.setData(undefined)
step = "has_been_split"
}
</script>
<LoginToggle ignoreLoading={true} {state}>
<Tr slot="not-logged-in" t={t.loginToSplit} />
@ -75,38 +80,39 @@
<!-- Empty -->
{:else if step === "initial"}
<button on:click={() => downloadWay()}>
<Scissors class="w-6 h-6 shrink-0" />
<Scissors class="h-6 w-6 shrink-0" />
<Tr t={t.inviteToSplit} />
</button>
{:else if step === "loading_way"}
<Loading />
{:else if step === "splitting"}
<div class="flex flex-col interactive border-interactive p-2">
<div class="w-full h-80">
<div class="interactive border-interactive flex flex-col p-2">
<div class="h-80 w-full">
<WaySplitMap {state} {splitPoints} {osmWay} />
</div>
<div class="flex flex-wrap-reverse md:flex-nowrap w-full">
<BackButton clss="w-full" on:click={() => {
splitPoints.set([])
step = "initial"
}}>
<div class="flex w-full flex-wrap-reverse md:flex-nowrap">
<BackButton
clss="w-full"
on:click={() => {
splitPoints.set([])
step = "initial"
}}
>
<Tr t={Translations.t.general.cancel} />
</BackButton>
<NextButton clss={ ($splitpointsNotEmpty ? "": "disabled ") + "w-full primary"} on:click={() => doSplit()}>
<NextButton
clss={($splitpointsNotEmpty ? "" : "disabled ") + "w-full primary"}
on:click={() => doSplit()}
>
<Tr t={t.split} />
</NextButton>
</div>
</div>
{:else if step === "has_been_split"}
<Tr cls="thanks" t={ t.hasBeenSplit.Clone().SetClass("font-bold thanks block w-full")} />
<Tr cls="thanks" t={t.hasBeenSplit.Clone().SetClass("font-bold thanks block w-full")} />
<button on:click={() => downloadWay()}>
<Scissors class="w-6 h-6" />
<Scissors class="h-6 w-6" />
<Tr t={t.splitAgain} />
</button>
{/if}
</LoginToggle>

View file

@ -171,7 +171,7 @@ export default class TagApplyButton implements AutoAction, SpecialVisualization
state: SpecialVisualizationState,
tags: UIEventSource<Record<string, string>>,
args: string[],
feature: Feature,
feature: Feature
): BaseUIElement {
const tagsToApply = TagApplyButton.generateTagsToApply(args[0], tags)
const msg = args[1]

View file

@ -68,10 +68,14 @@
},
[skippedQuestions]
)
let firstQuestion: UIEventSource<TagRenderingConfig> = new UIEventSource<TagRenderingConfig>(undefined)
let allQuestionsToAsk : UIEventSource<TagRenderingConfig[]> = new UIEventSource<TagRenderingConfig[]>([])
let firstQuestion: UIEventSource<TagRenderingConfig> = new UIEventSource<TagRenderingConfig>(
undefined
)
let allQuestionsToAsk: UIEventSource<TagRenderingConfig[]> = new UIEventSource<
TagRenderingConfig[]
>([])
async function calculateQuestions(){
async function calculateQuestions() {
console.log("Applying questions to ask")
const qta = questionsToAsk.data
firstQuestion.setData(undefined)
@ -81,12 +85,10 @@
allQuestionsToAsk.setData(qta)
}
onDestroy(questionsToAsk.addCallback(() =>calculateQuestions()))
onDestroy(questionsToAsk.addCallback(() => calculateQuestions()))
onDestroy(showAllQuestionsAtOnce.addCallback(() => calculateQuestions()))
calculateQuestions()
let answered: number = 0
let skipped: number = 0

View file

@ -135,24 +135,25 @@
// We want to (re)-initialize whenever the 'tags' or 'config' change - but not when 'checkedConfig' changes
initialize($tags, config)
}
onDestroy(
freeformInput.subscribe((freeformValue) => {
if (!mappings || mappings?.length == 0 || config.freeform?.key === undefined) {
return
}
// If a freeform value is given, mark the 'mapping' as marked
if (config.multiAnswer) {
if (checkedMappings === undefined) {
// Initialization didn't yet run
onDestroy(
freeformInput.subscribe((freeformValue) => {
if (!mappings || mappings?.length == 0 || config.freeform?.key === undefined) {
return
}
checkedMappings[mappings.length] = freeformValue?.length > 0
return
}
if (freeformValue?.length > 0) {
selectedMapping = mappings.length
}
}))
// If a freeform value is given, mark the 'mapping' as marked
if (config.multiAnswer) {
if (checkedMappings === undefined) {
// Initialization didn't yet run
return
}
checkedMappings[mappings.length] = freeformValue?.length > 0
return
}
if (freeformValue?.length > 0) {
selectedMapping = mappings.length
}
})
)
$: {
if (
@ -243,7 +244,9 @@ onDestroy(
<form
class="interactive border-interactive relative flex flex-col overflow-y-auto px-2"
style="max-height: 75vh"
on:submit|preventDefault={() =>{ /*onSave(); This submit is not needed and triggers to early, causing bugs: see #1808*/}}
on:submit|preventDefault={() => {
/*onSave(); This submit is not needed and triggers to early, causing bugs: see #1808*/
}}
>
<fieldset>
<legend>
@ -399,7 +402,10 @@ onDestroy(
<slot name="cancel" />
<slot name="save-button" {selectedTags}>
{#if allowDeleteOfFreeform && (mappings?.length ?? 0) === 0 && $freeformInput === undefined && $freeformInputUnvalidated === ""}
<button class="primary flex" on:click|stopPropagation|preventDefault={() => onSave()}>
<button
class="primary flex"
on:click|stopPropagation|preventDefault={() => onSave()}
>
<TrashIcon class="h-6 w-6 text-red-500" />
<Tr t={Translations.t.general.eraseValue} />
</button>

View file

@ -1,90 +1,93 @@
<script lang="ts">
/**
* Allows to import a 'mangrove' private key from backup
*/
import LoginToggle from "../Base/LoginToggle.svelte"
import FileSelector from "../Base/FileSelector.svelte"
import type { SpecialVisualizationState } from "../SpecialVisualization"
import Tr from "../Base/Tr.svelte"
import Translations from "../i18n/Translations"
import { UIEventSource } from "../../Logic/UIEventSource"
/**
* Allows to import a 'mangrove' private key from backup
*/
import LoginToggle from "../Base/LoginToggle.svelte"
import FileSelector from "../Base/FileSelector.svelte"
import type { SpecialVisualizationState } from "../SpecialVisualization"
import Tr from "../Base/Tr.svelte"
import Translations from "../i18n/Translations"
import { UIEventSource } from "../../Logic/UIEventSource"
export let state: SpecialVisualizationState
export let text: string
export let state: SpecialVisualizationState
export let text: string
let error: string = undefined
let success: string = undefined
let error: string = undefined
let success: string = undefined
function importContent(str: string) {
const parsed = JSON.parse(str)
function importContent(str: string) {
const parsed = JSON.parse(str)
const format = {
"crv": "P-256",
"d": undefined,
"ext": true,
"key_ops": ["sign"],
"kty": "EC",
"x": undefined,
"y": undefined,
"metadata": "Mangrove private key",
}
const neededKeys = Object.keys(format)
for (const neededKey of neededKeys) {
const expected = format[neededKey]
const actual = parsed[neededKey]
if (actual === undefined) {
error = "Not a valid key. The value for " + neededKey + " is missing"
return
}
if (typeof expected === "string" && expected !== actual) {
error = "Not a valid key. The value for " + neededKey + " should be " + expected + " but is " + actual
return
}
}
const current: UIEventSource<string> = state.userRelatedState.mangroveIdentity.mangroveIdentity
const flattened = JSON.stringify(parsed, null, "")
if (flattened === current.data) {
success = "The imported key is identical to the existing key"
return
}
console.log("Got", flattened, current)
current.setData(flattened)
success = "Applied private key"
const format = {
crv: "P-256",
d: undefined,
ext: true,
key_ops: ["sign"],
kty: "EC",
x: undefined,
y: undefined,
metadata: "Mangrove private key",
}
async function onImport(files: FileList) {
error = undefined
success = undefined
try {
const reader = new FileReader()
reader.readAsText(files[0], "UTF-8")
// here we tell the reader what to do when it's done reading...
const content = await new Promise<string>((resolve, reject) => {
reader.onload = readerEvent => {
resolve(<string>readerEvent.target.result)
}
})
importContent(content)
} catch (e) {
error = e
}
const neededKeys = Object.keys(format)
for (const neededKey of neededKeys) {
const expected = format[neededKey]
const actual = parsed[neededKey]
if (actual === undefined) {
error = "Not a valid key. The value for " + neededKey + " is missing"
return
}
if (typeof expected === "string" && expected !== actual) {
error =
"Not a valid key. The value for " +
neededKey +
" should be " +
expected +
" but is " +
actual
return
}
}
const current: UIEventSource<string> = state.userRelatedState.mangroveIdentity.mangroveIdentity
const flattened = JSON.stringify(parsed, null, "")
if (flattened === current.data) {
success = "The imported key is identical to the existing key"
return
}
console.log("Got", flattened, current)
current.setData(flattened)
success = "Applied private key"
}
async function onImport(files: FileList) {
error = undefined
success = undefined
try {
const reader = new FileReader()
reader.readAsText(files[0], "UTF-8")
// here we tell the reader what to do when it's done reading...
const content = await new Promise<string>((resolve, reject) => {
reader.onload = (readerEvent) => {
resolve(<string>readerEvent.target.result)
}
})
importContent(content)
} catch (e) {
error = e
}
}
</script>
<LoginToggle {state}>
<div class="flex flex-col m-1">
<FileSelector accept="application/json" multiple={false} on:submit={e => onImport(e.detail)}>
<div class="m-1 flex flex-col">
<FileSelector accept="application/json" multiple={false} on:submit={(e) => onImport(e.detail)}>
{text}
</FileSelector>
{#if error}
<div class="alert">
<Tr t={Translations.t.general.error} /> {error}</div>
<Tr t={Translations.t.general.error} />
{error}
</div>
{/if}
{#if success}
<div class="thanks">

View file

@ -61,12 +61,12 @@
opinion: opinion.data,
metadata: { nickname, is_affiliated: isAffiliated.data },
}
try {
await reviews.createReview(review)
} catch (e) {
console.error("Could not create review due to", e)
uploadFailed = "" + e
}
try {
await reviews.createReview(review)
} catch (e) {
console.error("Could not create review due to", e)
uploadFailed = "" + e
}
_state = "done"
}
</script>

View file

@ -42,12 +42,13 @@
{#if $allReviews?.length - $reviews?.length === 1}
<Tr t={t.non_place_review} />
{:else}
<Tr t={t.non_place_reviews.Subs({n:$allReviews?.length - $reviews?.length })} />
<Tr t={t.non_place_reviews.Subs({ n: $allReviews?.length - $reviews?.length })} />
{/if}
<a target="_blank"
class="link-underline"
rel="noopener nofollow"
href={`https://mangrove.reviews/list?kid=${encodeURIComponent($kid)}`}
<a
target="_blank"
class="link-underline"
rel="noopener nofollow"
href={`https://mangrove.reviews/list?kid=${encodeURIComponent($kid)}`}
>
<Tr t={t.see_all} />
</a>

File diff suppressed because it is too large Load diff

View file

@ -42,7 +42,7 @@
)
let osmConnection = new OsmConnection({
oauth_token,
checkOnlineRegularly: true
checkOnlineRegularly: true,
})
const expertMode = UIEventSource.asBoolean(
osmConnection.GetPreference("studio-expert-mode", "false", {

View file

@ -1,5 +1,2 @@
<script lang="ts">
</script>

View file

@ -18,7 +18,7 @@
EyeIcon,
HeartIcon,
MenuIcon,
XCircleIcon
XCircleIcon,
} from "@rgossiaux/svelte-heroicons/solid"
import Tr from "./Base/Tr.svelte"
import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte"
@ -99,26 +99,31 @@
})
let selectedLayer: Store<LayerConfig> = state.selectedElement.mapD((element) => {
if (element.properties.id.startsWith("current_view")) {
return currentViewLayer
}
if (element.properties.id === "new_point_dialog") {
return layout.layers.find(l => l.id === "last_click")
}
if (element.properties.id === "location_track") {
return layout.layers.find(l => l.id === "gps_track")
}
return state.layout.getMatchingLayer(element.properties)
if (element.properties.id.startsWith("current_view")) {
return currentViewLayer
}
)
if (element.properties.id === "new_point_dialog") {
return layout.layers.find((l) => l.id === "last_click")
}
if (element.properties.id === "location_track") {
return layout.layers.find((l) => l.id === "gps_track")
}
return state.layout.getMatchingLayer(element.properties)
})
let currentZoom = state.mapProperties.zoom
let showCrosshair = state.userRelatedState.showCrosshair
let visualFeedback = state.visualFeedback
let viewport: UIEventSource<HTMLDivElement> = new UIEventSource<HTMLDivElement>(undefined)
let mapproperties: MapProperties = state.mapProperties
state.mapProperties.installCustomKeyboardHandler(viewport)
let canZoomIn = mapproperties.maxzoom.map(mz => mapproperties.zoom.data < mz, [mapproperties.zoom])
let canZoomOut = mapproperties.minzoom.map(mz => mapproperties.zoom.data > mz, [mapproperties.zoom])
let canZoomIn = mapproperties.maxzoom.map(
(mz) => mapproperties.zoom.data < mz,
[mapproperties.zoom]
)
let canZoomOut = mapproperties.minzoom.map(
(mz) => mapproperties.zoom.data > mz,
[mapproperties.zoom]
)
function updateViewport() {
const rect = viewport.data?.getBoundingClientRect()
@ -133,7 +138,7 @@
const bottomRight = mlmap.unproject([rect.right, rect.bottom])
const bbox = new BBox([
[topLeft.lng, topLeft.lat],
[bottomRight.lng, bottomRight.lat]
[bottomRight.lng, bottomRight.lat],
])
state.visualFeedbackViewportBounds.setData(bbox)
}
@ -149,7 +154,8 @@
let currentViewLayer = layout.layers.find((l) => l.id === "current_view")
let rasterLayer: Store<RasterLayerPolygon> = state.mapProperties.rasterLayer
let rasterLayerName =
rasterLayer.data?.properties?.name ?? AvailableRasterLayers.defaultBackgroundLayer.properties.name
rasterLayer.data?.properties?.name ??
AvailableRasterLayers.defaultBackgroundLayer.properties.name
onDestroy(
rasterLayer.addCallbackAndRunD((l) => {
rasterLayerName = l.properties.name
@ -224,7 +230,12 @@
on:keydown={forwardEventToMap}
>
<div class="m-0.5 mx-1 flex cursor-pointer items-center max-[480px]:w-full sm:mx-1 md:mx-2">
<img role="presentation" alt="" class="mr-0.5 block h-6 w-6 sm:mr-1 md:mr-2 md:h-8 md:w-8" src={layout.icon} />
<img
role="presentation"
alt=""
class="mr-0.5 block h-6 w-6 sm:mr-1 md:mr-2 md:h-8 md:w-8"
src={layout.icon}
/>
<b class="mr-1">
<Tr t={layout.title} />
</b>
@ -385,8 +396,6 @@
<svelte:fragment slot="error" />
</LoginToggle>
{#if $selectedElement !== undefined && $selectedLayer !== undefined && !$selectedLayer.popupInFloatover}
<!-- right modal with the selected element view -->
<ModalRight
@ -409,10 +418,10 @@
state.selectedElement.setData(undefined)
}}
>
<div class="flex flex-col h-full w-full">
<div class="flex h-full w-full flex-col">
{#if $selectedLayer.popupInFloatover === "title"}
<SelectedElementTitle {state} layer={$selectedLayer} selectedElement={$selectedElement} >
<span slot="close-button"/>
<SelectedElementTitle {state} layer={$selectedLayer} selectedElement={$selectedElement}>
<span slot="close-button" />
</SelectedElementTitle>
{/if}
<SelectedElementView {state} layer={$selectedLayer} selectedElement={$selectedElement} />
@ -423,7 +432,7 @@
<If condition={state.previewedImage.map((i) => i !== undefined)}>
<FloatOver extraClasses="p-1" on:close={() => state.previewedImage.setData(undefined)}>
<button
class="absolute p-0 right-4 top-4 h-8 w-8 rounded-full"
class="absolute right-4 top-4 h-8 w-8 rounded-full p-0"
on:click={() => previewedImage.setData(undefined)}
slot="close-button"
>
@ -595,7 +604,7 @@
highlightedRendering={state.guistate.highlightedUserSetting}
selectedElement={{
type: "Feature",
properties: {id:"settings"},
properties: { id: "settings" },
geometry: { type: "Point", coordinates: [0, 0] },
}}
{state}

View file

@ -20,7 +20,10 @@ export default class WikidataSearchBox extends InputElement<string> {
new Table(
["name", "doc"],
[
["key", "the value of this tag will initialize search (default: name). This can be a ';'-separated list in which case every key will be inspected. The non-null value will be used as search"],
[
"key",
"the value of this tag will initialize search (default: name). This can be a ';'-separated list in which case every key will be inspected. The non-null value will be used as search",
],
[
"options",
new Combine([

View file

@ -25,7 +25,9 @@
{/if}
{#if $wikipediaDetails.wikidata}
<ToSvelte construct={() => WikidataPreviewBox.WikidataResponsePreview($wikipediaDetails.wikidata)} />
<ToSvelte
construct={() => WikidataPreviewBox.WikidataResponsePreview($wikipediaDetails.wikidata)}
/>
{/if}
{#if $wikipediaDetails.articleUrl}