Merge develop
This commit is contained in:
parent
c62705c1dd
commit
c167094b65
12 changed files with 251 additions and 139 deletions
assets/layers/usersettings
src
Logic
Models/ThemeConfig
UI
index_theme.ts.template
|
@ -1465,13 +1465,51 @@
|
|||
"#force-save-button": "yes"
|
||||
},
|
||||
{
|
||||
"id": "debug-gps",
|
||||
"id": "debug-gps-group",
|
||||
"condition": "mapcomplete-show_debug=yes",
|
||||
"render": {
|
||||
"special": {
|
||||
"type": "group",
|
||||
"header": "debug-gps-title",
|
||||
"labels": "debug-gps"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "debug-gps-title",
|
||||
"labels": ["hidden"],
|
||||
"render": {
|
||||
"en": "GPS info"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "debug-gps",
|
||||
"labels": ["hidden"],
|
||||
"render": "{gps_all_tags()}"
|
||||
},
|
||||
|
||||
{
|
||||
"id": "debug-info-group",
|
||||
"condition": "mapcomplete-show_debug=yes",
|
||||
|
||||
"render": {
|
||||
"special": {
|
||||
"type": "group",
|
||||
"header": "debug-tags-title",
|
||||
"labels": "debug"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "debug-tags-title",
|
||||
"labels": ["hidden"],
|
||||
"render": {
|
||||
"en": "Debug info"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "debug",
|
||||
"condition": "mapcomplete-show_debug=yes",
|
||||
"labels": ["hidden"],
|
||||
"render": "{all_tags()}"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -14,7 +14,7 @@ export interface GeoLocationPointProperties extends GeolocationCoordinates {
|
|||
}
|
||||
|
||||
/**
|
||||
* An abstract representation of the current state of the geolocation.
|
||||
* An abstract representation of the current state of the geolocation, keeping track of permissions and if a location is known.
|
||||
*/
|
||||
export class GeoLocationState {
|
||||
/**
|
||||
|
@ -167,8 +167,16 @@ export class GeoLocationState {
|
|||
|
||||
if(AndroidPolyfill.inAndroid.data){
|
||||
this.permission.setData("requested")
|
||||
AndroidPolyfill.geolocationPermission.addCallbackAndRunD(state => this.permission.set(state))
|
||||
this.startWatching()
|
||||
this.permission.addCallbackAndRunD(p => {
|
||||
if(p === "granted"){
|
||||
this.startWatching()
|
||||
return true
|
||||
}
|
||||
})
|
||||
AndroidPolyfill.requestGeoPermission().then(state => {
|
||||
const granted = state.value === "true"
|
||||
this.permission.set(granted ? "granted" : "denied")
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -210,6 +218,13 @@ export class GeoLocationState {
|
|||
* @private
|
||||
*/
|
||||
private async startWatching() {
|
||||
|
||||
if(AndroidPolyfill.inAndroid.data){
|
||||
AndroidPolyfill.watchLocation( this.currentGPSLocation, location => {
|
||||
console.log(JSON.stringify(location))
|
||||
})
|
||||
}
|
||||
|
||||
navigator.geolocation.watchPosition(
|
||||
(position: GeolocationPosition) => {
|
||||
this._gpsAvailable.set(true)
|
||||
|
|
|
@ -416,6 +416,10 @@ export default class UserRelatedState {
|
|||
typeof window === "undefined" ? "no" : window.navigator.share ? "yes" : "no",
|
||||
_iframe: Utils.isIframe ? "yes" : "no",
|
||||
})
|
||||
if(!Utils.runningFromConsole){
|
||||
amendedPrefs.data["_host"] = window.location.host
|
||||
amendedPrefs.data["_path"] = window.location.pathname
|
||||
}
|
||||
|
||||
for (const key in Constants.userJourney) {
|
||||
amendedPrefs.data["__userjourney_" + key] = Constants.userJourney[key]
|
||||
|
|
|
@ -19,9 +19,9 @@ const DatabridgePluginSingleton = registerPlugin<DatabridgePlugin>("Databridge",
|
|||
return { value: "web" }
|
||||
}
|
||||
return null
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export class AndroidPolyfill {
|
||||
|
@ -36,12 +36,18 @@ export class AndroidPolyfill {
|
|||
* @private
|
||||
*/
|
||||
private backfillGeolocation(databridgePlugin: DatabridgePlugin) {
|
||||
const src = UIEventSource.FromPromise(databridgePlugin.request({ key: "location:request-permission" }))
|
||||
const src = UIEventSource.FromPromise(databridgePlugin.request({ key: "location:has-permission" }))
|
||||
src.addCallbackAndRunD(permission => {
|
||||
AndroidPolyfill._geolocationPermission.set(<"granted" | "denied">permission.value)
|
||||
console.log("> Checking geopermission gave: ", JSON.stringify(permission), permission.value)
|
||||
const granted = permission.value === "true"
|
||||
AndroidPolyfill._geolocationPermission.set(granted ? "granted" : "denied")
|
||||
})
|
||||
}
|
||||
|
||||
public static async requestGeoPermission(): Promise<{ value: string | object }> {
|
||||
return DatabridgePluginSingleton.request({ key: "location:request-permission" })
|
||||
}
|
||||
|
||||
public async init() {
|
||||
console.log("Sniffing shell version")
|
||||
const shell = await this.databridgePlugin.request({ key: "meta" })
|
||||
|
@ -55,9 +61,9 @@ export class AndroidPolyfill {
|
|||
}
|
||||
|
||||
public static async requestLoginCodes() {
|
||||
const result = await DatabridgePluginSingleton.request<{oauth_token: string}>({ key: "request:login" })
|
||||
const result = await DatabridgePluginSingleton.request<{ oauth_token: string }>({ key: "request:login" })
|
||||
const token: string = result.value.oauth_token
|
||||
console.log("AndroidPolyfill: received oauth_token; trying to pass them to the oauth lib",token)
|
||||
console.log("AndroidPolyfill: received oauth_token; trying to pass them to the oauth lib", token)
|
||||
return token
|
||||
}
|
||||
|
||||
|
@ -67,7 +73,7 @@ export class AndroidPolyfill {
|
|||
console.log("Registering back button callback", callback)
|
||||
DatabridgePluginSingleton.request({ key: "backbutton" }).then(ev => {
|
||||
console.log("AndroidPolyfill: received backbutton: ", ev)
|
||||
if(ev === null){
|
||||
if (ev === null) {
|
||||
// Probably in web environment
|
||||
return
|
||||
}
|
||||
|
@ -84,5 +90,26 @@ export class AndroidPolyfill {
|
|||
})
|
||||
|
||||
}
|
||||
|
||||
public static watchLocation(writeInto: UIEventSource<GeolocationCoordinates>, callback: (location) => void) {
|
||||
DatabridgePluginSingleton.request({
|
||||
key: "location:watch",
|
||||
}).then((l: {
|
||||
value: { latitude: number, longitude: number, accuraccy: number, altidude: number, heading: number, speed:number }
|
||||
}) => {
|
||||
// example l: {"value":{"latitude":51.0618627,"longitude":3.730468566666667,"accuracy":2.0393495559692383,"altitude":46.408,"heading":168.2969970703125}}
|
||||
console.log("Received location from Android:", JSON.stringify(l))
|
||||
const loc = l.value
|
||||
writeInto.set({
|
||||
latitude: loc.latitude,
|
||||
longitude: loc.longitude,
|
||||
heading: loc.heading,
|
||||
accuracy: loc.accuraccy,
|
||||
altitude: loc.altidude,
|
||||
altitudeAccuracy: undefined,
|
||||
speed: loc.speed,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -126,6 +126,9 @@ export default class TagRenderingConfig {
|
|||
this.id
|
||||
)
|
||||
}
|
||||
if(json.labels && !Array.isArray( json.labels)){
|
||||
throw (`Invalid labels at ${context}: labels should be a list of strings, but got a ${typeof json.labels}`)
|
||||
}
|
||||
|
||||
this.labels = json.labels ?? []
|
||||
if (typeof json.classes === "string") {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { ariaLabel } from "../../Utils/ariaLabel"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import Backspace from "@babeard/svelte-heroicons/outline/Backspace"
|
||||
import { AndroidPolyfill } from "../../Logic/Web/AndroidPolyfill"
|
||||
|
||||
export let value: UIEventSource<string>
|
||||
let _value = value.data ?? ""
|
||||
|
@ -36,6 +37,7 @@
|
|||
if (autofocus) {
|
||||
isFocused.set(true)
|
||||
}
|
||||
let isAndroid = AndroidPolyfill.inAndroid
|
||||
</script>
|
||||
|
||||
<form class="w-full" on:submit|preventDefault={() => dispatch("search")}>
|
||||
|
@ -62,18 +64,20 @@
|
|||
use:set_placeholder={placeholder}
|
||||
use:ariaLabel={placeholder}
|
||||
/>
|
||||
|
||||
{#if $value.length > 0}
|
||||
<Backspace
|
||||
on:click={(e) => {
|
||||
{#if !isAndroid}
|
||||
<!-- Show a 'clear field' icon in the searchbar. The android-build already provides this for us, hence the outer if -->
|
||||
{#if $value.length > 0}
|
||||
<Backspace
|
||||
on:click={(e) => {
|
||||
value.set("")
|
||||
e.preventDefault()
|
||||
}}
|
||||
color="var(--button-background)"
|
||||
class="mr-3 h-6 w-6 cursor-pointer"
|
||||
/>
|
||||
{:else}
|
||||
<div class="mr-3 w-6" />
|
||||
color="var(--button-background)"
|
||||
class="mr-3 h-6 w-6 cursor-pointer"
|
||||
/>
|
||||
{:else}
|
||||
<div class="mr-3 w-6" />
|
||||
{/if}
|
||||
{/if}
|
||||
</label>
|
||||
</form>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
import Location_locked from "../../assets/svg/Location_locked.svelte"
|
||||
import Location_unlocked from "../../assets/svg/Location_unlocked.svelte"
|
||||
import Location from "../../assets/svg/Location.svelte"
|
||||
import Location_empty from "../../assets/svg/Location_empty.svelte"
|
||||
|
||||
export let state: ThemeViewState
|
||||
let geolocationstate = state.geolocation.geolocationState
|
||||
|
@ -31,10 +32,10 @@
|
|||
{:else if $geopermission === "denied" || !$isAvailable}
|
||||
<Location_refused class={clss} />
|
||||
{:else if $geopermission === "prompt"}
|
||||
<Location class={clss} />
|
||||
<Location_empty class={clss} />
|
||||
{:else if $geopermission === "requested"}
|
||||
<!-- Even though disabled, when clicking we request the location again in case the contributor dismissed the location popup -->
|
||||
<Location class={clss} style="animation: 3s linear 0s infinite normal none running spin;" />
|
||||
<Location_empty class={clss} style="animation: 3s linear 0s infinite normal none running spin;" />
|
||||
{:else}
|
||||
<Location class={clss} style="animation: 3s linear 0s infinite normal none running spin;" />
|
||||
{/if}
|
||||
|
|
|
@ -319,7 +319,7 @@
|
|||
if (state?.osmConnection) {
|
||||
onDestroy(
|
||||
state.osmConnection?.userDetails?.addCallbackAndRun((ud) => {
|
||||
numberOfCs = ud.csCount
|
||||
numberOfCs = ud?.csCount
|
||||
})
|
||||
)
|
||||
}
|
||||
|
|
|
@ -122,7 +122,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" || args[1] === "yes"
|
||||
|
@ -189,7 +189,7 @@ class StealViz implements SpecialVisualization {
|
|||
selectedElement: otherFeature,
|
||||
state,
|
||||
layer,
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
if (elements.length === 1) {
|
||||
|
@ -197,8 +197,8 @@ class StealViz implements SpecialVisualization {
|
|||
}
|
||||
return new Combine(elements).SetClass("flex flex-col")
|
||||
},
|
||||
[state.indexedFeatures.featuresById]
|
||||
)
|
||||
[state.indexedFeatures.featuresById],
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -250,11 +250,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, {
|
||||
|
@ -295,7 +295,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(";")
|
||||
|
@ -327,7 +327,7 @@ export default class SpecialVisualizations {
|
|||
for (const specialVisualization of SpecialVisualizations.specialVisualizations) {
|
||||
SpecialVisualizations.specialVisualisationsDict.set(
|
||||
specialVisualization.funcName,
|
||||
specialVisualization
|
||||
specialVisualization,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -347,15 +347,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>",
|
||||
|
@ -364,18 +364,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([
|
||||
|
@ -408,10 +408,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()
|
||||
|
@ -452,7 +452,7 @@ export default class SpecialVisualizations {
|
|||
(ud) => ud?.languages ?? []
|
||||
),
|
||||
})
|
||||
})
|
||||
}),
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -491,7 +491,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 })
|
||||
},
|
||||
|
@ -503,7 +503,7 @@ export default class SpecialVisualizations {
|
|||
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
): BaseUIElement {
|
||||
return new VariableUiElement(
|
||||
tagSource
|
||||
|
@ -513,7 +513,7 @@ export default class SpecialVisualizations {
|
|||
return new SvelteUIElement(SplitRoadWizard, { id, state })
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
}),
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -527,7 +527,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
|
||||
|
@ -550,7 +550,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
layer: LayerConfig,
|
||||
): BaseUIElement {
|
||||
if (!layer.deletion) {
|
||||
return undefined
|
||||
|
@ -576,7 +576,7 @@ export default class SpecialVisualizations {
|
|||
tags: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
layer: LayerConfig,
|
||||
) {
|
||||
if (feature.geometry.type !== "LineString") {
|
||||
return undefined
|
||||
|
@ -608,7 +608,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, {
|
||||
|
@ -671,7 +671,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(
|
||||
|
@ -681,9 +681,9 @@ export default class SpecialVisualizations {
|
|||
}
|
||||
const response = <WikidataResponse>e["success"]
|
||||
return Translation.fromMap(response.labels)
|
||||
})
|
||||
}),
|
||||
)
|
||||
})
|
||||
}),
|
||||
),
|
||||
},
|
||||
new MapillaryLinkVis(),
|
||||
|
@ -697,7 +697,7 @@ export default class SpecialVisualizations {
|
|||
tags: UIEventSource<Record<string, string>>,
|
||||
_,
|
||||
__,
|
||||
layer: LayerConfig
|
||||
layer: LayerConfig,
|
||||
) => new SvelteUIElement(AllTagsPanel, { tags, layer }),
|
||||
},
|
||||
{
|
||||
|
@ -782,7 +782,7 @@ export default class SpecialVisualizations {
|
|||
nameKey: nameKey,
|
||||
fallbackName,
|
||||
},
|
||||
state.featureSwitchIsTesting
|
||||
state.featureSwitchIsTesting,
|
||||
)
|
||||
return new SvelteUIElement(StarsBarIcon, {
|
||||
score: reviews.average,
|
||||
|
@ -821,7 +821,7 @@ export default class SpecialVisualizations {
|
|||
nameKey: nameKey,
|
||||
fallbackName,
|
||||
},
|
||||
state.featureSwitchIsTesting
|
||||
state.featureSwitchIsTesting,
|
||||
)
|
||||
return new SvelteUIElement(ReviewForm, {
|
||||
reviews,
|
||||
|
@ -859,7 +859,7 @@ export default class SpecialVisualizations {
|
|||
nameKey: nameKey,
|
||||
fallbackName,
|
||||
},
|
||||
state.featureSwitchIsTesting
|
||||
state.featureSwitchIsTesting,
|
||||
)
|
||||
return new SvelteUIElement(AllReviews, { reviews, state, tags, feature, layer })
|
||||
},
|
||||
|
@ -889,7 +889,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
layer: LayerConfig,
|
||||
): BaseUIElement {
|
||||
return new Combine([
|
||||
SpecialVisualizations.specialVisualisationsDict
|
||||
|
@ -914,7 +914,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 })
|
||||
|
@ -971,7 +971,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]
|
||||
|
@ -1008,17 +1008,17 @@ export default class SpecialVisualizations {
|
|||
return undefined
|
||||
}
|
||||
const allUnits: Unit[] = [].concat(
|
||||
...(state?.theme?.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)
|
||||
})
|
||||
}),
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1072,7 +1072,7 @@ export default class SpecialVisualizations {
|
|||
constr: (state) => {
|
||||
return new SubtleButton(
|
||||
new SvelteUIElement(Trash),
|
||||
Translations.t.general.removeLocationHistory
|
||||
Translations.t.general.removeLocationHistory,
|
||||
).onClick(() => {
|
||||
state.historicalUserLocations.features.setData([])
|
||||
state.selectedElement.setData(undefined)
|
||||
|
@ -1113,10 +1113,10 @@ export default class SpecialVisualizations {
|
|||
new SvelteUIElement(NoteCommentElement, {
|
||||
comment,
|
||||
state,
|
||||
})
|
||||
)
|
||||
}),
|
||||
),
|
||||
).SetClass("flex flex-col")
|
||||
})
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -1149,7 +1149,7 @@ export default class SpecialVisualizations {
|
|||
tags: UIEventSource<Record<string, string>>,
|
||||
_: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
layer: LayerConfig,
|
||||
) => {
|
||||
return new SvelteUIElement(FeatureTitle, { state, tags, feature, layer })
|
||||
},
|
||||
|
@ -1167,8 +1167,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(
|
||||
|
@ -1193,7 +1193,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.",
|
||||
|
@ -1207,15 +1207,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" +
|
||||
|
@ -1291,7 +1291,7 @@ export default class SpecialVisualizations {
|
|||
(l) =>
|
||||
l.name !== null &&
|
||||
l.title &&
|
||||
state.perLayer.get(l.id) !== undefined
|
||||
state.perLayer.get(l.id) !== undefined,
|
||||
)
|
||||
.map(
|
||||
(l) => {
|
||||
|
@ -1301,8 +1301,8 @@ export default class SpecialVisualizations {
|
|||
const fsBboxed = new BBoxFeatureSourceForLayer(fs, bbox)
|
||||
return new StatisticsPanel(fsBboxed)
|
||||
},
|
||||
[state.mapProperties.bounds]
|
||||
)
|
||||
[state.mapProperties.bounds],
|
||||
),
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1372,7 +1372,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 === "") {
|
||||
|
@ -1410,7 +1410,7 @@ export default class SpecialVisualizations {
|
|||
},
|
||||
},
|
||||
null,
|
||||
" "
|
||||
" ",
|
||||
) +
|
||||
"\n```",
|
||||
args: [
|
||||
|
@ -1434,7 +1434,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 ?? ""
|
||||
|
@ -1452,7 +1452,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
|
||||
}
|
||||
|
@ -1469,7 +1469,7 @@ export default class SpecialVisualizations {
|
|||
elements.push(subsTr)
|
||||
}
|
||||
return elements
|
||||
})
|
||||
}),
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1489,7 +1489,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) => {
|
||||
|
@ -1501,7 +1501,7 @@ export default class SpecialVisualizations {
|
|||
console.error("Cannot create a translation for", v, "due to", e)
|
||||
return JSON.stringify(v)
|
||||
}
|
||||
})
|
||||
}),
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1521,7 +1521,7 @@ export default class SpecialVisualizations {
|
|||
tags: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
layer: LayerConfig,
|
||||
): BaseUIElement {
|
||||
const key = argument[0]
|
||||
return new SvelteUIElement(FediverseLink, { key, tags, state })
|
||||
|
@ -1543,7 +1543,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
args: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
layer: LayerConfig,
|
||||
): BaseUIElement {
|
||||
return new FixedUiElement("{" + args[0] + "}")
|
||||
},
|
||||
|
@ -1564,7 +1564,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(
|
||||
|
@ -1582,12 +1582,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")
|
||||
}
|
||||
})
|
||||
}),
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1608,7 +1608,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 })
|
||||
|
@ -1624,15 +1624,24 @@ 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
|
||||
const geostate = (<ThemeViewState>(state)).geolocation.geolocationState
|
||||
const tags = geostate.currentGPSLocation.map(
|
||||
(geoloc) => {
|
||||
const tags = { }
|
||||
for (const k in geoloc ?? {}) {
|
||||
tags[k] = geoloc[k]
|
||||
}
|
||||
tags["_permission"] = geostate.permission.data,
|
||||
tags["_request_moment"] = geostate.requestMoment.data
|
||||
return tags
|
||||
},
|
||||
[geostate.permission, geostate.requestMoment]
|
||||
)
|
||||
|
||||
return new Combine([
|
||||
new SvelteUIElement(OrientationDebugPanel, {}),
|
||||
new SvelteUIElement(OrientationDebugPanel, {}), // compass and gyroscope info
|
||||
new SvelteUIElement(AllTagsPanel, {
|
||||
state,
|
||||
tags,
|
||||
|
@ -1651,7 +1660,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,
|
||||
|
@ -1671,7 +1680,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,
|
||||
|
@ -1691,7 +1700,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 })
|
||||
},
|
||||
|
@ -1704,7 +1713,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 })
|
||||
},
|
||||
|
@ -1723,7 +1732,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(
|
||||
|
@ -1734,11 +1743,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]
|
||||
})
|
||||
}),
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1768,7 +1777,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"
|
||||
|
@ -1794,12 +1803,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,
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1837,7 +1846,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"
|
||||
|
@ -1845,7 +1854,7 @@ export default class SpecialVisualizations {
|
|||
const isClosed = (argument[4] ?? "yes") === "yes"
|
||||
|
||||
const countryStore: Store<string | undefined> = tags.mapD(
|
||||
(tags) => tags._country
|
||||
(tags) => tags._country,
|
||||
)
|
||||
const sourceUrl: Store<string | undefined> = tags.mapD((tags) => {
|
||||
if (!tags[key] || tags[key] === "undefined") {
|
||||
|
@ -1867,24 +1876,24 @@ 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
|
||||
console.log(
|
||||
"Got properties from velopark:",
|
||||
properties
|
||||
properties,
|
||||
)
|
||||
return properties
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
throw e
|
||||
}
|
||||
})()
|
||||
})(),
|
||||
)
|
||||
}
|
||||
if (country === undefined) {
|
||||
|
@ -1896,29 +1905,29 @@ 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",
|
||||
)
|
||||
}
|
||||
})()
|
||||
})(),
|
||||
)
|
||||
},
|
||||
[countryStore]
|
||||
[countryStore],
|
||||
)
|
||||
|
||||
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(
|
||||
|
@ -1933,7 +1942,7 @@ export default class SpecialVisualizations {
|
|||
collapsed: isClosed,
|
||||
}),
|
||||
undefined,
|
||||
sourceUrl.map((url) => !!url)
|
||||
sourceUrl.map((url) => !!url),
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -1953,7 +1962,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]
|
||||
|
@ -1975,7 +1984,7 @@ 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.theme.getMatchingLayer(tags)
|
||||
|
@ -2007,7 +2016,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",
|
||||
|
@ -2032,7 +2041,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())
|
||||
|
@ -2055,7 +2064,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 = {
|
||||
|
@ -2095,7 +2104,7 @@ export default class SpecialVisualizations {
|
|||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
layer: LayerConfig,
|
||||
): BaseUIElement {
|
||||
const text = argument[0]
|
||||
return new SubtleButton(undefined, text).onClick(() => {
|
||||
|
@ -2126,7 +2135,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"
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import MetaTagging from "./src/Logic/MetaTagging";
|
|||
import { FixedUiElement } from "./src/UI/Base/FixedUiElement";
|
||||
import { Utils } from "./src/Utils"
|
||||
import Constants from "./src/Models/Constants"
|
||||
import { AndroidPolyfill } from "./src/Logic/Web/AndroidPolyfill"
|
||||
|
||||
function webgl_support() {
|
||||
try {
|
||||
|
|
|
@ -19,5 +19,5 @@
|
|||
"esModuleInterop": true
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "test", "scripts"]
|
||||
"exclude": ["node_modules", "test", "scripts","android","dist","dist-full"]
|
||||
}
|
||||
|
|
|
@ -21,11 +21,21 @@ export default defineConfig({
|
|||
build: {
|
||||
rollupOptions: {
|
||||
input,
|
||||
external:[
|
||||
"android"
|
||||
]
|
||||
},
|
||||
},
|
||||
base: `${ASSET_URL}`,
|
||||
plugins ,
|
||||
server: {
|
||||
port: 1234,
|
||||
watch:{
|
||||
ignored: [
|
||||
"**/android/**",
|
||||
'**/.git/**',
|
||||
'**/dist/**'
|
||||
]
|
||||
}
|
||||
},
|
||||
})
|
||||
|
|
Loading…
Add table
Reference in a new issue