forked from MapComplete/MapComplete
Merge develop
This commit is contained in:
commit
b5669f6bf8
786 changed files with 42904 additions and 35985 deletions
|
@ -2,7 +2,11 @@ import Combine from "./Base/Combine"
|
|||
import { FixedUiElement } from "./Base/FixedUiElement"
|
||||
import BaseUIElement from "./BaseUIElement"
|
||||
import Title from "./Base/Title"
|
||||
import { RenderingSpecification, SpecialVisualization, SpecialVisualizationState } from "./SpecialVisualization"
|
||||
import {
|
||||
RenderingSpecification,
|
||||
SpecialVisualization,
|
||||
SpecialVisualizationState,
|
||||
} from "./SpecialVisualization"
|
||||
import { HistogramViz } from "./Popup/HistogramViz"
|
||||
import MinimapViz from "./Popup/MinimapViz.svelte"
|
||||
import { ShareLinkViz } from "./Popup/ShareLinkViz"
|
||||
|
@ -15,7 +19,6 @@ import { MapillaryLinkVis } from "./Popup/MapillaryLinkVis"
|
|||
import { ImmutableStore, Store, Stores, UIEventSource } from "../Logic/UIEventSource"
|
||||
import AllTagsPanel from "./Popup/AllTagsPanel.svelte"
|
||||
import AllImageProviders from "../Logic/ImageProviders/AllImageProviders"
|
||||
import { ImageCarousel } from "./Image/ImageCarousel"
|
||||
import { VariableUiElement } from "./Base/VariableUIElement"
|
||||
import { Utils } from "../Utils"
|
||||
import Wikidata, { WikidataResponse } from "../Logic/Web/Wikidata"
|
||||
|
@ -31,13 +34,13 @@ import FeatureReviews from "../Logic/Web/MangroveReviews"
|
|||
import Maproulette, { MaprouletteTask } from "../Logic/Maproulette"
|
||||
import SvelteUIElement from "./Base/SvelteUIElement"
|
||||
import { BBoxFeatureSourceForLayer } from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
|
||||
import { Feature, GeoJsonProperties } from "geojson"
|
||||
import { Feature, GeoJsonProperties, LineString } from "geojson"
|
||||
import { GeoOperations } from "../Logic/GeoOperations"
|
||||
import CreateNewNote from "./Popup/Notes/CreateNewNote.svelte"
|
||||
import AddNewPoint from "./Popup/AddNewPoint/AddNewPoint.svelte"
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
||||
import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig"
|
||||
import { ExportAsGpxViz } from "./Popup/ExportAsGpxViz"
|
||||
import ExportFeatureButton from "./Popup/ExportFeatureButton.svelte"
|
||||
import WikipediaPanel from "./Wikipedia/WikipediaPanel.svelte"
|
||||
import TagRenderingEditable from "./Popup/TagRendering/TagRenderingEditable.svelte"
|
||||
import { PointImportButtonViz } from "./Popup/ImportButtons/PointImportButtonViz"
|
||||
|
@ -45,7 +48,6 @@ import WayImportButtonViz from "./Popup/ImportButtons/WayImportButtonViz"
|
|||
import ConflateImportButtonViz from "./Popup/ImportButtons/ConflateImportButtonViz"
|
||||
import DeleteWizard from "./Popup/DeleteFlow/DeleteWizard.svelte"
|
||||
import OpenIdEditor from "./BigComponents/OpenIdEditor.svelte"
|
||||
import FediverseValidator from "./InputElement/Validators/FediverseValidator"
|
||||
import SendEmail from "./Popup/SendEmail.svelte"
|
||||
import UploadImage from "./Image/UploadImage.svelte"
|
||||
import { Imgur } from "../Logic/ImageProviders/Imgur"
|
||||
|
@ -69,7 +71,6 @@ import NearbyImages from "./Image/NearbyImages.svelte"
|
|||
import NearbyImagesCollapsed from "./Image/NearbyImagesCollapsed.svelte"
|
||||
import MoveWizard from "./Popup/MoveWizard.svelte"
|
||||
import { Unit } from "../Models/Unit"
|
||||
import Link from "./Base/Link.svelte"
|
||||
import OrientationDebugPanel from "./Debug/OrientationDebugPanel.svelte"
|
||||
import MaprouletteSetStatus from "./MapRoulette/MaprouletteSetStatus.svelte"
|
||||
import DirectionIndicator from "./Base/DirectionIndicator.svelte"
|
||||
|
@ -85,7 +86,6 @@ import DynLink from "./Base/DynLink.svelte"
|
|||
import Locale from "./i18n/Locale"
|
||||
import LanguageUtils from "../Utils/LanguageUtils"
|
||||
import MarkdownUtils from "../Utils/MarkdownUtils"
|
||||
import ArrowDownTray from "@babeard/svelte-heroicons/mini/ArrowDownTray"
|
||||
import Trash from "@babeard/svelte-heroicons/mini/Trash"
|
||||
import NothingKnown from "./Popup/NothingKnown.svelte"
|
||||
import { CombinedFetcher } from "../Logic/Web/NearbyImagesSearch"
|
||||
|
@ -98,6 +98,8 @@ import GroupedView from "./Popup/GroupedView.svelte"
|
|||
import { QuestionableTagRenderingConfigJson } from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
||||
import NoteCommentElement from "./Popup/Notes/NoteCommentElement.svelte"
|
||||
import DisabledQuestions from "./Popup/DisabledQuestions.svelte"
|
||||
import FediverseLink from "./Popup/FediverseLink.svelte"
|
||||
import ImageCarousel from "./Image/ImageCarousel.svelte"
|
||||
|
||||
class NearbyImageVis implements SpecialVisualization {
|
||||
// Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests
|
||||
|
@ -123,7 +125,7 @@ class NearbyImageVis implements SpecialVisualization {
|
|||
tags: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): SvelteUIElement {
|
||||
const isOpen = args[0] === "open"
|
||||
const readonly = args[1] === "readonly"
|
||||
|
@ -165,7 +167,7 @@ class StealViz implements SpecialVisualization {
|
|||
const tagRenderings: [LayerConfig, TagRenderingConfig][] = []
|
||||
for (const layerAndTagRenderingId of layerAndtagRenderingIds.split(";")) {
|
||||
const [layerId, tagRenderingId] = layerAndTagRenderingId.trim().split(".")
|
||||
const layer = state.layout.layers.find((l) => l.id === layerId)
|
||||
const layer = state.theme.layers.find((l) => l.id === layerId)
|
||||
const tagRendering = layer.tagRenderings.find((tr) => tr.id === tagRenderingId)
|
||||
tagRenderings.push([layer, tagRendering])
|
||||
}
|
||||
|
@ -190,7 +192,7 @@ class StealViz implements SpecialVisualization {
|
|||
selectedElement: otherFeature,
|
||||
state,
|
||||
layer,
|
||||
}),
|
||||
})
|
||||
)
|
||||
}
|
||||
if (elements.length === 1) {
|
||||
|
@ -198,8 +200,8 @@ class StealViz implements SpecialVisualization {
|
|||
}
|
||||
return new Combine(elements).SetClass("flex flex-col")
|
||||
},
|
||||
[state.indexedFeatures.featuresById],
|
||||
),
|
||||
[state.indexedFeatures.featuresById]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -251,11 +253,11 @@ class CloseNoteViz implements SpecialVisualization {
|
|||
public constr(
|
||||
state: SpecialVisualizationState,
|
||||
tags: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
args: string[]
|
||||
): SvelteUIElement {
|
||||
const { text, icon, idkey, comment, minZoom, zoomButton } = Utils.ParseVisArgs(
|
||||
this.args,
|
||||
args,
|
||||
args
|
||||
)
|
||||
|
||||
return new SvelteUIElement(CloseNoteButton, {
|
||||
|
@ -296,7 +298,7 @@ export class QuestionViz implements SpecialVisualization {
|
|||
tags: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): SvelteUIElement {
|
||||
const labels = args[0]
|
||||
?.split(";")
|
||||
|
@ -328,7 +330,7 @@ export default class SpecialVisualizations {
|
|||
for (const specialVisualization of SpecialVisualizations.specialVisualizations) {
|
||||
SpecialVisualizations.specialVisualisationsDict.set(
|
||||
specialVisualization.funcName,
|
||||
specialVisualization,
|
||||
specialVisualization
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -348,15 +350,15 @@ export default class SpecialVisualizations {
|
|||
viz.docs,
|
||||
viz.args.length > 0
|
||||
? MarkdownUtils.table(
|
||||
["name", "default", "description"],
|
||||
viz.args.map((arg) => {
|
||||
let defaultArg = arg.defaultValue ?? "_undefined_"
|
||||
if (defaultArg == "") {
|
||||
defaultArg = "_empty string_"
|
||||
}
|
||||
return [arg.name, defaultArg, arg.doc]
|
||||
}),
|
||||
)
|
||||
["name", "default", "description"],
|
||||
viz.args.map((arg) => {
|
||||
let defaultArg = arg.defaultValue ?? "_undefined_"
|
||||
if (defaultArg == "") {
|
||||
defaultArg = "_empty string_"
|
||||
}
|
||||
return [arg.name, defaultArg, arg.doc]
|
||||
})
|
||||
)
|
||||
: undefined,
|
||||
"#### Example usage of " + viz.funcName,
|
||||
"<code>" + example + "</code>",
|
||||
|
@ -365,18 +367,18 @@ export default class SpecialVisualizations {
|
|||
|
||||
public static constructSpecification(
|
||||
template: string,
|
||||
extraMappings: SpecialVisualization[] = [],
|
||||
extraMappings: SpecialVisualization[] = []
|
||||
): RenderingSpecification[] {
|
||||
return SpecialVisualisationUtils.constructSpecification(
|
||||
template,
|
||||
SpecialVisualizations.specialVisualisationsDict,
|
||||
extraMappings,
|
||||
extraMappings
|
||||
)
|
||||
}
|
||||
|
||||
public static HelpMessage(): string {
|
||||
const helpTexts: string[] = SpecialVisualizations.specialVisualizations.map((viz) =>
|
||||
SpecialVisualizations.DocumentationFor(viz),
|
||||
SpecialVisualizations.DocumentationFor(viz)
|
||||
)
|
||||
|
||||
const firstPart = new Combine([
|
||||
|
@ -409,10 +411,10 @@ export default class SpecialVisualizations {
|
|||
},
|
||||
},
|
||||
null,
|
||||
" ",
|
||||
),
|
||||
" "
|
||||
)
|
||||
).SetClass("code"),
|
||||
"In other words: use `{ \"before\": ..., \"after\": ..., \"special\": {\"type\": ..., \"argname\": ...argvalue...}`. The args are in the `special` block; an argvalue can be a string, a translation or another value. (Refer to class `RewriteSpecial` in case of problems)",
|
||||
'In other words: use `{ "before": ..., "after": ..., "special": {"type": ..., "argname": ...argvalue...}`. The args are in the `special` block; an argvalue can be a string, a translation or another value. (Refer to class `RewriteSpecial` in case of problems)',
|
||||
])
|
||||
.SetClass("flex flex-col")
|
||||
.AsMarkdown()
|
||||
|
@ -445,15 +447,15 @@ export default class SpecialVisualizations {
|
|||
Locale.showLinkToWeblate.map((showTranslations) => {
|
||||
const languages = showTranslations
|
||||
? LanguageUtils.usedLanguagesSorted
|
||||
: state.layout.language
|
||||
: state.theme.language
|
||||
return new SvelteUIElement(LanguagePicker, {
|
||||
assignTo: state.userRelatedState.language,
|
||||
availableLanguages: languages,
|
||||
preferredLanguages: state.osmConnection.userDetails.map(
|
||||
(ud) => ud.languages,
|
||||
(ud) => ud.languages
|
||||
),
|
||||
})
|
||||
}),
|
||||
})
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -492,7 +494,7 @@ export default class SpecialVisualizations {
|
|||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
feature: Feature
|
||||
): SvelteUIElement {
|
||||
return new SvelteUIElement(MinimapViz, { state, args, feature, tagSource })
|
||||
},
|
||||
|
@ -504,7 +506,7 @@ export default class SpecialVisualizations {
|
|||
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
tagSource: UIEventSource<Record<string, string>>
|
||||
): BaseUIElement {
|
||||
return new VariableUiElement(
|
||||
tagSource
|
||||
|
@ -514,7 +516,7 @@ export default class SpecialVisualizations {
|
|||
return new SvelteUIElement(SplitRoadWizard, { id, state })
|
||||
}
|
||||
return undefined
|
||||
}),
|
||||
})
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -528,7 +530,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
if (feature.geometry.type !== "Point") {
|
||||
return undefined
|
||||
|
@ -551,7 +553,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
if (!layer.deletion) {
|
||||
return undefined
|
||||
|
@ -566,7 +568,37 @@ export default class SpecialVisualizations {
|
|||
},
|
||||
},
|
||||
new ShareLinkViz(),
|
||||
new ExportAsGpxViz(),
|
||||
{
|
||||
funcName: "export_as_gpx",
|
||||
docs: "Exports the selected feature as GPX-file",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tags: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
) {
|
||||
if (feature.geometry.type !== "LineString") {
|
||||
return undefined
|
||||
}
|
||||
const t = Translations.t.general.download
|
||||
|
||||
return new SvelteUIElement(ExportFeatureButton, {
|
||||
tags,
|
||||
feature,
|
||||
layer,
|
||||
mimetype: "{gpx=application/gpx+xml}",
|
||||
extension: "gpx",
|
||||
construct: (feature: Feature<LineString>, title: string) =>
|
||||
GeoOperations.toGpx(feature, title),
|
||||
helpertext: t.downloadGpxHelper,
|
||||
maintext: t.downloadFeatureAsGpx,
|
||||
})
|
||||
},
|
||||
},
|
||||
new UploadToOsmViz(),
|
||||
new MultiApplyViz(),
|
||||
new AddNoteCommentViz(),
|
||||
|
@ -579,7 +611,7 @@ export default class SpecialVisualizations {
|
|||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
feature: Feature
|
||||
): BaseUIElement {
|
||||
const [lon, lat] = GeoOperations.centerpointCoordinates(feature)
|
||||
return new SvelteUIElement(CreateNewNote, {
|
||||
|
@ -642,7 +674,7 @@ export default class SpecialVisualizations {
|
|||
.map((tags) => tags[args[0]])
|
||||
.map((wikidata) => {
|
||||
wikidata = Utils.NoEmpty(
|
||||
wikidata?.split(";")?.map((wd) => wd.trim()) ?? [],
|
||||
wikidata?.split(";")?.map((wd) => wd.trim()) ?? []
|
||||
)[0]
|
||||
const entry = Wikidata.LoadWikidataEntry(wikidata)
|
||||
return new VariableUiElement(
|
||||
|
@ -652,9 +684,9 @@ export default class SpecialVisualizations {
|
|||
}
|
||||
const response = <WikidataResponse>e["success"]
|
||||
return Translation.fromMap(response.labels)
|
||||
}),
|
||||
})
|
||||
)
|
||||
}),
|
||||
})
|
||||
),
|
||||
},
|
||||
new MapillaryLinkVis(),
|
||||
|
@ -668,7 +700,7 @@ export default class SpecialVisualizations {
|
|||
tags: UIEventSource<Record<string, string>>,
|
||||
_,
|
||||
__,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
) => new SvelteUIElement(AllTagsPanel, { tags, layer }),
|
||||
},
|
||||
{
|
||||
|
@ -687,11 +719,8 @@ export default class SpecialVisualizations {
|
|||
if (args.length > 0) {
|
||||
imagePrefixes = [].concat(...args.map((a) => a.split(",")))
|
||||
}
|
||||
return new ImageCarousel(
|
||||
AllImageProviders.LoadImagesFor(tags, imagePrefixes),
|
||||
tags,
|
||||
state,
|
||||
)
|
||||
const images = AllImageProviders.LoadImagesFor(tags, imagePrefixes)
|
||||
return new SvelteUIElement(ImageCarousel, { state, tags, images })
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -709,15 +738,22 @@ export default class SpecialVisualizations {
|
|||
doc: "The text to show on the button",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "disable_blur",
|
||||
doc: "If set to 'true' or 'yes', then face blurring will be disabled. To be used sparingly",
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
constr: (state, tags, args) => {
|
||||
const targetKey = args[0] === "" ? undefined : args[0]
|
||||
const noBlur = args[3]?.toLowerCase()?.trim()
|
||||
return new SvelteUIElement(UploadImage, {
|
||||
state,
|
||||
tags,
|
||||
targetKey,
|
||||
labelText: args[1],
|
||||
image: args[2],
|
||||
noBlur: noBlur === "true" || noBlur === "yes",
|
||||
})
|
||||
},
|
||||
},
|
||||
|
@ -747,7 +783,7 @@ export default class SpecialVisualizations {
|
|||
nameKey: nameKey,
|
||||
fallbackName,
|
||||
},
|
||||
state.featureSwitchIsTesting,
|
||||
state.featureSwitchIsTesting
|
||||
)
|
||||
return new SvelteUIElement(StarsBarIcon, {
|
||||
score: reviews.average,
|
||||
|
@ -781,7 +817,7 @@ export default class SpecialVisualizations {
|
|||
nameKey: nameKey,
|
||||
fallbackName,
|
||||
},
|
||||
state.featureSwitchIsTesting,
|
||||
state.featureSwitchIsTesting
|
||||
)
|
||||
return new SvelteUIElement(ReviewForm, { reviews, state, tags, feature, layer })
|
||||
},
|
||||
|
@ -812,7 +848,7 @@ export default class SpecialVisualizations {
|
|||
nameKey: nameKey,
|
||||
fallbackName,
|
||||
},
|
||||
state.featureSwitchIsTesting,
|
||||
state.featureSwitchIsTesting
|
||||
)
|
||||
return new SvelteUIElement(AllReviews, { reviews, state, tags, feature, layer })
|
||||
},
|
||||
|
@ -838,7 +874,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
return new Combine([
|
||||
SpecialVisualizations.specialVisualisationsDict["create_review"].constr(
|
||||
|
@ -846,14 +882,14 @@ export default class SpecialVisualizations {
|
|||
tagSource,
|
||||
args,
|
||||
feature,
|
||||
layer,
|
||||
layer
|
||||
),
|
||||
SpecialVisualizations.specialVisualisationsDict["list_reviews"].constr(
|
||||
state,
|
||||
tagSource,
|
||||
args,
|
||||
feature,
|
||||
layer,
|
||||
layer
|
||||
),
|
||||
])
|
||||
},
|
||||
|
@ -871,7 +907,7 @@ export default class SpecialVisualizations {
|
|||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
_: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
argument: string[]
|
||||
): BaseUIElement {
|
||||
const [text] = argument
|
||||
return new SvelteUIElement(ImportReviewIdentity, { state, text })
|
||||
|
@ -928,7 +964,7 @@ export default class SpecialVisualizations {
|
|||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tags: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
args: string[]
|
||||
): SvelteUIElement {
|
||||
const keyToUse = args[0]
|
||||
const prefix = args[1]
|
||||
|
@ -965,17 +1001,17 @@ export default class SpecialVisualizations {
|
|||
return undefined
|
||||
}
|
||||
const allUnits: Unit[] = [].concat(
|
||||
...(state?.layout?.layers?.map((lyr) => lyr.units) ?? []),
|
||||
...(state?.theme?.layers?.map((lyr) => lyr.units) ?? [])
|
||||
)
|
||||
const unit = allUnits.filter((unit) =>
|
||||
unit.isApplicableToKey(key),
|
||||
unit.isApplicableToKey(key)
|
||||
)[0]
|
||||
if (unit === undefined) {
|
||||
return value
|
||||
}
|
||||
const getCountry = () => tagSource.data._country
|
||||
return unit.asHumanLongValue(value, getCountry)
|
||||
}),
|
||||
})
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -984,31 +1020,19 @@ export default class SpecialVisualizations {
|
|||
docs: "Exports the selected feature as GeoJson-file",
|
||||
args: [],
|
||||
|
||||
constr: (state, tagSource, tagsSource, feature, layer) => {
|
||||
constr: (state, tags, args, feature, layer) => {
|
||||
const t = Translations.t.general.download
|
||||
|
||||
return new SubtleButton(
|
||||
new SvelteUIElement(ArrowDownTray),
|
||||
new Combine([
|
||||
t.downloadFeatureAsGeojson.SetClass("font-bold text-lg"),
|
||||
t.downloadGeoJsonHelper.SetClass("subtle"),
|
||||
]).SetClass("flex flex-col"),
|
||||
)
|
||||
.onClick(() => {
|
||||
console.log("Exporting as Geojson")
|
||||
const tags = tagSource.data
|
||||
const title =
|
||||
layer?.title?.GetRenderValue(tags)?.Subs(tags)?.txt ?? "geojson"
|
||||
const data = JSON.stringify(feature, null, " ")
|
||||
Utils.offerContentsAsDownloadableFile(
|
||||
data,
|
||||
title + "_mapcomplete_export.geojson",
|
||||
{
|
||||
mimetype: "application/vnd.geo+json",
|
||||
},
|
||||
)
|
||||
})
|
||||
.SetClass("w-full")
|
||||
return new SvelteUIElement(ExportFeatureButton, {
|
||||
tags,
|
||||
feature,
|
||||
layer,
|
||||
mimetype: "application/vnd.geo+json",
|
||||
extension: "geojson",
|
||||
construct: (feature: Feature<LineString>) =>
|
||||
JSON.stringify(feature, null, " "),
|
||||
maintext: t.downloadFeatureAsGeojson,
|
||||
helpertext: t.downloadGeoJsonHelper,
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1041,7 +1065,7 @@ export default class SpecialVisualizations {
|
|||
constr: (state) => {
|
||||
return new SubtleButton(
|
||||
new SvelteUIElement(Trash).SetClass("h-6"),
|
||||
Translations.t.general.removeLocationHistory,
|
||||
Translations.t.general.removeLocationHistory
|
||||
).onClick(() => {
|
||||
state.historicalUserLocations.features.setData([])
|
||||
state.selectedElement.setData(undefined)
|
||||
|
@ -1079,10 +1103,13 @@ export default class SpecialVisualizations {
|
|||
.filter((c) => c.text !== "")
|
||||
.map(
|
||||
(comment) =>
|
||||
new SvelteUIElement(NoteCommentElement, { comment, state }),
|
||||
),
|
||||
new SvelteUIElement(NoteCommentElement, {
|
||||
comment,
|
||||
state,
|
||||
})
|
||||
)
|
||||
).SetClass("flex flex-col")
|
||||
}),
|
||||
})
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -1100,7 +1127,7 @@ export default class SpecialVisualizations {
|
|||
constr: (state, tags, args, feature, layer) => {
|
||||
const id = tags.data[args[0] ?? "id"]
|
||||
tags = state.featureProperties.getStore(id)
|
||||
return new SvelteUIElement(UploadImage, { state, tags, layer })
|
||||
return new SvelteUIElement(UploadImage, { state, tags, layer, feature })
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1115,11 +1142,11 @@ export default class SpecialVisualizations {
|
|||
tagsSource: UIEventSource<Record<string, string>>,
|
||||
_: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
) =>
|
||||
new VariableUiElement(
|
||||
tagsSource.map((tags) => {
|
||||
if (state.layout === undefined) {
|
||||
if (state.theme === undefined) {
|
||||
return "<feature title>"
|
||||
}
|
||||
const title = layer?.title?.GetRenderValue(tags)
|
||||
|
@ -1135,7 +1162,7 @@ export default class SpecialVisualizations {
|
|||
})
|
||||
.SetClass("px-1")
|
||||
.setSpan()
|
||||
}),
|
||||
})
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -1151,8 +1178,8 @@ export default class SpecialVisualizations {
|
|||
const challenge = Stores.FromPromise(
|
||||
Utils.downloadJsonCached<MaprouletteTask>(
|
||||
`${Maproulette.defaultEndpoint}/challenge/${parentId}`,
|
||||
24 * 60 * 60 * 1000,
|
||||
),
|
||||
24 * 60 * 60 * 1000
|
||||
)
|
||||
)
|
||||
|
||||
return new VariableUiElement(
|
||||
|
@ -1177,7 +1204,7 @@ export default class SpecialVisualizations {
|
|||
} else {
|
||||
return [title, new List(listItems)]
|
||||
}
|
||||
}),
|
||||
})
|
||||
)
|
||||
},
|
||||
docs: "Fetches the metadata of MapRoulette campaign that this task is part of and shows those details (namely `title`, `description` and `instruction`).\n\nThis reads the property `mr_challengeId` to detect the parent campaign.",
|
||||
|
@ -1191,15 +1218,15 @@ export default class SpecialVisualizations {
|
|||
"\n" +
|
||||
"```json\n" +
|
||||
"{\n" +
|
||||
" \"id\": \"mark_duplicate\",\n" +
|
||||
" \"render\": {\n" +
|
||||
" \"special\": {\n" +
|
||||
" \"type\": \"maproulette_set_status\",\n" +
|
||||
" \"message\": {\n" +
|
||||
" \"en\": \"Mark as not found or false positive\"\n" +
|
||||
' "id": "mark_duplicate",\n' +
|
||||
' "render": {\n' +
|
||||
' "special": {\n' +
|
||||
' "type": "maproulette_set_status",\n' +
|
||||
' "message": {\n' +
|
||||
' "en": "Mark as not found or false positive"\n' +
|
||||
" },\n" +
|
||||
" \"status\": \"2\",\n" +
|
||||
" \"image\": \"close\"\n" +
|
||||
' "status": "2",\n' +
|
||||
' "image": "close"\n' +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
|
@ -1270,12 +1297,12 @@ export default class SpecialVisualizations {
|
|||
|
||||
constr: (state) => {
|
||||
return new Combine(
|
||||
state.layout.layers
|
||||
state.theme.layers
|
||||
.filter(
|
||||
(l) =>
|
||||
l.name !== null &&
|
||||
l.title &&
|
||||
state.perLayer.get(l.id) !== undefined,
|
||||
state.perLayer.get(l.id) !== undefined
|
||||
)
|
||||
.map(
|
||||
(l) => {
|
||||
|
@ -1285,8 +1312,8 @@ export default class SpecialVisualizations {
|
|||
const fsBboxed = new BBoxFeatureSourceForLayer(fs, bbox)
|
||||
return new StatisticsPanel(fsBboxed)
|
||||
},
|
||||
[state.mapProperties.bounds],
|
||||
),
|
||||
[state.mapProperties.bounds]
|
||||
)
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1356,7 +1383,7 @@ export default class SpecialVisualizations {
|
|||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
args: string[]
|
||||
): SvelteUIElement {
|
||||
let [text, href, classnames, download, ariaLabel, icon] = args
|
||||
if (download === "") {
|
||||
|
@ -1394,7 +1421,7 @@ export default class SpecialVisualizations {
|
|||
},
|
||||
},
|
||||
null,
|
||||
" ",
|
||||
" "
|
||||
) +
|
||||
"\n```",
|
||||
args: [
|
||||
|
@ -1418,7 +1445,7 @@ export default class SpecialVisualizations {
|
|||
featureTags: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
) {
|
||||
const [key, tr, classesRaw] = args
|
||||
let classes = classesRaw ?? ""
|
||||
|
@ -1436,7 +1463,7 @@ export default class SpecialVisualizations {
|
|||
"Could not create a special visualization for multi(",
|
||||
args.join(", ") + ")",
|
||||
"no properties found for object",
|
||||
feature.properties.id,
|
||||
feature.properties.id
|
||||
)
|
||||
return undefined
|
||||
}
|
||||
|
@ -1452,7 +1479,7 @@ export default class SpecialVisualizations {
|
|||
elements.push(subsTr)
|
||||
}
|
||||
return elements
|
||||
}),
|
||||
})
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1472,7 +1499,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
return new VariableUiElement(
|
||||
tagSource.map((tags) => {
|
||||
|
@ -1484,7 +1511,7 @@ export default class SpecialVisualizations {
|
|||
console.error("Cannot create a translation for", v, "due to", e)
|
||||
return JSON.stringify(v)
|
||||
}
|
||||
}),
|
||||
})
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1501,52 +1528,13 @@ export default class SpecialVisualizations {
|
|||
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
tags: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const key = argument[0]
|
||||
const validator = new FediverseValidator()
|
||||
return new VariableUiElement(
|
||||
tagSource
|
||||
.map((tags) => tags[key])
|
||||
.map((fediAccount) => {
|
||||
fediAccount = validator.reformat(fediAccount)
|
||||
const [_, username, host] = fediAccount.match(
|
||||
FediverseValidator.usernameAtServer,
|
||||
)
|
||||
|
||||
const normalLink = new SvelteUIElement(Link, {
|
||||
text: fediAccount,
|
||||
href: "https://" + host + "/@" + username,
|
||||
newTab: true,
|
||||
})
|
||||
|
||||
const loggedInContributorMastodon =
|
||||
state.userRelatedState?.preferencesAsTags?.data?.[
|
||||
"_mastodon_link"
|
||||
]
|
||||
console.log(
|
||||
"LoggedinContributorMastodon",
|
||||
loggedInContributorMastodon,
|
||||
)
|
||||
if (!loggedInContributorMastodon) {
|
||||
return normalLink
|
||||
}
|
||||
const homeUrl = new URL(loggedInContributorMastodon)
|
||||
const homeHost = homeUrl.protocol + "//" + homeUrl.hostname
|
||||
|
||||
return new Combine([
|
||||
normalLink,
|
||||
new SvelteUIElement(Link, {
|
||||
href: homeHost + "/" + fediAccount,
|
||||
text: Translations.t.validation.fediverse.onYourServer,
|
||||
newTab: true,
|
||||
}).SetClass("button"),
|
||||
])
|
||||
}),
|
||||
)
|
||||
return new SvelteUIElement(FediverseLink, { key, tags, state })
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1565,7 +1553,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
return new FixedUiElement("{" + args[0] + "}")
|
||||
},
|
||||
|
@ -1586,7 +1574,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const key = argument[0] ?? "value"
|
||||
return new VariableUiElement(
|
||||
|
@ -1604,12 +1592,12 @@ export default class SpecialVisualizations {
|
|||
} catch (e) {
|
||||
return new FixedUiElement(
|
||||
"Could not parse this tag: " +
|
||||
JSON.stringify(value) +
|
||||
" due to " +
|
||||
e,
|
||||
JSON.stringify(value) +
|
||||
" due to " +
|
||||
e
|
||||
).SetClass("alert")
|
||||
}
|
||||
}),
|
||||
})
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1630,7 +1618,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const giggityUrl = argument[0]
|
||||
return new SvelteUIElement(Giggity, { tags: tagSource, state, giggityUrl })
|
||||
|
@ -1646,12 +1634,12 @@ export default class SpecialVisualizations {
|
|||
_: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const tags = (<ThemeViewState>(
|
||||
state
|
||||
)).geolocation.currentUserLocation.features.map(
|
||||
(features) => features[0]?.properties,
|
||||
(features) => features[0]?.properties
|
||||
)
|
||||
return new Combine([
|
||||
new SvelteUIElement(OrientationDebugPanel, {}),
|
||||
|
@ -1673,7 +1661,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
return new SvelteUIElement(MarkAsFavourite, {
|
||||
tags: tagSource,
|
||||
|
@ -1693,7 +1681,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
return new SvelteUIElement(MarkAsFavouriteMini, {
|
||||
tags: tagSource,
|
||||
|
@ -1713,7 +1701,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
return new SvelteUIElement(DirectionIndicator, { state, feature })
|
||||
},
|
||||
|
@ -1726,7 +1714,7 @@ export default class SpecialVisualizations {
|
|||
state: SpecialVisualizationState,
|
||||
tags: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
feature: Feature
|
||||
): SvelteUIElement {
|
||||
return new SvelteUIElement(QrCode, { state, tags, feature })
|
||||
},
|
||||
|
@ -1745,7 +1733,7 @@ export default class SpecialVisualizations {
|
|||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
args: string[]
|
||||
): BaseUIElement {
|
||||
const key = args[0] === "" ? "_direction:centerpoint" : args[0]
|
||||
return new VariableUiElement(
|
||||
|
@ -1756,11 +1744,11 @@ export default class SpecialVisualizations {
|
|||
})
|
||||
.mapD((value) => {
|
||||
const dir = GeoOperations.bearingToHuman(
|
||||
GeoOperations.parseBearing(value),
|
||||
GeoOperations.parseBearing(value)
|
||||
)
|
||||
console.log("Human dir", dir)
|
||||
return Translations.t.general.visualFeedback.directionsAbsolute[dir]
|
||||
}),
|
||||
})
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1790,7 +1778,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const url = args[0]
|
||||
const readonly = args[3] === "yes"
|
||||
|
@ -1816,12 +1804,12 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
return new Toggle(
|
||||
undefined,
|
||||
new SvelteUIElement(LoginButton, { osmConnection: state.osmConnection }),
|
||||
state.osmConnection.isLoggedIn,
|
||||
state.osmConnection.isLoggedIn
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1859,7 +1847,7 @@ export default class SpecialVisualizations {
|
|||
tags: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const key = argument[0] ?? "website"
|
||||
const useProxy = argument[1] !== "no"
|
||||
|
@ -1886,11 +1874,11 @@ export default class SpecialVisualizations {
|
|||
const features =
|
||||
await LinkedDataLoader.fetchVeloparkEntry(
|
||||
url,
|
||||
loadAll,
|
||||
loadAll
|
||||
)
|
||||
const feature =
|
||||
features.find(
|
||||
(f) => f.properties["ref:velopark"] === url,
|
||||
(f) => f.properties["ref:velopark"] === url
|
||||
) ?? features[0]
|
||||
const properties = feature.properties
|
||||
properties["ref:velopark"] = url
|
||||
|
@ -1900,7 +1888,7 @@ export default class SpecialVisualizations {
|
|||
console.error(e)
|
||||
throw e
|
||||
}
|
||||
})(),
|
||||
})()
|
||||
)
|
||||
}
|
||||
return Stores.FromPromiseWithErr(
|
||||
|
@ -1909,27 +1897,27 @@ export default class SpecialVisualizations {
|
|||
return await LinkedDataLoader.fetchJsonLd(
|
||||
url,
|
||||
{ country },
|
||||
useProxy ? "proxy" : "fetch-lod",
|
||||
useProxy ? "proxy" : "fetch-lod"
|
||||
)
|
||||
} catch (e) {
|
||||
console.log(
|
||||
"Could not get with proxy/download LOD, attempting to download directly. Error for ",
|
||||
url,
|
||||
"is",
|
||||
e,
|
||||
e
|
||||
)
|
||||
return await LinkedDataLoader.fetchJsonLd(
|
||||
url,
|
||||
{ country },
|
||||
"fetch-raw",
|
||||
"fetch-raw"
|
||||
)
|
||||
}
|
||||
})(),
|
||||
})()
|
||||
)
|
||||
})
|
||||
|
||||
externalData.addCallbackAndRunD((lod) =>
|
||||
console.log("linked_data_from_website received the following data:", lod),
|
||||
console.log("linked_data_from_website received the following data:", lod)
|
||||
)
|
||||
|
||||
return new Toggle(
|
||||
|
@ -1944,7 +1932,7 @@ export default class SpecialVisualizations {
|
|||
collapsed: isClosed,
|
||||
}),
|
||||
undefined,
|
||||
url.map((url) => !!url),
|
||||
url.map((url) => !!url)
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1964,7 +1952,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const text = argument[0]
|
||||
const cssClasses = argument[1]
|
||||
|
@ -1986,10 +1974,10 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const translation = tagSource.map((tags) => {
|
||||
const layer = state.layout.getMatchingLayer(tags)
|
||||
const layer = state.theme.getMatchingLayer(tags)
|
||||
return layer?.getMostMatchingPreset(tags)?.description
|
||||
})
|
||||
return new VariableUiElement(translation)
|
||||
|
@ -2004,7 +1992,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
return new SvelteUIElement(PendingChangesIndicator, { state, compact: false })
|
||||
},
|
||||
|
@ -2024,7 +2012,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): SvelteUIElement {
|
||||
return new SvelteUIElement<any, any, any>(ClearCaches, {
|
||||
msg: argument[0] ?? "Clear local caches",
|
||||
|
@ -2049,7 +2037,7 @@ export default class SpecialVisualizations {
|
|||
tags: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
selectedElement: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): SvelteUIElement {
|
||||
const [header, labelsStr] = argument
|
||||
const labels = labelsStr.split(";").map((x) => x.trim())
|
||||
|
@ -2072,7 +2060,7 @@ export default class SpecialVisualizations {
|
|||
tags: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
selectedElement: Feature,
|
||||
layer: LayerConfig,
|
||||
layer: LayerConfig
|
||||
): SvelteUIElement {
|
||||
const t = Translations.t.preset_type
|
||||
const question: QuestionableTagRenderingConfigJson = {
|
||||
|
@ -2107,7 +2095,13 @@ export default class SpecialVisualizations {
|
|||
doc: "Text to show on the button",
|
||||
},
|
||||
],
|
||||
constr(state: SpecialVisualizationState, tagSource: UIEventSource<Record<string, string>>, argument: string[], feature: Feature, layer: LayerConfig): BaseUIElement {
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const text = argument[0]
|
||||
return new SubtleButton(undefined, text).onClick(() => {
|
||||
state.osmConnection.preferencesHandler.ClearPreferences()
|
||||
|
@ -2138,7 +2132,7 @@ export default class SpecialVisualizations {
|
|||
"Invalid special visualisation found: funcName is undefined or doesn't match " +
|
||||
regex +
|
||||
invalid.map((sp) => sp.i).join(", ") +
|
||||
". Did you perhaps type \n funcName: \"funcname\" // type declaration uses COLON\ninstead of:\n funcName = \"funcName\" // value definition uses EQUAL"
|
||||
'. Did you perhaps type \n funcName: "funcname" // type declaration uses COLON\ninstead of:\n funcName = "funcName" // value definition uses EQUAL'
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue