chore: automated housekeeping...

This commit is contained in:
Pieter Vander Vennet 2024-12-17 04:23:24 +01:00
parent 047d741b1d
commit 39a98ed4a1
30 changed files with 1362 additions and 1690 deletions

View file

@ -273,7 +273,7 @@ This tagrendering is only visible in the popup if the following condition is met
### max_bolts
The question is `How many bolts do routes in {title()} have at most?`
*The sport climbing routes here have at most {climbing:bolts:max} bolts.<div class='subtle'>This is without relays and indicates how much quickdraws a climber needs</div>* is shown if `climbing:bolts:max` is set
*The sport climbing routes here have at most {climbing:bolts:max} bolts. <div class='subtle'>This is without belay stations and indicates how much quickdraws a climber needs.</div>* is shown if `climbing:bolts:max` is set
### Speed climbing?

View file

@ -80,7 +80,7 @@ The question is `What is the grade of this climbing route according to the frenc
### bolts
The question is `How many bolts does this route have before reaching the anchor?`
*This route has {climbing:bolts} bolts <div class='subtle'>This is without relays and indicates how much quickdraws a climber needs</div>* is shown if `climbing:bolts` is set
*This route has {climbing:bolts} bolts. <div class='subtle'>This is without belay stations and indicates how much quickdraws a climber needs.</div>* is shown if `climbing:bolts` is set
- *This route is not bolted* is shown if with <a href='https://wiki.openstreetmap.org/wiki/Key:climbing:bolted' target='_blank'>climbing:bolted</a>=<a href='https://wiki.openstreetmap.org/wiki/Tag:climbing:bolted%3Dno' target='_blank'>no</a>

View file

@ -426,10 +426,11 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
| max_snap_distance | 5 | The maximum distance that the imported point will be moved to snap onto a way in an already existing layer (in meters). This is previewed to the contributor, similar to the 'add new point'-action of MapComplete |
| note_id | _undefined_ | If given, this key will be read. The corresponding note on OSM will be closed, stating 'imported' |
| maproulette_id | _undefined_ | The property name of the maproulette_id - this is probably `mr_taskId`. If given, the maproulette challenge will be marked as fixed. Only use this if part of a maproulette-layer. |
| to_point | _undefined_ | If set, a feature will be converted to a centerpoint |
#### Example usage of import_button
<code>`{import_button(,,Import this data into OpenStreetMap,./assets/svg/addSmall.svg,,5,,)}`</code>
<code>`{import_button(,,Import this data into OpenStreetMap,./assets/svg/addSmall.svg,,5,,,)}`</code>
### import_way_button

View file

@ -125,7 +125,7 @@ This tagrendering is only visible in the popup if the following condition is met
### uk_addresses_import_button
_This tagrendering has no question and is thus read-only_
*{import_button(address,urpn_count=$urpn_count;ref:GB:uprn=$ref:GB:uprn$,Add this address,./assets/themes/uk_addresses/housenumber_add.svg,,,,)}*
*{import_button(address,urpn_count=$urpn_count;ref:GB:uprn=$ref:GB:uprn$,Add this address,./assets/themes/uk_addresses/housenumber_add.svg,,,,,)}*
### leftover-questions

View file

@ -98,7 +98,7 @@ Maproulette challenge containing velopark data
This layer is loaded from an external source, namely
`https://maproulette.org/api/v2/challenge/view/43282`
`https://maproulette.org/api/v2/challenge/view/50552`
No themes use this layer
@ -176,7 +176,7 @@ This tagrendering is only visible in the popup if the following condition is met
### import_point
_This tagrendering has no question and is thus read-only_
*{import_button(bike_parking_with_velopark_ref bike_parking,amenity=bicycle_parking;ref:velopark=$ref:velopark,Create a new bicycle parking in OSM. This parking will have the link&COMMA you'll be able to copy the attributes in the next step,,,,,mr_taskId)}*
*{import_button(bike_parking_with_velopark_ref bike_parking,amenity=bicycle_parking;ref:velopark=$ref:velopark,Create a new bicycle parking in OSM. This parking will have the link&COMMA you'll be able to copy the attributes in the next step,,,,,mr_taskId,yes)}*
This tagrendering is only visible in the popup if the following condition is met: <a href='https://wiki.openstreetmap.org/wiki/Key:mr_taskStatus' target='_blank'>mr_taskStatus</a>=<a href='https://wiki.openstreetmap.org/wiki/Tag:mr_taskStatus%3DCreated' target='_blank'>Created</a>

View file

@ -35,10 +35,10 @@ This document gives an overview of which URL-parameters can be used to influence
26. [background](#background)
+ [Selecting a category](#selecting-a-category)
+ [Selecting a specific layer](#selecting-a-specific-layer)
27. [z](#z)
28. [lat](#lat)
29. [lon](#lon)
30. [oauth_token](#oauth_token)
27. [oauth_token](#oauth_token)
28. [z](#z)
29. [lat](#lat)
30. [lon](#lon)
31. [layer-public_bookcase](#layer-public_bookcase)
32. [filter-public_bookcase-kid-books](#filter-public_bookcase-kid-books)
33. [filter-public_bookcase-adult-books](#filter-public_bookcase-adult-books)
@ -334,11 +334,19 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src
No default value set
## oauth_token
Used to complete the login
This documentation is defined in the source code at [ThemeViewState.ts](/src/Models/ThemeViewState.ts#L177)
No default value set
## z
The initial/current zoom level
This documentation is defined in the source code at [InitialMapPositioning.ts](/src/Logic/Actors/InitialMapPositioning.ts#L37)
This documentation is defined in the source code at [InitialMapPositioning.ts](/src/Logic/Actors/InitialMapPositioning.ts#L39)
The default value is _1_
@ -346,7 +354,7 @@ The default value is _1_
The initial/current latitude
This documentation is defined in the source code at [InitialMapPositioning.ts](/src/Logic/Actors/InitialMapPositioning.ts#L37)
This documentation is defined in the source code at [InitialMapPositioning.ts](/src/Logic/Actors/InitialMapPositioning.ts#L39)
The default value is _0_
@ -354,18 +362,10 @@ The default value is _0_
The initial/current longitude of the app
This documentation is defined in the source code at [InitialMapPositioning.ts](/src/Logic/Actors/InitialMapPositioning.ts#L37)
This documentation is defined in the source code at [InitialMapPositioning.ts](/src/Logic/Actors/InitialMapPositioning.ts#L39)
The default value is _0_
## oauth_token
Used to complete the login
This documentation is defined in the source code at [ThemeViewState.ts](/src/Models/ThemeViewState.ts#L189)
No default value set
## layer-public_bookcase
Whether or not layer public_bookcase is shown
@ -410,7 +410,7 @@ The default value is _0_
The mode the application starts in, e.g. 'map', 'dashboard' or 'statistics'
This documentation is defined in the source code at [generateDocs.ts](ervdvn/git2/MapComplete/scripts/generateDocs.ts#L436)
This documentation is defined in the source code at [generateDocs.ts](ervdvn/git/MapComplete/scripts/generateDocs.ts#L436)
The default value is _map_

View file

@ -282,11 +282,11 @@
"logout": "登出",
"mappingsAreHidden": "有些選項已經隱藏,搜尋來顯示更多選項。",
"menu": {
"aboutCurrentThemeTitle": "關於地圖",
"aboutMapComplete": "關於 MapComplete",
"filter": "篩選資料",
"aboutCurrentThemeTitle": "關於地圖",
"openHereDifferentApp": "在其他應用程式開啟目前位置",
"moreUtilsTitle": "探索更多",
"openHereDifferentApp": "在其他應用程式開啟目前位置",
"showIntroduction": "顯示指引",
"title": "選單"
},
@ -354,6 +354,12 @@
"skippedMultiple": "你跳過 {skipped} 問題",
"skippedOne": "你跳過一個問題"
},
"questions": {
"disable": "不要再問這個問題",
"disabledIntro": "你關閉一些類型的問題,要再次啟用問題,請在這邊點一下",
"disabledTitle": "關閉問題",
"enable": "針對所有問題啟用"
},
"removeLocationHistory": "刪除位置歷史",
"retry": "重試",
"returnToTheMap": "回到地圖",
@ -362,9 +368,9 @@
"search": {
"error": "有狀況發生了…",
"nothing": "沒有找到…",
"recents": "最近看到的地方",
"search": "搜尋地點",
"searching": "搜尋中…",
"recents": "最近看到的地方"
"searching": "搜尋中…"
},
"searchAnswer": "搜尋選項",
"seeIndex": "查看所有專題地圖的概覽",
@ -494,12 +500,6 @@
"readMore": "閱讀剩下的條目內容",
"searchToShort": "你的搜尋檢索太短了,請輸入長一點的文字",
"searchWikidata": "在 Wikidata 搜尋"
},
"questions": {
"disable": "不要再問這個問題",
"disabledIntro": "你關閉一些類型的問題,要再次啟用問題,請在這邊點一下",
"disabledTitle": "關閉問題",
"enable": "針對所有問題啟用"
}
},
"hotkeyDocumentation": {
@ -536,9 +536,30 @@
"seeNearby": "瀏覽與連結附近圖片",
"title": "附近的街景影像"
},
"panoramax": {
"deletionRequested": "報告已經送出,管理員不久會觀看",
"freeform": "還有其他相關資訊嗎?",
"otherFreeform": "請指明為何需要移除這一圖片:",
"placeholder": "請解釋為何這圖片需要刪除",
"report": {
"copyright": "圖片內含有版權內容",
"inappropriate": "這圖片不洽當(有裸露、仇恨內容或是並非街景)",
"other": "如果是其他原因請指明",
"privacy": "圖片顯示私人產權"
},
"requestDeletion": "請求刪除圖片",
"title": "為什麼要永久刪除圖片?"
},
"pleaseLogin": "請登入以新增圖片",
"processing": "伺服器正在處理你的圖片",
"respectPrivacy": "請別照人像或是車牌,不要上傳 Google 地圖、Google 街景或其他受版權保護的資料來源。",
"selectFile": "從你的裝置選取圖片",
"toBig": "{actual_size} 因此照片太大,請使用最大 {max_size} 的照片",
"unlink": {
"button": "解除連結圖片",
"explanation": "圖片解除連結之後,這個圖片不會與這個物件一同顯示。但仍會在附近圖片或其他物件時顯示。",
"title": "解除連結這一圖片?"
},
"upload": {
"failReasons": "你也許已經失去網路連線",
"failReasonsAdvanced": "另一個方式,請確認瀏覽器與外掛沒有擋掉第三方 API。",
@ -548,36 +569,15 @@
"someFailed": "抱歉,我們無法上傳 {count} 影像",
"uploading": "{count} 影像已經上傳…"
},
"noBlur": "圖片不會模糊化,請不要照人",
"one": {
"done": "你的影像已經成功上傳,謝謝你!",
"failed": "抱歉,我們無法上傳你的影像",
"retrying": "再次上傳你的影像中 …",
"uploading": "你的影像已經上傳了…"
}
},
"noBlur": "圖片不會模糊化,請不要照人"
},
"uploadFailed": "無法上傳您的圖片。您是否已連線至網際網路,並允許第三方 APIBrave 瀏覽器或 uMatrix 外掛程式都可能會封鎖它們。",
"panoramax": {
"title": "為什麼要永久刪除圖片?",
"deletionRequested": "報告已經送出,管理員不久會觀看",
"otherFreeform": "請指明為何需要移除這一圖片:",
"report": {
"copyright": "圖片內含有版權內容",
"inappropriate": "這圖片不洽當(有裸露、仇恨內容或是並非街景)",
"other": "如果是其他原因請指明",
"privacy": "圖片顯示私人產權"
},
"freeform": "還有其他相關資訊嗎?",
"placeholder": "請解釋為何這圖片需要刪除",
"requestDeletion": "請求刪除圖片"
},
"unlink": {
"button": "解除連結圖片",
"explanation": "圖片解除連結之後,這個圖片不會與這個物件一同顯示。但仍會在附近圖片或其他物件時顯示。",
"title": "解除連結這一圖片?"
},
"processing": "伺服器正在處理你的圖片",
"selectFile": "從你的裝置選取圖片"
"uploadFailed": "無法上傳您的圖片。您是否已連線至網際網路,並允許第三方 APIBrave 瀏覽器或 uMatrix 外掛程式都可能會封鎖它們。"
},
"importInspector": {
"title": "檢視與管理匯入註解"
@ -595,6 +595,9 @@
"logIn": "登入來看其他你先前查看的主題",
"title": "MapComplete"
},
"inspector": {
"menu": "檢核貢獻者"
},
"move": {
"cancel": "選擇不同的原因",
"cannotBeMoved": "這個圖徵無法移動。",
@ -669,6 +672,11 @@
"takeImages": "拍攝樹木照片來自動偵測樹木類型",
"tryAgain": "選擇不同物種"
},
"preset_type": {
"question": "這個物件屬於什麼類型?",
"typeDescription": "這是 <b>{title}</b>. <div class='subtle'>{description}</div>",
"typeTitle": "這是 <b>{title}</b>"
},
"privacy": {
"editingIntro": "當你對地圖變動時,這些變動會存在開放街圖並且是公開給所有人。採用 MapComplete 的編輯變動包括以下資料:",
"editingOutro": "請參考<a href='https://wiki.osmfoundation.org/wiki/Privacy_Policy' target='_blank'>OpenStreetMap.org的隱私政策</a>來取得更多資訊。我們也提醒你註冊帳號時能夠採用假名。",
@ -731,6 +739,9 @@
"activateButton": "協助翻譯 MapComplete",
"missing": "{count} 未翻譯字串"
},
"unknown": {
"clear": "清除答案"
},
"userinfo": {
"notLoggedIn": "你已經登出了"
},
@ -810,16 +821,5 @@
"empty": "請輸入一些 Wikidata 項目",
"startsWithQ": "維基數據編號以 Q 開頭後面接數字"
}
},
"preset_type": {
"typeDescription": "這是 <b>{title}</b>. <div class='subtle'>{description}</div>",
"question": "這個物件屬於什麼類型?",
"typeTitle": "這是 <b>{title}</b>"
},
"unknown": {
"clear": "清除答案"
},
"inspector": {
"menu": "檢核貢獻者"
}
}

View file

@ -8,11 +8,13 @@ import { FeatureSource, WritableFeatureSource } from "../FeatureSource/FeatureSo
import { LocalStorageSource } from "../Web/LocalStorageSource"
import { GeoOperations } from "../GeoOperations"
import { OsmTags } from "../../Models/OsmFeature"
import StaticFeatureSource, { WritableStaticFeatureSource } from "../FeatureSource/Sources/StaticFeatureSource"
import StaticFeatureSource, {
WritableStaticFeatureSource,
} from "../FeatureSource/Sources/StaticFeatureSource"
import { MapProperties } from "../../Models/MapProperties"
import { Orientation } from "../../Sensors/Orientation"
"use strict"
;("use strict")
/**
* The geolocation-handler takes a map-location and a geolocation state.
* It'll move the map as appropriate given the state of the geolocation-API

View file

@ -9,7 +9,7 @@ import { Utils } from "../../Utils"
import { GeoLocationState } from "../State/GeoLocationState"
import { OsmConnection } from "../Osm/OsmConnection"
"use strict"
;("use strict")
/**
* This actor is responsible to set the map location.
@ -27,7 +27,11 @@ export default class InitialMapPositioning {
public location: UIEventSource<{ lon: number; lat: number }>
public useTerrain: Store<boolean>
constructor(layoutToUse: ThemeConfig, geolocationState: GeoLocationState, osmConnection: OsmConnection) {
constructor(
layoutToUse: ThemeConfig,
geolocationState: GeoLocationState,
osmConnection: OsmConnection
) {
function localStorageSynced(
key: string,
deflt: number,
@ -49,7 +53,6 @@ export default class InitialMapPositioning {
return src
}
// -- Location control initialization
this.zoom = localStorageSynced(
"z",
@ -94,12 +97,11 @@ export default class InitialMapPositioning {
console.log("Loading note", initialHash)
const noteId = Number(initialHash)
if (osmConnection.isLoggedIn.data) {
osmConnection.getNote(noteId).then(note => {
osmConnection.getNote(noteId).then((note) => {
const [lon, lat] = note.geometry.coordinates
console.log("Got note:", note)
this.location.set({ lon, lat })
}
)
})
}
} else if (
Constants.GeoIpServer &&

View file

@ -2,7 +2,7 @@ import { FeatureSource, WritableFeatureSource } from "../FeatureSource"
import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource"
import { Feature } from "geojson"
"use strict"
;("use strict")
/**
* A simple, read only feature store.
*/
@ -32,7 +32,9 @@ export default class StaticFeatureSource<T extends Feature = Feature> implements
}
}
export class WritableStaticFeatureSource<T extends Feature = Feature> implements WritableFeatureSource<T> {
export class WritableStaticFeatureSource<T extends Feature = Feature>
implements WritableFeatureSource<T>
{
public readonly features: UIEventSource<T[]> = undefined
constructor(features: UIEventSource<T[]> | T[] | { features: T[] } | { features: Store<T[]> }) {
@ -53,6 +55,5 @@ export class WritableStaticFeatureSource<T extends Feature = Feature> implements
} else {
this.features = feats
}
}
}

View file

@ -10,13 +10,13 @@ import {
MultiPolygon,
Point,
Polygon,
Position
Position,
} from "geojson"
import { Tiles } from "../Models/TileRange"
import { Utils } from "../Utils"
import { NearestPointOnLine } from "@turf/nearest-point-on-line"
("use strict")
;("use strict")
export class GeoOperations {
private static readonly _earthRadius = 6378137

View file

@ -190,7 +190,7 @@ export class ImageUploadManager {
}
}
try {
({ key, value, absoluteUrl } = await this._uploader.uploadImage(
;({ key, value, absoluteUrl } = await this._uploader.uploadImage(
blob,
location,
author,
@ -200,7 +200,7 @@ export class ImageUploadManager {
this.increaseCountFor(this._uploadRetried, featureId)
console.error("Could not upload image, trying again:", e)
try {
({ key, value, absoluteUrl } = await this._uploader.uploadImage(
;({ key, value, absoluteUrl } = await this._uploader.uploadImage(
blob,
location,
author,

View file

@ -6,7 +6,8 @@ export interface MaprouletteTask {
description: string
instruction: string
}
export const maprouletteStatus = ["Open",
export const maprouletteStatus = [
"Open",
"Fixed",
"False_positive",
"Skipped",
@ -16,7 +17,7 @@ export const maprouletteStatus = ["Open",
"Disabled",
] as const
export type MaprouletteStatus = typeof maprouletteStatus[number]
export type MaprouletteStatus = (typeof maprouletteStatus)[number]
export default class Maproulette {
public static readonly defaultEndpoint = "https://maproulette.org/api/v2"
@ -30,7 +31,6 @@ export default class Maproulette {
public static readonly STATUS_TOO_HARD = 6
public static readonly STATUS_DISABLED = 9
public static singleton = new Maproulette()
/*
* The API endpoint to use
@ -88,7 +88,7 @@ export default class Maproulette {
tags?: string
requestReview?: boolean
completionResponses?: Record<string, string>
},
}
): Promise<void> {
console.log("Maproulette: setting", `${this.endpoint}/task/${taskId}/${status}`, options)
options ??= {}

View file

@ -42,31 +42,34 @@ export default class UserDetails {
export type OsmServiceState = "online" | "readonly" | "offline" | "unknown" | "unreachable"
interface CapabilityResult {
"version": "0.6" | string,
"generator": "OpenStreetMap server" | string,
"copyright": "OpenStreetMap and contributors" | string,
"attribution": "http://www.openstreetmap.org/copyright" | string,
"license": "http://opendatacommons.org/licenses/odbl/1-0/" | string,
"api": {
"version": { "minimum": "0.6", "maximum": "0.6" },
"area": { "maximum": 0.25 | number },
"note_area": { "maximum": 25 | number },
"tracepoints": { "per_page": 5000 | number },
"waynodes": { "maximum": 2000 | number },
"relationmembers": { "maximum": 32000 | number },
"changesets": { "maximum_elements": 10000 | number,
"default_query_limit": 100 | number,
"maximum_query_limit": 100 |number},
"notes": { "default_query_limit": 100 | number, "maximum_query_limit": 10000 |number},
"timeout": { "seconds": 300 |number},
"status": {
"database": OsmServiceState,
"api": OsmServiceState,
"gpx": OsmServiceState }
},
"policy": {
"imagery": {
"blacklist":{regex: string}[]
version: "0.6" | string
generator: "OpenStreetMap server" | string
copyright: "OpenStreetMap and contributors" | string
attribution: "http://www.openstreetmap.org/copyright" | string
license: "http://opendatacommons.org/licenses/odbl/1-0/" | string
api: {
version: { minimum: "0.6"; maximum: "0.6" }
area: { maximum: 0.25 | number }
note_area: { maximum: 25 | number }
tracepoints: { per_page: 5000 | number }
waynodes: { maximum: 2000 | number }
relationmembers: { maximum: 32000 | number }
changesets: {
maximum_elements: 10000 | number
default_query_limit: 100 | number
maximum_query_limit: 100 | number
}
notes: { default_query_limit: 100 | number; maximum_query_limit: 10000 | number }
timeout: { seconds: 300 | number }
status: {
database: OsmServiceState
api: OsmServiceState
gpx: OsmServiceState
}
}
policy: {
imagery: {
blacklist: { regex: string }[]
}
}
}
@ -76,14 +79,14 @@ export class OsmConnection {
public userDetails: UIEventSource<UserDetails>
public isLoggedIn: Store<boolean>
public gpxServiceIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
"unknown",
"unknown"
)
public apiIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
"unknown",
"unknown"
)
public loadingStatus = new UIEventSource<"not-attempted" | "loading" | "error" | "logged-in">(
"not-attempted",
"not-attempted"
)
public preferencesHandler: OsmPreferences
public readonly _oauth_config: AuthConfig
@ -127,7 +130,7 @@ export class OsmConnection {
this.userDetails = new UIEventSource<UserDetails>(
new UserDetails(this._oauth_config.url),
"userDetails",
"userDetails"
)
if (options.fakeUser) {
const ud = this.userDetails.data
@ -148,7 +151,7 @@ export class OsmConnection {
(user) =>
user.loggedIn &&
(this.apiIsOnline.data === "unknown" || this.apiIsOnline.data === "online"),
[this.apiIsOnline],
[this.apiIsOnline]
)
this.isLoggedIn.addCallback((isLoggedIn) => {
if (this.userDetails.data.loggedIn == false && isLoggedIn == true) {
@ -191,7 +194,7 @@ export class OsmConnection {
defaultValue: string = undefined,
options?: {
prefix?: string
},
}
): UIEventSource<T | undefined> {
const prefix = options?.prefix ?? "mapcomplete-"
return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix)
@ -200,7 +203,7 @@ export class OsmConnection {
public getPreference<T extends string = string>(
key: string,
defaultValue: string = undefined,
prefix: string = "mapcomplete-",
prefix: string = "mapcomplete-"
): UIEventSource<T | undefined> {
return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix)
}
@ -244,12 +247,12 @@ export class OsmConnection {
this.updateAuthObject()
LocalStorageSource.get("location_before_login").setData(
Utils.runningFromConsole ? undefined : window.location.href,
Utils.runningFromConsole ? undefined : window.location.href
)
this.auth.xhr(
{
method: "GET",
path: "/api/0.6/user/details"
path: "/api/0.6/user/details",
},
(err, details: XMLDocument) => {
if (err != null) {
@ -282,13 +285,13 @@ export class OsmConnection {
data.account_created = userInfo.getAttribute("account_created")
data.uid = Number(userInfo.getAttribute("id"))
data.languages = Array.from(
userInfo.getElementsByTagName("languages")[0].getElementsByTagName("lang"),
userInfo.getElementsByTagName("languages")[0].getElementsByTagName("lang")
).map((l) => l.textContent)
data.csCount = Number.parseInt(
userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? "0",
userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? "0"
)
data.tracesCount = Number.parseInt(
userInfo.getElementsByTagName("traces")[0].getAttribute("count") ?? "0",
userInfo.getElementsByTagName("traces")[0].getAttribute("count") ?? "0"
)
data.img = undefined
@ -320,7 +323,7 @@ export class OsmConnection {
action(this.userDetails.data)
}
this._onLoggedIn = []
},
}
)
}
@ -338,7 +341,7 @@ export class OsmConnection {
method: "GET" | "POST" | "PUT" | "DELETE",
header?: Record<string, string>,
content?: string,
allowAnonymous: boolean = false,
allowAnonymous: boolean = false
): Promise<string> {
const connection: osmAuth = this.auth
if (allowAnonymous && !this.auth.authenticated()) {
@ -346,7 +349,7 @@ export class OsmConnection {
`${this.Backend()}/api/0.6/${path}`,
header,
method,
content,
content
)
if (possibleResult["content"]) {
return possibleResult["content"]
@ -361,7 +364,7 @@ export class OsmConnection {
method,
headers: header,
content,
path: `/api/0.6/${path}`
path: `/api/0.6/${path}`,
},
function (err, response) {
if (err !== null) {
@ -369,7 +372,7 @@ export class OsmConnection {
} else {
ok(response)
}
},
}
)
})
}
@ -378,7 +381,7 @@ export class OsmConnection {
path: string,
content?: string,
header?: Record<string, string>,
allowAnonymous: boolean = false,
allowAnonymous: boolean = false
): Promise<T> {
return <T>await this.interact(path, "POST", header, content, allowAnonymous)
}
@ -386,7 +389,7 @@ export class OsmConnection {
public async put<T extends string>(
path: string,
content?: string,
header?: Record<string, string>,
header?: Record<string, string>
): Promise<T> {
return <T>await this.interact(path, "PUT", header, content)
}
@ -394,7 +397,7 @@ export class OsmConnection {
public async get(
path: string,
header?: Record<string, string>,
allowAnonymous: boolean = false,
allowAnonymous: boolean = false
): Promise<string> {
return await this.interact(path, "GET", header, undefined, allowAnonymous)
}
@ -433,7 +436,7 @@ export class OsmConnection {
return new Promise<{ id: number }>((ok) => {
window.setTimeout(
() => ok({ id: Math.floor(Math.random() * 1000) }),
Math.random() * 5000,
Math.random() * 5000
)
})
}
@ -443,9 +446,9 @@ export class OsmConnection {
"notes.json",
content,
{
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
},
true,
true
)
const parsed = JSON.parse(response)
console.log("Got result:", parsed)
@ -455,9 +458,7 @@ export class OsmConnection {
}
public async getNote(id: number): Promise<Feature<Point>> {
return JSON.parse(await this.get(
"notes/" + id + ".json"
))
return JSON.parse(await this.get("notes/" + id + ".json"))
}
public static GpxTrackVisibility = ["private", "public", "trackable", "identifiable"] as const
@ -474,14 +475,14 @@ export class OsmConnection {
* Note: these are called 'tags' on the wiki, but I opted to name them 'labels' instead as they aren't "key=value" tags, but just words.
*/
labels: string[]
},
}
): Promise<{ id: number }> {
if (this._dryRun.data) {
console.warn("Dryrun enabled - not actually uploading GPX ", gpx)
return new Promise<{ id: number }>((ok) => {
window.setTimeout(
() => ok({ id: Math.floor(Math.random() * 1000) }),
Math.random() * 5000,
Math.random() * 5000
)
})
}
@ -490,7 +491,7 @@ export class OsmConnection {
file: gpx,
description: options.description,
tags: options.labels?.join(",") ?? "",
visibility: options.visibility
visibility: options.visibility,
}
if (!contents.description) {
@ -498,7 +499,7 @@ export class OsmConnection {
}
const extras = {
file:
"; filename=\"" +
'; filename="' +
(options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) +
'"\r\nContent-Type: application/gpx+xml',
}
@ -508,7 +509,7 @@ user
let body = ""
for (const key in contents) {
body += "--" + boundary + "\r\n"
body += "Content-Disposition: form-data; name=\"" + key + "\""
body += 'Content-Disposition: form-data; name="' + key + '"'
if (extras[key] !== undefined) {
body += extras[key]
}
@ -519,7 +520,7 @@ user
const response = await this.post("gpx/create", body, {
"Content-Type": "multipart/form-data; boundary=" + boundary,
"Content-Length": "" + body.length
"Content-Length": "" + body.length,
})
const parsed = JSON.parse(response)
console.log("Uploaded GPX track", parsed)
@ -540,7 +541,7 @@ user
{
method: "POST",
path: `/api/0.6/notes/${id}/comment?text=${encodeURIComponent(text)}`
path: `/api/0.6/notes/${id}/comment?text=${encodeURIComponent(text)}`,
},
function (err) {
if (err !== null) {
@ -548,7 +549,7 @@ user
} else {
ok()
}
},
}
)
})
}
@ -578,7 +579,7 @@ user
*/
singlepage: !this._iframeMode,
auto: true,
apiUrl: this._oauth_config.api_url ?? this._oauth_config.url
apiUrl: this._oauth_config.api_url ?? this._oauth_config.url,
})
}
@ -637,13 +638,18 @@ user
return parsed
}
private async FetchCapabilities(): Promise<{ api: OsmServiceState; gpx: OsmServiceState; database: OsmServiceState }> {
private async FetchCapabilities(): Promise<{
api: OsmServiceState
gpx: OsmServiceState
database: OsmServiceState
}> {
if (Utils.runningFromConsole) {
return { api: "online", gpx: "online", database: "online" }
}
try {
const result = await Utils.downloadJson<CapabilityResult>(this.Backend() + "/api/0.6/capabilities.json")
const result = await Utils.downloadJson<CapabilityResult>(
this.Backend() + "/api/0.6/capabilities.json"
)
if (result?.api?.status === undefined) {
console.log("Something went wrong:", result)
return { api: "unreachable", gpx: "unreachable", database: "unreachable" }
@ -652,7 +658,6 @@ user
} catch (e) {
console.error("Could not fetch capabilities")
return { api: "offline", gpx: "offline", database: "online" }
}
}
}

View file

@ -4,11 +4,39 @@ export class ThemeMetaTagging {
public static readonly themeName = "usersettings"
public metaTaggging_for_usersettings(feat: { properties: Record<string, string> }) {
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_md', () => feat.properties._description.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)?.at(1) )
Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/&lt;/g,'<')?.replace(/&gt;/g,'>') ?? '' )
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_a', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.href.match(/mastodon|en.osm.town/) !== null)[0]?.href }) (feat) )
Utils.AddLazyProperty(feat.properties, '_mastodon_link', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.getAttribute("rel")?.indexOf('me') >= 0)[0]?.href})(feat) )
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate', () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a )
feat.properties['__current_backgroun'] = 'initial_value'
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_md", () =>
feat.properties._description
.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)
?.at(1)
)
Utils.AddLazyProperty(
feat.properties,
"_d",
() => feat.properties._description?.replace(/&lt;/g, "<")?.replace(/&gt;/g, ">") ?? ""
)
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_a", () =>
((feat) => {
const e = document.createElement("div")
e.innerHTML = feat.properties._d
return Array.from(e.getElementsByTagName("a")).filter(
(a) => a.href.match(/mastodon|en.osm.town/) !== null
)[0]?.href
})(feat)
)
Utils.AddLazyProperty(feat.properties, "_mastodon_link", () =>
((feat) => {
const e = document.createElement("div")
e.innerHTML = feat.properties._d
return Array.from(e.getElementsByTagName("a")).filter(
(a) => a.getAttribute("rel")?.indexOf("me") >= 0
)[0]?.href
})(feat)
)
Utils.AddLazyProperty(
feat.properties,
"_mastodon_candidate",
() => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a
)
feat.properties["__current_backgroun"] = "initial_value"
}
}

View file

@ -68,7 +68,7 @@ export default class LinkedDataLoader {
coors
.trim()
.split(" ")
.map((n) => Number(n)),
.map((n) => Number(n))
),
],
}
@ -156,7 +156,7 @@ export default class LinkedDataLoader {
}
const compacted = await jsonld.compact(
openingHoursSpecification,
<any>LinkedDataLoader.COMPACTING_CONTEXT_OH,
<any>LinkedDataLoader.COMPACTING_CONTEXT_OH
)
const spec: object = compacted["@graph"]
if (!spec) {
@ -190,12 +190,12 @@ export default class LinkedDataLoader {
const compacted = await jsonld.compact(data, <any>LinkedDataLoader.COMPACTING_CONTEXT)
compacted["opening_hours"] = await LinkedDataLoader.ohToOsmFormat(
compacted["opening_hours"],
compacted["opening_hours"]
)
if (compacted["openingHours"]) {
const ohspec: string[] = <any>compacted["openingHours"]
compacted["opening_hours"] = OH.simplify(
ohspec.map((r) => LinkedDataLoader.ohStringToOsmFormat(r)).join("; "),
ohspec.map((r) => LinkedDataLoader.ohStringToOsmFormat(r)).join("; ")
)
delete compacted["openingHours"]
}
@ -236,7 +236,7 @@ export default class LinkedDataLoader {
static async fetchJsonLd(
url: string,
options?: JsonLdLoaderOptions,
mode?: "fetch-lod" | "fetch-raw" | "proxy",
mode?: "fetch-lod" | "fetch-raw" | "proxy"
): Promise<object> {
mode ??= "fetch-lod"
if (mode === "proxy") {
@ -251,7 +251,7 @@ export default class LinkedDataLoader {
const div = document.createElement("div")
div.innerHTML = htmlContent
const script = Array.from(div.getElementsByTagName("script")).find(
(script) => script.type === "application/ld+json",
(script) => script.type === "application/ld+json"
)
const snippet = JSON.parse(script.textContent)
@ -266,7 +266,7 @@ export default class LinkedDataLoader {
*/
static removeDuplicateData(
externalData: Record<string, string>,
currentData: Record<string, string>,
currentData: Record<string, string>
): Record<string, string> {
const d = { ...externalData }
delete d["@context"]
@ -332,7 +332,7 @@ export default class LinkedDataLoader {
}
private static patchVeloparkProperties(
input: Record<string, Set<string>>,
input: Record<string, Set<string>>
): Record<string, string[]> {
const output: Record<string, string[]> = {}
for (const k in input) {
@ -473,7 +473,7 @@ export default class LinkedDataLoader {
audience,
"for",
input["ref:velopark"],
" assuming yes",
" assuming yes"
)
return "yes"
})
@ -517,7 +517,7 @@ export default class LinkedDataLoader {
private static async fetchVeloparkProperty<T extends string, G extends T>(
url: string,
property: string,
variable?: string,
variable?: string
): Promise<SparqlResult<T, G>> {
if (property === "schema:photos") {
console.log(">> Getting photos")
@ -533,7 +533,7 @@ export default class LinkedDataLoader {
[url],
undefined,
" ?parking a <http://schema.mobivoc.org/BicycleParkingStation>",
"?parking " + property + " " + (variable ?? ""),
"?parking " + property + " " + (variable ?? "")
)
return results
@ -549,7 +549,7 @@ export default class LinkedDataLoader {
private static async fetchVeloparkGraphProperty<T extends string>(
url: string,
property: string,
subExpr?: string,
subExpr?: string
): Promise<SparqlResult<T, "g">> {
const result = await new TypedSparql().typedSparql<T, "g">(
{
@ -563,7 +563,12 @@ export default class LinkedDataLoader {
"g",
" ?parking a <http://schema.mobivoc.org/BicycleParkingStation>",
S.graph("g", "?section " + property + " " + (subExpr ?? ""), "?section a ?type", "BIND(STR(?section) AS ?id)"),
S.graph(
"g",
"?section " + property + " " + (subExpr ?? ""),
"?section a ?type",
"BIND(STR(?section) AS ?id)"
)
)
return result
@ -621,7 +626,6 @@ export default class LinkedDataLoader {
// The other 'sections' need to get those copied! Then, we delete the "default"-section
if (r["default"] !== undefined && Object.keys(r).length > 1) {
spreadSection("default")
}
if (Object.keys(r).length > 1) {
// This result has multiple sections
@ -630,10 +634,13 @@ export default class LinkedDataLoader {
if (Object.keys(r).length > 2) {
console.log("Multiple sections detected: ", JSON.stringify(keys))
}
const shortestKeyLength: number = Math.min(...keys.map(k => k.length))
const key = keys.find(k => k.length === shortestKeyLength)
if (keys.some(k => !k.startsWith(key))) {
throw "Invalid multi-object: the shortest key is not the start of all the others: " + JSON.stringify(keys)
const shortestKeyLength: number = Math.min(...keys.map((k) => k.length))
const key = keys.find((k) => k.length === shortestKeyLength)
if (keys.some((k) => !k.startsWith(key))) {
throw (
"Invalid multi-object: the shortest key is not the start of all the others: " +
JSON.stringify(keys)
)
}
spreadSection(key)
}
@ -652,7 +659,7 @@ export default class LinkedDataLoader {
directUrl: string,
propertiesWithoutGraph: PropertiesSpec<T>,
propertiesInGraph: PropertiesSpec<T>,
extra?: string[],
extra?: string[]
): Promise<SparqlResult<T, string>> {
const allPartialResults: SparqlResult<T, string>[] = []
for (const propertyName in propertiesWithoutGraph) {
@ -662,7 +669,7 @@ export default class LinkedDataLoader {
const result = await this.fetchVeloparkProperty(
directUrl,
propertyName,
"?" + variableName,
"?" + variableName
)
allPartialResults.push(result)
} else {
@ -671,7 +678,7 @@ export default class LinkedDataLoader {
const result = await this.fetchVeloparkProperty(
directUrl,
propertyName,
`[${subProperty} ?${variableName}] `,
`[${subProperty} ?${variableName}] `
)
allPartialResults.push(result)
}
@ -689,7 +696,7 @@ export default class LinkedDataLoader {
const result = await this.fetchVeloparkGraphProperty(
directUrl,
propertyName,
variableName,
variableName
)
allPartialResults.push(result)
}
@ -701,7 +708,7 @@ export default class LinkedDataLoader {
const result = await this.fetchVeloparkGraphProperty(
directUrl,
propertyName,
variableName,
variableName
)
allPartialResults.push(result)
} else {
@ -710,7 +717,7 @@ export default class LinkedDataLoader {
const result = await this.fetchVeloparkGraphProperty(
directUrl,
propertyName,
`[${subProperty} ?${variableName}] `,
`[${subProperty} ?${variableName}] `
)
allPartialResults.push(result)
}
@ -735,7 +742,7 @@ export default class LinkedDataLoader {
*/
public static async fetchVeloparkEntry(
url: string,
includeExtras: boolean = false,
includeExtras: boolean = false
): Promise<Feature[]> {
const cacheKey = includeExtras + url
if (this.veloparkCache[cacheKey]) {
@ -796,12 +803,12 @@ export default class LinkedDataLoader {
withProxyUrl,
optionalPaths,
graphOptionalPaths,
extra,
extra
)
for (const unpatchedKey in unpatched) {
// Dirty hack
const rawData = await Utils.downloadJsonCached<object>(url, 1000 * 60 * 60)
const images = rawData["photos"]?.map(ph => <string> ph.image)
const images = rawData["photos"]?.map((ph) => <string>ph.image)
if (images) {
unpatched[unpatchedKey].images = new Set<string>(images)
}

View file

@ -71,7 +71,10 @@ export default class TypedSparql {
result[key.value].add(value.value)
})
if (graphVariable && result[graphVariable]?.size > 0) {
const id: string = (<string> Array.from(result["id"] ?? [])?.[0] ?? Array.from(result[graphVariable] ?? [])?.[0]) ?? "default"
const id: string =
<string>Array.from(result["id"] ?? [])?.[0] ??
Array.from(result[graphVariable] ?? [])?.[0] ??
"default"
resultAllGraphs[id] = result
} else {
resultAllGraphs["default"] = result

View file

@ -2,7 +2,11 @@ import ThemeConfig from "./ThemeConfig/ThemeConfig"
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
import { Changes } from "../Logic/Osm/Changes"
import { Store, UIEventSource } from "../Logic/UIEventSource"
import { FeatureSource, IndexedFeatureSource, WritableFeatureSource } from "../Logic/FeatureSource/FeatureSource"
import {
FeatureSource,
IndexedFeatureSource,
WritableFeatureSource,
} from "../Logic/FeatureSource/FeatureSource"
import { OsmConnection } from "../Logic/Osm/OsmConnection"
import { ExportableMap, MapProperties } from "./MapProperties"
import LayerState from "../Logic/State/LayerState"
@ -46,7 +50,9 @@ import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter"
import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage"
import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"
import NoElementsInViewDetector, { FeatureViewState } from "../Logic/Actors/NoElementsInViewDetector"
import NoElementsInViewDetector, {
FeatureViewState,
} from "../Logic/Actors/NoElementsInViewDetector"
import FilteredLayer from "./FilteredLayer"
import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector"
import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager"
@ -57,7 +63,7 @@ import { GeolocationControlState } from "../UI/BigComponents/GeolocationControl"
import Zoomcontrol from "../UI/Zoomcontrol"
import {
SummaryTileSource,
SummaryTileSourceRewriter
SummaryTileSourceRewriter,
} from "../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource"
import summaryLayer from "../assets/generated/layers/summary.json"
import last_click_layerconfig from "../assets/generated/layers/last_click.json"
@ -178,7 +184,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
"oauth_token",
undefined,
"Used to complete the login"
)
),
})
const initial = new InitialMapPositioning(layout, geolocationState, this.osmConnection)
this.mapProperties = new MapLibreAdaptor(this.map, initial, { correctClick: 20 })
@ -186,7 +192,6 @@ export default class ThemeViewState implements SpecialVisualizationState {
this.featureSwitchIsTesting = this.featureSwitches.featureSwitchIsTesting
this.featureSwitchUserbadge = this.featureSwitches.featureSwitchEnableLogin
this.userRelatedState = new UserRelatedState(
this.osmConnection,
layout,
@ -783,7 +788,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
const layers = this.theme.layers.filter(
(l) =>
(<string[]><unknown>Constants.priviliged_layers).indexOf(l.id) < 0 &&
(<string[]>(<unknown>Constants.priviliged_layers)).indexOf(l.id) < 0 &&
l.source.geojsonSource === undefined &&
l.doCount
)

View file

@ -128,8 +128,10 @@
{#if $unknownImages.length > 0}
{#if readonly}
<div class="flex w-full space-x-2 overflow-x-auto border border-gray-600 p-1"
style="scroll-snap-type: x proximity; border: 1px solid black">
<div
class="flex w-full space-x-2 overflow-x-auto border border-gray-600 p-1"
style="scroll-snap-type: x proximity; border: 1px solid black"
>
{#each $unknownImages as image (image)}
<div class="relative flex w-fit items-center bg-gray-200">
<AttributedImage

View file

@ -56,10 +56,9 @@ export class PointImportButtonViz implements SpecialVisualization {
state: SpecialVisualizationState,
tagSource: UIEventSource<Record<string, string>>,
argument: string[],
feature: Feature,
feature: Feature
): BaseUIElement {
const to_point_index = this.args.findIndex(arg => arg.name === "to_point")
const to_point_index = this.args.findIndex((arg) => arg.name === "to_point")
const summarizePointArg = argument[to_point_index].toLowerCase()
if (feature.geometry.type !== "Point") {
if (summarizePointArg !== "no" && summarizePointArg !== "false") {
@ -75,7 +74,7 @@ export class PointImportButtonViz implements SpecialVisualization {
<Feature<Point>>feature,
baseArgs,
tagsToApply,
tagSource,
tagSource
)
return new SvelteUIElement(PointImportFlow, {

View file

@ -88,7 +88,11 @@ export class PointImportFlowState extends ImportFlow<PointImportFlowArguments> {
)
} else {
console.log("Marking maproulette task as fixed")
await Maproulette.singleton.closeTask(Number(maproulette_id), Maproulette.STATUS_FIXED, this.state)
await Maproulette.singleton.closeTask(
Number(maproulette_id),
Maproulette.STATUS_FIXED,
this.state
)
originalFeatureTags.data["mr_taskStatus"] = "Fixed"
originalFeatureTags.ping()
}

View file

@ -159,9 +159,14 @@ export default class TagApplyButton implements AutoAction, SpecialVisualization
const maproulette_id = tags.data[maproulette_id_key]
const maproulette_feature = state.indexedFeatures.featuresById.data.get(maproulette_id)
const maproulette_task_id = Number(maproulette_feature.properties.mr_taskId)
await Maproulette.singleton.closeTask(maproulette_task_id, Maproulette.STATUS_FIXED, state, {
await Maproulette.singleton.closeTask(
maproulette_task_id,
Maproulette.STATUS_FIXED,
state,
{
comment: "Tags are copied onto " + targetId + " with MapComplete",
})
}
)
maproulette_feature.properties["mr_taskStatus"] = "Fixed"
state.featureProperties.getStore(maproulette_id).ping()
}

View file

@ -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"
@ -750,7 +754,7 @@ export default class SpecialVisualizations {
feature,
labelText: args[1],
image: args[2],
noBlur: noBlur === "true" || noBlur === "yes"
noBlur: noBlur === "true" || noBlur === "yes",
})
},
},
@ -1862,7 +1866,7 @@ export default class SpecialVisualizations {
})
const externalData: Store<{ success: GeoJsonProperties } | { error: any }> =
sourceUrl.bindD(
url => {
(url) => {
const country = countryStore.data
if (url.startsWith("https://data.velopark.be/")) {
return Stores.FromPromiseWithErr(

View file

@ -206,13 +206,15 @@
{
const summaryTileServer = Constants.VectorTileServer
// "mvt_layer_server": "https://cache.mapcomplete.org/public.{type}_{layer}/{z}/{x}/{y}.pbf",
const status = testDownload(Utils.SubstituteKeys(summaryTileServer, {
const status = testDownload(
Utils.SubstituteKeys(summaryTileServer, {
type: "pois",
layer: "food",
z: 14,
x: 8848,
y: 5828
}))
y: 5828,
})
)
services.push({
name: summaryTileServer,
status: status.mapD((s) => {
@ -221,11 +223,10 @@
}
return "online"
}),
message: new ImmutableStore("See SettingUpPSQL.md to fix")
message: new ImmutableStore("See SettingUpPSQL.md to fix"),
})
}
{
const s = Constants.countryCoderEndpoint
const status = testDownload(s + "/0.0.0.json")

View file

@ -105,11 +105,11 @@
let canZoomIn = mapproperties.maxzoom.map(
(mz) => mapproperties.zoom.data < mz,
[mapproperties.zoom],
[mapproperties.zoom]
)
let canZoomOut = mapproperties.minzoom.map(
(mz) => mapproperties.zoom.data > mz,
[mapproperties.zoom],
[mapproperties.zoom]
)
let rasterLayerName =
@ -118,7 +118,7 @@
onDestroy(
rasterLayer.addCallbackAndRunD((l) => {
rasterLayerName = l.properties.name
}),
})
)
debug.addCallbackAndRun((dbg) => {

View file

@ -1,7 +1,7 @@
{
"contributors": [
{
"commits": 8729,
"commits": 8779,
"contributor": "Pieter Vander Vennet"
},
{

View file

@ -1,5 +1,6 @@
{
"ca": "català",
"cs": "čeština",
"da": "dansk",
"de": "Deutsch",
"en": "English",
@ -23,7 +24,6 @@
"sl": "slovenščina",
"sv": "svenska",
"uk": "українська мова",
"zgh": "ⵜⴰⵎⴰⵣⵉⵖⵜ ⵜⴰⵏⴰⵡⴰⵢⵜ ⵜⴰⵎⵖⵔⵉⴱⵉⵜ",
"zh_Hans": "简体中文",
"zh_Hant": "繁體中文"
}

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@
"contributor": "paunofu"
},
{
"commits": 150,
"commits": 154,
"contributor": "Anonymous"
},
{
@ -49,17 +49,17 @@
"contributor": "gallegonovato"
},
{
"commits": 45,
"contributor": "Babos Gábor"
},
{
"commits": 44,
"commits": 47,
"contributor": "Supaplex"
},
{
"commits": 42,
"commits": 46,
"contributor": "Midgard"
},
{
"commits": 45,
"contributor": "Babos Gábor"
},
{
"commits": 38,
"contributor": "Lucas"
@ -364,6 +364,10 @@
"commits": 4,
"contributor": "Jan Zabel"
},
{
"commits": 3,
"contributor": "Gábor"
},
{
"commits": 3,
"contributor": "Michal Čermák"
@ -448,10 +452,6 @@
"commits": 3,
"contributor": "SiegbjornSitumeang"
},
{
"commits": 2,
"contributor": "Gábor"
},
{
"commits": 2,
"contributor": "Héctor Ochoa Ortiz"