forked from MapComplete/MapComplete
Merge develop
This commit is contained in:
commit
08ffe4b7c0
146 changed files with 4380 additions and 1435 deletions
|
|
@ -23,7 +23,6 @@ export default class AllThemesGui {
|
|||
undefined,
|
||||
"Used to complete the login"
|
||||
),
|
||||
osmConfiguration: <"osm" | "osm-test">featureSwitches.featureSwitchApiURL.data,
|
||||
})
|
||||
const state = new UserRelatedState(osmConnection)
|
||||
const intro = new Combine([
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { Utils } from "../../Utils"
|
|||
import Constants from "../../Models/Constants"
|
||||
|
||||
export class OpenJosm extends Combine {
|
||||
public static readonly needsUrls = ["http://127.0.0.1:8111/load_and_zoom"]
|
||||
constructor(osmConnection: OsmConnection, bounds: Store<BBox>, iconStyle?: string) {
|
||||
const t = Translations.t.general.attribution
|
||||
|
||||
|
|
|
|||
|
|
@ -14,13 +14,6 @@
|
|||
export let tags: UIEventSource<Record<string, string>>
|
||||
export let highlightedRendering: UIEventSource<string> = undefined
|
||||
|
||||
let _tags: Record<string, string>
|
||||
onDestroy(
|
||||
tags.addCallbackAndRun((tags) => {
|
||||
_tags = tags
|
||||
})
|
||||
)
|
||||
|
||||
let _metatags: Record<string, string>
|
||||
onDestroy(
|
||||
state.userRelatedState.preferencesAsTags.addCallbackAndRun((tags) => {
|
||||
|
|
@ -29,7 +22,7 @@
|
|||
)
|
||||
</script>
|
||||
|
||||
{#if _tags._deleted === "yes"}
|
||||
{#if $tags._deleted === "yes"}
|
||||
<Tr t={Translations.t.delete.isDeleted} />
|
||||
<button class="w-full" on:click={() => state.selectedElement.setData(undefined)}>
|
||||
<Tr t={Translations.t.general.returnToTheMap} />
|
||||
|
|
@ -37,8 +30,8 @@
|
|||
{:else}
|
||||
<div class="flex flex-col gap-y-2 overflow-y-auto p-1 px-2">
|
||||
{#each layer.tagRenderings as config (config.id)}
|
||||
{#if (config.condition === undefined || config.condition.matchesProperties(_tags)) && (config.metacondition === undefined || config.metacondition.matchesProperties( { ..._tags, ..._metatags } ))}
|
||||
{#if config.IsKnown(_tags)}
|
||||
{#if (config.condition?.matchesProperties($tags) ?? true) && config.metacondition?.matchesProperties({ ...$tags, ..._metatags } ?? true)}
|
||||
{#if config.IsKnown($tags)}
|
||||
<TagRenderingEditable
|
||||
{tags}
|
||||
{config}
|
||||
|
|
|
|||
|
|
@ -417,10 +417,19 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
|||
if (!map.getLayer(addLayerBeforeId)) {
|
||||
addLayerBeforeId = undefined
|
||||
}
|
||||
await this.awaitStyleIsLoaded()
|
||||
if (!map.getSource(background.id)) {
|
||||
map.addSource(background.id, MapLibreAdaptor.prepareWmsSource(background))
|
||||
}
|
||||
if (!map.getLayer(background.id)) {
|
||||
console.log(
|
||||
"Adding background layer",
|
||||
background.id,
|
||||
"beforeId",
|
||||
addLayerBeforeId,
|
||||
"; all layers are",
|
||||
map.getStyle().layers.map((l) => l.id)
|
||||
)
|
||||
map.addLayer(
|
||||
{
|
||||
id: background.id,
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource";
|
||||
import type { Map as MlMap } from "maplibre-gl";
|
||||
import { GeoJSONSource, Marker } from "maplibre-gl";
|
||||
import { ShowDataLayerOptions } from "./ShowDataLayerOptions";
|
||||
import { GeoOperations } from "../../Logic/GeoOperations";
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
||||
import PointRenderingConfig from "../../Models/ThemeConfig/PointRenderingConfig";
|
||||
import { OsmTags } from "../../Models/OsmFeature";
|
||||
import { FeatureSource, FeatureSourceForLayer } from "../../Logic/FeatureSource/FeatureSource";
|
||||
import { BBox } from "../../Logic/BBox";
|
||||
import { Feature, Point } from "geojson";
|
||||
import LineRenderingConfig from "../../Models/ThemeConfig/LineRenderingConfig";
|
||||
import { Utils } from "../../Utils";
|
||||
import * as range_layer from "../../../assets/layers/range/range.json";
|
||||
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson";
|
||||
import PerLayerFeatureSourceSplitter from "../../Logic/FeatureSource/PerLayerFeatureSourceSplitter";
|
||||
import FilteredLayer from "../../Models/FilteredLayer";
|
||||
import SimpleFeatureSource from "../../Logic/FeatureSource/Sources/SimpleFeatureSource";
|
||||
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import type { Map as MlMap } from "maplibre-gl"
|
||||
import { GeoJSONSource, Marker } from "maplibre-gl"
|
||||
import { ShowDataLayerOptions } from "./ShowDataLayerOptions"
|
||||
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import PointRenderingConfig from "../../Models/ThemeConfig/PointRenderingConfig"
|
||||
import { OsmTags } from "../../Models/OsmFeature"
|
||||
import { FeatureSource, FeatureSourceForLayer } from "../../Logic/FeatureSource/FeatureSource"
|
||||
import { BBox } from "../../Logic/BBox"
|
||||
import { Feature, Point } from "geojson"
|
||||
import LineRenderingConfig from "../../Models/ThemeConfig/LineRenderingConfig"
|
||||
import { Utils } from "../../Utils"
|
||||
import * as range_layer from "../../../assets/layers/range/range.json"
|
||||
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
import PerLayerFeatureSourceSplitter from "../../Logic/FeatureSource/PerLayerFeatureSourceSplitter"
|
||||
import FilteredLayer from "../../Models/FilteredLayer"
|
||||
import SimpleFeatureSource from "../../Logic/FeatureSource/Sources/SimpleFeatureSource"
|
||||
|
||||
class PointRenderingLayer {
|
||||
private readonly _config: PointRenderingConfig
|
||||
|
|
@ -228,6 +228,8 @@ class LineRenderingLayer {
|
|||
this._onClick = onClick
|
||||
const self = this
|
||||
features.features.addCallbackAndRunD(() => self.update(features.features))
|
||||
|
||||
map.on("styledata", () => self.update(features.features))
|
||||
}
|
||||
|
||||
public destruct(): void {
|
||||
|
|
@ -280,22 +282,27 @@ class LineRenderingLayer {
|
|||
// As such, we only now read the features from the featureSource and compare with the previously set data
|
||||
const features = featureSource.data
|
||||
const src = <GeoJSONSource>map.getSource(this._layername)
|
||||
if (this.currentSourceData === features) {
|
||||
if (
|
||||
src !== undefined &&
|
||||
this.currentSourceData === features &&
|
||||
src._data === <any>features
|
||||
) {
|
||||
// Already up to date
|
||||
return
|
||||
}
|
||||
{// Add source to the map or update the features
|
||||
{
|
||||
// Add source to the map or update the feature source
|
||||
if (src === undefined) {
|
||||
this.currentSourceData = features;
|
||||
this.currentSourceData = features
|
||||
map.addSource(this._layername, {
|
||||
type: "geojson",
|
||||
data: {
|
||||
type: "FeatureCollection",
|
||||
features
|
||||
features,
|
||||
},
|
||||
promoteId: "id"
|
||||
});
|
||||
const linelayer = this._layername + "_line";
|
||||
promoteId: "id",
|
||||
})
|
||||
const linelayer = this._layername + "_line"
|
||||
map.addLayer({
|
||||
source: this._layername,
|
||||
id: linelayer,
|
||||
|
|
@ -304,14 +311,18 @@ 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",
|
||||
},
|
||||
})
|
||||
|
||||
for (const feature of features) {
|
||||
if (!feature.properties.id) {
|
||||
console.warn("Feature without id:", feature)
|
||||
continue
|
||||
}
|
||||
map.setFeatureState(
|
||||
{ source: this._layername, id: feature.properties.id },
|
||||
this.calculatePropsFor(feature.properties)
|
||||
|
|
@ -320,10 +331,10 @@ class LineRenderingLayer {
|
|||
|
||||
map.on("click", linelayer, (e) => {
|
||||
// line-layer-listener
|
||||
e.originalEvent["consumed"] = true;
|
||||
this._onClick(e.features[0]);
|
||||
});
|
||||
const polylayer = this._layername + "_polygon";
|
||||
e.originalEvent["consumed"] = true
|
||||
this._onClick(e.features[0])
|
||||
})
|
||||
const polylayer = this._layername + "_polygon"
|
||||
|
||||
map.addLayer({
|
||||
source: this._layername,
|
||||
|
|
@ -333,41 +344,40 @@ 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) => {
|
||||
// polygon-layer-listener
|
||||
if (e.originalEvent["consumed"]) {
|
||||
// This is a polygon beneath a marker, we can ignore it
|
||||
return;
|
||||
return
|
||||
}
|
||||
e.originalEvent["consumed"] = true;
|
||||
console.log("Got features:", e.features, e);
|
||||
this._onClick(e.features[0]);
|
||||
});
|
||||
e.originalEvent["consumed"] = true
|
||||
this._onClick(e.features[0])
|
||||
})
|
||||
}
|
||||
|
||||
this._visibility?.addCallbackAndRunD((visible) => {
|
||||
try {
|
||||
map.setLayoutProperty(linelayer, "visibility", visible ? "visible" : "none");
|
||||
map.setLayoutProperty(polylayer, "visibility", visible ? "visible" : "none");
|
||||
map.setLayoutProperty(linelayer, "visibility", visible ? "visible" : "none")
|
||||
map.setLayoutProperty(polylayer, "visibility", visible ? "visible" : "none")
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
"Error while setting visibility of layers ",
|
||||
linelayer,
|
||||
polylayer,
|
||||
e
|
||||
);
|
||||
)
|
||||
}
|
||||
});
|
||||
})
|
||||
} else {
|
||||
this.currentSourceData = features;
|
||||
this.currentSourceData = features
|
||||
src.setData({
|
||||
type: "FeatureCollection",
|
||||
features: this.currentSourceData
|
||||
});
|
||||
features: this.currentSourceData,
|
||||
})
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < features.length; i++) {
|
||||
|
|
@ -388,9 +398,6 @@ class LineRenderingLayer {
|
|||
if (this._listenerInstalledOn.has(id)) {
|
||||
continue
|
||||
}
|
||||
if (!map.getSource(this._layername)) {
|
||||
continue
|
||||
}
|
||||
if (this._fetchStore === undefined) {
|
||||
map.setFeatureState(
|
||||
{ source: this._layername, id },
|
||||
|
|
@ -399,8 +406,12 @@ class LineRenderingLayer {
|
|||
} else {
|
||||
const tags = this._fetchStore(id)
|
||||
this._listenerInstalledOn.add(id)
|
||||
tags.addCallbackAndRunD((properties) => {
|
||||
if(!map.getLayer(this._layername)){
|
||||
map.setFeatureState(
|
||||
{ source: this._layername, id },
|
||||
this.calculatePropsFor(feature.properties)
|
||||
)
|
||||
tags.addCallbackD((properties) => {
|
||||
if (!map.getLayer(this._layername)) {
|
||||
return
|
||||
}
|
||||
map.setFeatureState(
|
||||
|
|
@ -418,7 +429,6 @@ export default class ShowDataLayer {
|
|||
<any>range_layer,
|
||||
"ShowDataLayer.ts:range.json"
|
||||
)
|
||||
private readonly _map: Store<MlMap>
|
||||
private readonly _options: ShowDataLayerOptions & {
|
||||
layer: LayerConfig
|
||||
drawMarkers?: true | boolean
|
||||
|
|
@ -435,7 +445,6 @@ export default class ShowDataLayer {
|
|||
drawLines?: true | boolean
|
||||
}
|
||||
) {
|
||||
this._map = map
|
||||
this._options = options
|
||||
const self = this
|
||||
this.onDestroy.push(map.addCallbackAndRunD((map) => self.initDrawFeatures(map)))
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@ import Combine from "../Base/Combine"
|
|||
import Title from "../Base/Title"
|
||||
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import Constants from "../../Models/Constants"
|
||||
|
||||
export class AddNoteCommentViz implements SpecialVisualization {
|
||||
funcName = "add_note_comment"
|
||||
needsUrls = [Constants.osmAuthConfig.url]
|
||||
docs = "A textfield to add a comment to a node (with the option to close the note)."
|
||||
args = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import { Utils } from "../../Utils"
|
|||
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"
|
||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
import Loading from "../Base/Loading"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import Translations from "../i18n/Translations"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import { Changes } from "../../Logic/Osm/Changes"
|
||||
|
|
@ -209,6 +208,8 @@ class ApplyButton extends UIElement {
|
|||
export default class AutoApplyButton implements SpecialVisualization {
|
||||
public readonly docs: BaseUIElement
|
||||
public readonly funcName: string = "auto_apply"
|
||||
public readonly needsUrls = []
|
||||
|
||||
public readonly args: {
|
||||
name: string
|
||||
defaultValue?: string
|
||||
|
|
@ -271,14 +272,7 @@ export default class AutoApplyButton implements SpecialVisualization {
|
|||
argument: string[]
|
||||
): BaseUIElement {
|
||||
try {
|
||||
if (
|
||||
!state.layout.official &&
|
||||
!(
|
||||
state.featureSwitchIsTesting.data ||
|
||||
state.osmConnection._oauth_config.url ===
|
||||
OsmConnection.oauth_configs["osm-test"].url
|
||||
)
|
||||
) {
|
||||
if (!state.layout.official && !state.featureSwitchIsTesting.data) {
|
||||
const t = Translations.t.general.add.import
|
||||
return new Combine([
|
||||
new FixedUiElement(
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ import Toggle from "../Input/Toggle"
|
|||
import { LoginToggle } from "./LoginButton"
|
||||
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import Constants from "../../Models/Constants"
|
||||
|
||||
export class CloseNoteButton implements SpecialVisualization {
|
||||
public readonly funcName = "close_note"
|
||||
public readonly needsUrls = [Constants.osmAuthConfig.url]
|
||||
public readonly docs =
|
||||
"Button to close a note. A predifined text can be defined to close the note with. If the note is already closed, will show a small text."
|
||||
public readonly args = [
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@
|
|||
$: isHardDelete = changedProperties[DeleteConfig.deleteReasonKey] !== undefined
|
||||
|
||||
async function onDelete() {
|
||||
if (selectedTags === undefined) {
|
||||
return
|
||||
}
|
||||
currentState = "applying"
|
||||
let actionToTake: OsmChangeAction
|
||||
const changedProperties = TagUtils.changeAsProperties(selectedTags.asChange(tags?.data ?? {}))
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export class ExportAsGpxViz implements SpecialVisualization {
|
|||
funcName = "export_as_gpx"
|
||||
docs = "Exports the selected feature as GPX-file"
|
||||
args = []
|
||||
|
||||
needsUrls = []
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@ import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
|||
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import Histogram from "../BigComponents/Histogram"
|
||||
import { Feature } from "geojson"
|
||||
import Constants from "../../Models/Constants"
|
||||
|
||||
export class HistogramViz implements SpecialVisualization {
|
||||
funcName = "histogram"
|
||||
docs = "Create a histogram for a list of given values, read from the properties."
|
||||
needsUrls = []
|
||||
|
||||
example =
|
||||
'`{histogram(\'some_key\')}` with properties being `{some_key: ["a","b","a","c"]} to create a histogram'
|
||||
args = [
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export interface ConflateFlowArguments extends ImportFlowArguments {
|
|||
|
||||
export default class ConflateImportButtonViz implements SpecialVisualization, AutoAction {
|
||||
supportsAutoAction: boolean = true
|
||||
needsUrls = []
|
||||
public readonly funcName: string = "conflate_button"
|
||||
public readonly args: {
|
||||
name: string
|
||||
|
|
|
|||
|
|
@ -194,10 +194,7 @@ export default abstract class ImportFlow<ArgT extends ImportFlowArguments> {
|
|||
return { error: t.hasBeenImported }
|
||||
}
|
||||
|
||||
const usesTestUrl =
|
||||
this.state.osmConnection._oauth_config.url ===
|
||||
OsmConnection.oauth_configs["osm-test"].url
|
||||
if (!state.layout.official && !(isTesting || usesTestUrl)) {
|
||||
if (!state.layout.official && !isTesting) {
|
||||
// Unofficial theme - imports not allowed
|
||||
return {
|
||||
error: t.officialThemesOnly,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export class PointImportButtonViz implements SpecialVisualization {
|
|||
public readonly docs: string | BaseUIElement
|
||||
public readonly example?: string
|
||||
public readonly args: { name: string; defaultValue?: string; doc: string }[]
|
||||
public needsUrls = []
|
||||
|
||||
constructor() {
|
||||
this.funcName = "import_button"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSou
|
|||
*/
|
||||
export default class WayImportButtonViz implements AutoAction, SpecialVisualization {
|
||||
public readonly funcName: string = "import_way_button"
|
||||
needsUrls = []
|
||||
public readonly docs: string =
|
||||
"This button will copy the data from an external dataset into OpenStreetMap, copying the geometry and adding it as a 'line'" +
|
||||
ImportFlowUtils.documentationGeneral
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import { Feature } from "geojson"
|
|||
|
||||
export class LanguageElement implements SpecialVisualization {
|
||||
funcName: string = "language_chooser"
|
||||
needsUrls = []
|
||||
|
||||
docs: string | BaseUIElement =
|
||||
"The language element allows to show and pick all known (modern) languages. The key can be set"
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import MapillaryLink from "../BigComponents/MapillaryLink.svelte"
|
|||
export class MapillaryLinkVis implements SpecialVisualization {
|
||||
funcName = "mapillary_link"
|
||||
docs = "Adds a button to open mapillary on the specified location"
|
||||
needsUrls = []
|
||||
|
||||
args = [
|
||||
{
|
||||
name: "zoom",
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { BBox } from "../../Logic/BBox"
|
|||
export class MinimapViz implements SpecialVisualization {
|
||||
funcName = "minimap"
|
||||
docs = "A small map showing the selected feature."
|
||||
needsUrls = []
|
||||
args = [
|
||||
{
|
||||
doc: "The (maximum) zoomlevel: the target zoomlevel after fitting the entire feature. The minimap will fit the entire feature, then zoom out to this zoom level. The higher, the more zoomed in with 1 being the entire world and 19 being really close",
|
||||
|
|
@ -79,7 +80,9 @@ export class MinimapViz implements SpecialVisualization {
|
|||
)
|
||||
|
||||
const mlmap = new UIEventSource(undefined)
|
||||
const mla = new MapLibreAdaptor(mlmap)
|
||||
const mla = new MapLibreAdaptor(mlmap, {
|
||||
rasterLayer: state.mapProperties.rasterLayer,
|
||||
})
|
||||
|
||||
mla.maxzoom.setData(17)
|
||||
let zoom = 18
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisua
|
|||
|
||||
export class MultiApplyViz implements SpecialVisualization {
|
||||
funcName = "multi_apply"
|
||||
needsUrls = []
|
||||
docs =
|
||||
"A button to apply the tagging of this object onto a list of other features. This is an advanced feature for which you'll need calculatedTags"
|
||||
args = [
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders"
|
|||
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||
import PlantNet from "../PlantNet/PlantNet.svelte"
|
||||
|
||||
import { default as PlantNetCode } from "../../Logic/Web/PlantNet"
|
||||
export class PlantNetDetectionViz implements SpecialVisualization {
|
||||
funcName = "plantnet_detection"
|
||||
needsUrls = [PlantNetCode.baseUrl]
|
||||
|
||||
docs =
|
||||
"Sends the images linked to the current object to plantnet.org and asks it what plant species is shown on it. The user can then select the correct species; the corresponding wikidata-identifier will then be added to the object (together with `source:species:wikidata=plantnet.org AI`). "
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import { Feature } from "geojson"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||
import Questionbox from "./TagRendering/Questionbox.svelte"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
|
||||
/**
|
||||
* Thin wrapper around QuestionBox.svelte to include it into the special Visualisations
|
||||
*/
|
||||
export default class QuestionViz implements SpecialVisualization {
|
||||
funcName = "questions"
|
||||
docs =
|
||||
"The special element which shows the questions which are unkown. Added by default if not yet there"
|
||||
args = [
|
||||
{
|
||||
name: "labels",
|
||||
doc: "One or more ';'-separated labels. If these are given, only questions with these labels will be given. Use `unlabeled` for all questions that don't have an explicit label. If none given, all questions will be shown",
|
||||
},
|
||||
{
|
||||
name: "blacklisted-labels",
|
||||
doc: "One or more ';'-separated labels of questions which should _not_ be included",
|
||||
},
|
||||
]
|
||||
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tags: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const labels = args[0]
|
||||
?.split(";")
|
||||
?.map((s) => s.trim())
|
||||
?.filter((s) => s !== "")
|
||||
const blacklist = args[1]
|
||||
?.split(";")
|
||||
?.map((s) => s.trim())
|
||||
?.filter((s) => s !== "")
|
||||
return new SvelteUIElement(Questionbox, {
|
||||
layer,
|
||||
tags,
|
||||
selectedElement: feature,
|
||||
state,
|
||||
onlyForLabels: labels,
|
||||
notForLabels: blacklist,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ export class ShareLinkViz implements SpecialVisualization {
|
|||
doc: "The url to share (default: current URL)",
|
||||
},
|
||||
]
|
||||
needsUrls = []
|
||||
|
||||
public constr(
|
||||
state: SpecialVisualizationState,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import Maproulette from "../../Logic/Maproulette"
|
|||
|
||||
export default class TagApplyButton implements AutoAction, SpecialVisualization {
|
||||
public readonly funcName = "tag_apply"
|
||||
needsUrls = []
|
||||
public readonly docs =
|
||||
"Shows a big button; clicking this button will apply certain tags onto the feature.\n\nThe first argument takes a specification of which tags to add.\n" +
|
||||
Utils.Special_visualizations_tagsToApplyHelpText
|
||||
|
|
@ -110,6 +111,7 @@ export default class TagApplyButton implements AutoAction, SpecialVisualization
|
|||
|
||||
while (spec.length > 0) {
|
||||
const [part] = spec.match(/((\\;)|[^;])*/)
|
||||
console.log("Spec is", part, spec)
|
||||
spec = spec.substring(part.length + 1) // +1 to remove the pending ';' as well
|
||||
const kv = part.split("=").map((s) => s.trim().replace("\\;", ";"))
|
||||
if (kv.length == 2) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import UploadTraceToOsmUI from "../BigComponents/UploadTraceToOsmUI"
|
|||
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||
import Constants from "../../Models/Constants"
|
||||
|
||||
/**
|
||||
* Wrapper around 'UploadTraceToOsmUI'
|
||||
|
|
@ -11,6 +12,7 @@ export class UploadToOsmViz implements SpecialVisualization {
|
|||
docs =
|
||||
"Uploads the GPS-history as GPX to OpenStreetMap.org; clears the history afterwards. The actual feature is ignored."
|
||||
args = []
|
||||
needsUrls = [Constants.osmAuthConfig.url]
|
||||
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
|
|
|
|||
31
src/UI/RemoveOtherLanguages.js
Normal file
31
src/UI/RemoveOtherLanguages.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
let lang = (
|
||||
(navigator.languages && navigator.languages[0]) ||
|
||||
navigator.language ||
|
||||
navigator["userLanguage"] ||
|
||||
"en"
|
||||
).substr(0, 2)
|
||||
|
||||
function filterLangs(maindiv) {
|
||||
let foundLangs = 0
|
||||
for (const child of Array.from(maindiv.children)) {
|
||||
if (child.attributes.getNamedItem("lang")?.value === lang) {
|
||||
foundLangs++
|
||||
}
|
||||
}
|
||||
if (foundLangs === 0) {
|
||||
lang = "en"
|
||||
}
|
||||
for (const child of Array.from(maindiv.children)) {
|
||||
const childLang = child.attributes.getNamedItem("lang")
|
||||
if (childLang === undefined) {
|
||||
continue
|
||||
}
|
||||
if (childLang.value === lang) {
|
||||
continue
|
||||
}
|
||||
child.parentElement.removeChild(child)
|
||||
}
|
||||
}
|
||||
|
||||
filterLangs(document.getElementById("descriptions-while-loading"))
|
||||
filterLangs(document.getElementById("default-title"))
|
||||
|
|
@ -88,6 +88,7 @@ export interface SpecialVisualization {
|
|||
readonly funcName: string
|
||||
readonly docs: string | BaseUIElement
|
||||
readonly example?: string
|
||||
readonly needsUrls: string[]
|
||||
|
||||
/**
|
||||
* Indicates that this special visualisation will make requests to the 'alLNodesDatabase' and that it thus should be included
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import Wikidata, { WikidataResponse } from "../Logic/Web/Wikidata"
|
|||
import { Translation } from "./i18n/Translation"
|
||||
import Translations from "./i18n/Translations"
|
||||
import OpeningHoursVisualization from "./OpeningHours/OpeningHoursVisualization"
|
||||
import LiveQueryHandler from "../Logic/Web/LiveQueryHandler"
|
||||
import { SubtleButton } from "./Base/SubtleButton"
|
||||
import Svg from "../Svg"
|
||||
import NoteCommentElement from "./Popup/NoteCommentElement"
|
||||
|
|
@ -41,7 +40,6 @@ import FeatureReviews from "../Logic/Web/MangroveReviews"
|
|||
import Maproulette from "../Logic/Maproulette"
|
||||
import SvelteUIElement from "./Base/SvelteUIElement"
|
||||
import { BBoxFeatureSourceForLayer } from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
|
||||
import QuestionViz from "./Popup/QuestionViz"
|
||||
import { Feature, Point } from "geojson"
|
||||
import { GeoOperations } from "../Logic/GeoOperations"
|
||||
import CreateNewNote from "./Popup/CreateNewNote.svelte"
|
||||
|
|
@ -68,9 +66,15 @@ import SendEmail from "./Popup/SendEmail.svelte"
|
|||
import NearbyImages from "./Popup/NearbyImages.svelte"
|
||||
import NearbyImagesCollapsed from "./Popup/NearbyImagesCollapsed.svelte"
|
||||
import UploadImage from "./Image/UploadImage.svelte"
|
||||
import { Imgur } from "../Logic/ImageProviders/Imgur"
|
||||
import Constants from "../Models/Constants"
|
||||
import { MangroveReviews } from "mangrove-reviews-typescript"
|
||||
import Wikipedia from "../Logic/Web/Wikipedia"
|
||||
import NearbyImagesSearch from "../Logic/Web/NearbyImagesSearch"
|
||||
import AllReviews from "./Reviews/AllReviews.svelte"
|
||||
import StarsBarIcon from "./Reviews/StarsBarIcon.svelte"
|
||||
import ReviewForm from "./Reviews/ReviewForm.svelte"
|
||||
import Questionbox from "./Popup/TagRendering/Questionbox.svelte";
|
||||
|
||||
class NearbyImageVis implements SpecialVisualization {
|
||||
// Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests
|
||||
|
|
@ -84,7 +88,7 @@ class NearbyImageVis implements SpecialVisualization {
|
|||
docs =
|
||||
"A component showing nearby images loaded from various online services such as Mapillary. In edit mode and when used on a feature, the user can select an image to add to the feature"
|
||||
funcName = "nearby_images"
|
||||
|
||||
needsUrls = NearbyImagesSearch.apiUrls
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tags: UIEventSource<Record<string, string>>,
|
||||
|
|
@ -122,6 +126,7 @@ class StealViz implements SpecialVisualization {
|
|||
required: true,
|
||||
},
|
||||
]
|
||||
needsUrls = []
|
||||
|
||||
constr(state: SpecialVisualizationState, featureTags, args) {
|
||||
const [featureIdKey, layerAndtagRenderingIds] = args
|
||||
|
|
@ -176,6 +181,52 @@ class StealViz implements SpecialVisualization {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thin wrapper around QuestionBox.svelte to include it into the special Visualisations
|
||||
*/
|
||||
export class QuestionViz implements SpecialVisualization {
|
||||
funcName = "questions"
|
||||
needsUrls = []
|
||||
docs =
|
||||
"The special element which shows the questions which are unkown. Added by default if not yet there"
|
||||
args = [
|
||||
{
|
||||
name: "labels",
|
||||
doc: "One or more ';'-separated labels. If these are given, only questions with these labels will be given. Use `unlabeled` for all questions that don't have an explicit label. If none given, all questions will be shown",
|
||||
},
|
||||
{
|
||||
name: "blacklisted-labels",
|
||||
doc: "One or more ';'-separated labels of questions which should _not_ be included",
|
||||
},
|
||||
]
|
||||
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tags: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
): BaseUIElement {
|
||||
const labels = args[0]
|
||||
?.split(";")
|
||||
?.map((s) => s.trim())
|
||||
?.filter((s) => s !== "")
|
||||
const blacklist = args[1]
|
||||
?.split(";")
|
||||
?.map((s) => s.trim())
|
||||
?.filter((s) => s !== "")
|
||||
return new SvelteUIElement(Questionbox, {
|
||||
layer,
|
||||
tags,
|
||||
selectedElement: feature,
|
||||
state,
|
||||
onlyForLabels: labels,
|
||||
notForLabels: blacklist,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default class SpecialVisualizations {
|
||||
public static specialVisualizations: SpecialVisualization[] = SpecialVisualizations.initList()
|
||||
|
||||
|
|
@ -382,6 +433,7 @@ export default class SpecialVisualizations {
|
|||
funcName: "add_new_point",
|
||||
docs: "An element which allows to add a new point on the 'last_click'-location. Only makes sense in the layer `last_click`",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
constr(state: SpecialVisualizationState, _, __, feature): BaseUIElement {
|
||||
let [lon, lat] = GeoOperations.centerpointCoordinates(feature)
|
||||
return new SvelteUIElement(AddNewPoint, {
|
||||
|
|
@ -393,6 +445,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "user_profile",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
docs: "A component showing information about the currently logged in user (username, profile description, profile picture + link to edit them). Mostly meant to be used in the 'user-settings'",
|
||||
constr(state: SpecialVisualizationState): BaseUIElement {
|
||||
return new SvelteUIElement(UserProfile, {
|
||||
|
|
@ -403,6 +456,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "language_picker",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
docs: "A component to set the language of the user interface",
|
||||
constr(state: SpecialVisualizationState): BaseUIElement {
|
||||
return new LanguagePicker(
|
||||
|
|
@ -414,6 +468,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "logout",
|
||||
args: [],
|
||||
needsUrls: [Constants.osmAuthConfig.url],
|
||||
docs: "Shows a button where the user can log out",
|
||||
constr(state: SpecialVisualizationState): BaseUIElement {
|
||||
return new SubtleButton(Svg.logout_svg(), Translations.t.general.logout, {
|
||||
|
|
@ -430,6 +485,7 @@ export default class SpecialVisualizations {
|
|||
funcName: "split_button",
|
||||
docs: "Adds a button which allows to split a way",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>
|
||||
|
|
@ -450,6 +506,7 @@ export default class SpecialVisualizations {
|
|||
funcName: "move_button",
|
||||
docs: "Adds a button which allows to move the object to another location. The config will be read from the layer config",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
|
|
@ -473,6 +530,7 @@ export default class SpecialVisualizations {
|
|||
funcName: "delete_button",
|
||||
docs: "Adds a button which allows to delete the object at this location. The config will be read from the layer config",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
|
|
@ -497,6 +555,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "open_note",
|
||||
args: [],
|
||||
needsUrls: [Constants.osmAuthConfig.url],
|
||||
docs: "Creates a new map note on the given location. This options is placed in the 'last_click'-popup automatically if the 'notes'-layer is enabled",
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
|
|
@ -529,6 +588,7 @@ export default class SpecialVisualizations {
|
|||
defaultValue: "wikidata;wikipedia",
|
||||
},
|
||||
],
|
||||
needsUrls: [...Wikidata.neededUrls, ...Wikipedia.neededUrls],
|
||||
example:
|
||||
"`{wikipedia()}` is a basic example, `{wikipedia(name:etymology:wikidata)}` to show the wikipedia page of whom the feature was named after. Also remember that these can be styled, e.g. `{wikipedia():max-height: 10rem}` to limit the height",
|
||||
constr: (_, tagsSource, args) => {
|
||||
|
|
@ -552,6 +612,7 @@ export default class SpecialVisualizations {
|
|||
defaultValue: "wikidata",
|
||||
},
|
||||
],
|
||||
needsUrls: Wikidata.neededUrls,
|
||||
example:
|
||||
"`{wikidata_label()}` is a basic example, `{wikipedia(name:etymology:wikidata)}` to show the label itself",
|
||||
constr: (_, tagsSource, args) =>
|
||||
|
|
@ -581,6 +642,7 @@ export default class SpecialVisualizations {
|
|||
funcName: "all_tags",
|
||||
docs: "Prints all key-value pairs of the object - used for debugging",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
constr: (state, tags: UIEventSource<any>) =>
|
||||
new SvelteUIElement(AllTagsPanel, { tags, state }),
|
||||
},
|
||||
|
|
@ -594,6 +656,7 @@ export default class SpecialVisualizations {
|
|||
doc: "The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc... Multiple values are allowed if ';'-separated ",
|
||||
},
|
||||
],
|
||||
needsUrls: AllImageProviders.apiUrls,
|
||||
constr: (state, tags, args) => {
|
||||
let imagePrefixes: string[] = undefined
|
||||
if (args.length > 0) {
|
||||
|
|
@ -609,6 +672,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "image_upload",
|
||||
docs: "Creates a button where a user can upload an image to IMGUR",
|
||||
needsUrls: [Imgur.apiUrl],
|
||||
args: [
|
||||
{
|
||||
name: "image-key",
|
||||
|
|
@ -633,6 +697,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "rating",
|
||||
docs: "Shows stars which represent the avarage rating on mangrove.reviews",
|
||||
needsUrls: [MangroveReviews.ORIGINAL_API],
|
||||
args: [
|
||||
{
|
||||
name: "subjectKey",
|
||||
|
|
@ -658,11 +723,6 @@ export default class SpecialVisualizations {
|
|||
)
|
||||
return new SvelteUIElement(StarsBarIcon, {
|
||||
score: reviews.average,
|
||||
reviews,
|
||||
state,
|
||||
tags,
|
||||
feature,
|
||||
layer,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
|
@ -670,6 +730,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "create_review",
|
||||
docs: "Invites the contributor to leave a review. Somewhat small UI-element until interacted",
|
||||
needsUrls: [MangroveReviews.ORIGINAL_API],
|
||||
args: [
|
||||
{
|
||||
name: "subjectKey",
|
||||
|
|
@ -699,6 +760,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "list_reviews",
|
||||
docs: "Adds an overview of the mangrove-reviews of this object. Mangrove.Reviews needs - in order to identify the reviewed object - a coordinate and a name. By default, the name of the object is given, but this can be overwritten",
|
||||
needsUrls: [MangroveReviews.ORIGINAL_API],
|
||||
example:
|
||||
"`{reviews()}` for a vanilla review, `{reviews(name, play_forest)}` to review a play forest. If a name is known, the name will be used as identifier, otherwise 'play_forest' is used",
|
||||
args: [
|
||||
|
|
@ -747,6 +809,7 @@ export default class SpecialVisualizations {
|
|||
doc: "Remove this string from the end of the value before parsing. __Note: use `&RPARENs` to indicate `)` if needed__",
|
||||
},
|
||||
],
|
||||
needsUrls: [],
|
||||
example:
|
||||
"A normal opening hours table can be invoked with `{opening_hours_table()}`. A table for e.g. conditional access with opening hours can be `{opening_hours_table(access:conditional, no @ &LPARENS, &RPARENS)}`",
|
||||
constr: (state, tagSource: UIEventSource<any>, args) => {
|
||||
|
|
@ -759,38 +822,9 @@ export default class SpecialVisualizations {
|
|||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
funcName: "live",
|
||||
docs: "Downloads a JSON from the given URL, e.g. '{live(example.org/data.json, shorthand:x.y.z, other:a.b.c, shorthand)}' will download the given file, will create an object {shorthand: json[x][y][z], other: json[a][b][c] out of it and will return 'other' or 'json[a][b][c]. This is made to use in combination with tags, e.g. {live({url}, {url:format}, needed_value)}",
|
||||
example:
|
||||
"{live({url},{url:format},hour)} {live(https://data.mobility.brussels/bike/api/counts/?request=live&featureID=CB2105,hour:data.hour_cnt;day:data.day_cnt;year:data.year_cnt,hour)}",
|
||||
args: [
|
||||
{
|
||||
name: "Url",
|
||||
doc: "The URL to load",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "Shorthands",
|
||||
doc: "A list of shorthands, of the format 'shorthandname:path.path.path'. separated by ;",
|
||||
},
|
||||
{
|
||||
name: "path",
|
||||
doc: "The path (or shorthand) that should be returned",
|
||||
},
|
||||
],
|
||||
constr: (_, tagSource: UIEventSource<any>, args) => {
|
||||
const url = args[0]
|
||||
const shorthands = args[1]
|
||||
const neededValue = args[2]
|
||||
const source = LiveQueryHandler.FetchLiveData(url, shorthands.split(";"))
|
||||
return new VariableUiElement(
|
||||
source.map((data) => data[neededValue] ?? "Loading...")
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
funcName: "canonical",
|
||||
needsUrls: [],
|
||||
docs: "Converts a short, canonical value into the long, translated text including the unit. This only works if a `unit` is defined for the corresponding value. The unit specification will be included in the text. ",
|
||||
example:
|
||||
"If the object has `length=42`, then `{canonical(length)}` will be shown as **42 meter** (in english), **42 metre** (in french), ...",
|
||||
|
|
@ -828,6 +862,7 @@ export default class SpecialVisualizations {
|
|||
funcName: "export_as_geojson",
|
||||
docs: "Exports the selected feature as GeoJson-file",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
constr: (state, tagSource, tagsSource, feature, layer) => {
|
||||
const t = Translations.t.general.download
|
||||
|
||||
|
|
@ -857,6 +892,7 @@ export default class SpecialVisualizations {
|
|||
funcName: "open_in_iD",
|
||||
docs: "Opens the current view in the iD-editor",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
constr: (state, feature) => {
|
||||
return new SvelteUIElement(OpenIdEditor, {
|
||||
mapProperties: state.mapProperties,
|
||||
|
|
@ -868,6 +904,8 @@ export default class SpecialVisualizations {
|
|||
funcName: "open_in_josm",
|
||||
docs: "Opens the current view in the JOSM-editor",
|
||||
args: [],
|
||||
needsUrls: OpenJosm.needsUrls,
|
||||
|
||||
constr: (state) => {
|
||||
return new OpenJosm(state.osmConnection, state.mapProperties.bounds)
|
||||
},
|
||||
|
|
@ -876,6 +914,7 @@ export default class SpecialVisualizations {
|
|||
funcName: "clear_location_history",
|
||||
docs: "A button to remove the travelled track information from the device",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
constr: (state) => {
|
||||
return new SubtleButton(
|
||||
Svg.delete_icon_svg().SetStyle("height: 1.5rem"),
|
||||
|
|
@ -901,6 +940,7 @@ export default class SpecialVisualizations {
|
|||
defaultValue: "0",
|
||||
},
|
||||
],
|
||||
needsUrls: [Constants.osmAuthConfig.url],
|
||||
constr: (state, tags, args) =>
|
||||
new VariableUiElement(
|
||||
tags
|
||||
|
|
@ -929,6 +969,7 @@ export default class SpecialVisualizations {
|
|||
defaultValue: "id",
|
||||
},
|
||||
],
|
||||
needsUrls: [Imgur.apiUrl],
|
||||
constr: (state, tags, args) => {
|
||||
const id = tags.data[args[0] ?? "id"]
|
||||
tags = state.featureProperties.getStore(id)
|
||||
|
|
@ -939,6 +980,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "title",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
docs: "Shows the title of the popup. Useful for some cases, e.g. 'What is phone number of {title()}?'",
|
||||
example:
|
||||
"`What is the phone number of {title()}`, which might automatically become `What is the phone number of XYZ`.",
|
||||
|
|
@ -959,6 +1001,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "maproulette_task",
|
||||
args: [],
|
||||
needsUrls: [Maproulette.defaultEndpoint],
|
||||
constr(state, tagSource) {
|
||||
let parentId = tagSource.data.mr_challengeId
|
||||
if (parentId === undefined) {
|
||||
|
|
@ -967,7 +1010,7 @@ export default class SpecialVisualizations {
|
|||
}
|
||||
let challenge = Stores.FromPromise(
|
||||
Utils.downloadJsonCached(
|
||||
`https://maproulette.org/api/v2/challenge/${parentId}`,
|
||||
`${Maproulette.defaultEndpoint}/challenge/${parentId}`,
|
||||
24 * 60 * 60 * 1000
|
||||
)
|
||||
)
|
||||
|
|
@ -1002,6 +1045,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "maproulette_set_status",
|
||||
docs: "Change the status of the given MapRoulette task",
|
||||
needsUrls: [Maproulette.defaultEndpoint],
|
||||
example:
|
||||
" The following example sets the status to '2' (false positive)\n" +
|
||||
"\n" +
|
||||
|
|
@ -1125,6 +1169,7 @@ export default class SpecialVisualizations {
|
|||
funcName: "statistics",
|
||||
docs: "Show general statistics about the elements currently in view. Intended to use on the `current_view`-layer",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
constr: (state) => {
|
||||
return new Combine(
|
||||
state.layout.layers
|
||||
|
|
@ -1167,6 +1212,8 @@ export default class SpecialVisualizations {
|
|||
required: true,
|
||||
},
|
||||
],
|
||||
needsUrls: [],
|
||||
|
||||
constr(__, tags, args) {
|
||||
return new SvelteUIElement(SendEmail, { args, tags })
|
||||
},
|
||||
|
|
@ -1194,6 +1241,7 @@ export default class SpecialVisualizations {
|
|||
doc: "If set, this link will act as a download-button. The contents of `href` will be offered for download; this parameter will act as the proposed filename",
|
||||
},
|
||||
],
|
||||
needsUrls: [],
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
|
|
@ -1215,6 +1263,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "multi",
|
||||
docs: "Given an embedded tagRendering (read only) and a key, will read the keyname as a JSON-list. Every element of this list will be considered as tags and rendered with the tagRendering",
|
||||
needsUrls: [],
|
||||
example:
|
||||
"```json\n" +
|
||||
JSON.stringify(
|
||||
|
|
@ -1305,6 +1354,7 @@ export default class SpecialVisualizations {
|
|||
required: true,
|
||||
},
|
||||
],
|
||||
needsUrls: [],
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ export class SubstitutedTranslation extends VariableUiElement {
|
|||
constr: typeof value === "function" ? value : () => value,
|
||||
docs: "Dynamically injected input element",
|
||||
args: [],
|
||||
needsUrls: [],
|
||||
example: "",
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue