forked from MapComplete/MapComplete
chore: automated housekeeping...
This commit is contained in:
parent
047d741b1d
commit
39a98ed4a1
30 changed files with 1362 additions and 1690 deletions
|
@ -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?
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
||||
|
|
|
@ -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": "無法上傳您的圖片。您是否已連線至網際網路,並允許第三方 API?Brave 瀏覽器或 uMatrix 外掛程式都可能會封鎖它們。",
|
||||
"panoramax": {
|
||||
"title": "為什麼要永久刪除圖片?",
|
||||
"deletionRequested": "報告已經送出,管理員不久會觀看",
|
||||
"otherFreeform": "請指明為何需要移除這一圖片:",
|
||||
"report": {
|
||||
"copyright": "圖片內含有版權內容",
|
||||
"inappropriate": "這圖片不洽當(有裸露、仇恨內容或是並非街景)",
|
||||
"other": "如果是其他原因請指明",
|
||||
"privacy": "圖片顯示私人產權"
|
||||
},
|
||||
"freeform": "還有其他相關資訊嗎?",
|
||||
"placeholder": "請解釋為何這圖片需要刪除",
|
||||
"requestDeletion": "請求刪除圖片"
|
||||
},
|
||||
"unlink": {
|
||||
"button": "解除連結圖片",
|
||||
"explanation": "圖片解除連結之後,這個圖片不會與這個物件一同顯示。但仍會在附近圖片或其他物件時顯示。",
|
||||
"title": "解除連結這一圖片?"
|
||||
},
|
||||
"processing": "伺服器正在處理你的圖片",
|
||||
"selectFile": "從你的裝置選取圖片"
|
||||
"uploadFailed": "無法上傳您的圖片。您是否已連線至網際網路,並允許第三方 API?Brave 瀏覽器或 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": "檢核貢獻者"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 => {
|
||||
const [lon, lat] = note.geometry.coordinates
|
||||
console.log("Got note:", note)
|
||||
this.location.set({ lon, lat })
|
||||
}
|
||||
)
|
||||
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 &&
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
@ -64,8 +64,8 @@ export default class Maproulette {
|
|||
if (code === "Created") {
|
||||
return Maproulette.STATUS_OPEN
|
||||
}
|
||||
const i = maprouletteStatus.findIndex(<any> code)
|
||||
if(i < 0){
|
||||
const i = maprouletteStatus.findIndex(<any>code)
|
||||
if (i < 0) {
|
||||
return undefined
|
||||
}
|
||||
return i
|
||||
|
@ -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 ??= {}
|
||||
|
|
|
@ -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,15 +364,15 @@ export class OsmConnection {
|
|||
method,
|
||||
headers: header,
|
||||
content,
|
||||
path: `/api/0.6/${path}`
|
||||
path: `/api/0.6/${path}`,
|
||||
},
|
||||
function(err, response) {
|
||||
function (err, response) {
|
||||
if (err !== null) {
|
||||
error(err)
|
||||
} 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,17 +499,17 @@ export class OsmConnection {
|
|||
}
|
||||
const extras = {
|
||||
file:
|
||||
"; filename=\"" +
|
||||
'; filename="' +
|
||||
(options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) +
|
||||
'"\r\nContent-Type: application/gpx+xml',
|
||||
}
|
||||
user
|
||||
user
|
||||
const boundary = "987654"
|
||||
|
||||
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,15 +541,15 @@ 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) {
|
||||
function (err) {
|
||||
if (err !== null) {
|
||||
error(err)
|
||||
} else {
|
||||
ok()
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -557,7 +558,7 @@ user
|
|||
* To be called by land.html
|
||||
*/
|
||||
public finishLogin(callback: (previousURL: string) => void) {
|
||||
this.auth.authenticate(function() {
|
||||
this.auth.authenticate(function () {
|
||||
// Fully authed at this point
|
||||
console.log("Authentication successful!")
|
||||
const previousLocation = LocalStorageSource.get("location_before_login")
|
||||
|
@ -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,22 +638,26 @@ 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"}
|
||||
return { api: "online", gpx: "online", database: "online" }
|
||||
}
|
||||
try{
|
||||
|
||||
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"}
|
||||
}
|
||||
return result.api.status
|
||||
}catch (e) {
|
||||
try {
|
||||
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" }
|
||||
}
|
||||
return result.api.status
|
||||
} catch (e) {
|
||||
console.error("Could not fetch capabilities")
|
||||
return { api: "offline", gpx: "offline" , database: "online"}
|
||||
|
||||
return { api: "offline", gpx: "offline", database: "online" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,42 @@
|
|||
import { Utils } from "../../Utils"
|
||||
/** This code is autogenerated - do not edit. Edit ./assets/layers/usersettings/usersettings.json instead */
|
||||
export class ThemeMetaTagging {
|
||||
public static readonly themeName = "usersettings"
|
||||
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(/</g,'<')?.replace(/>/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'
|
||||
}
|
||||
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(/</g, "<")?.replace(/>/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"
|
||||
}
|
||||
}
|
|
@ -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,9 +517,9 @@ 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"){
|
||||
if (property === "schema:photos") {
|
||||
console.log(">> Getting photos")
|
||||
}
|
||||
const results = await new TypedSparql().typedSparql<T, G>(
|
||||
|
@ -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
|
||||
|
@ -605,7 +610,7 @@ export default class LinkedDataLoader {
|
|||
* remove section "key" afterwards
|
||||
* @param key
|
||||
*/
|
||||
function spreadSection(key: string){
|
||||
function spreadSection(key: string) {
|
||||
for (const section in r) {
|
||||
if (section === key) {
|
||||
continue
|
||||
|
@ -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,16 +634,19 @@ 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)
|
||||
}
|
||||
if (Object.keys(r).length == 1) {
|
||||
const key = Object.keys(r)[0]
|
||||
if(key.indexOf("#")>0){
|
||||
if (key.indexOf("#") > 0) {
|
||||
const newKey = key.split("#")[0]
|
||||
r[newKey] = r[key]
|
||||
delete r[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]) {
|
||||
|
@ -754,7 +761,7 @@ export default class LinkedDataLoader {
|
|||
"schema:email": "email",
|
||||
"schema:telephone": "phone",
|
||||
},
|
||||
// "schema:photos": "images",
|
||||
// "schema:photos": "images",
|
||||
"schema:dateModified": "_last_edit_timestamp",
|
||||
}
|
||||
if (includeExtras) {
|
||||
|
@ -796,13 +803,13 @@ 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)
|
||||
if(images){
|
||||
const rawData = await Utils.downloadJsonCached<object>(url, 1000 * 60 * 60)
|
||||
const images = rawData["photos"]?.map((ph) => <string>ph.image)
|
||||
if (images) {
|
||||
unpatched[unpatchedKey].images = new Set<string>(images)
|
||||
}
|
||||
}
|
||||
|
@ -811,7 +818,7 @@ export default class LinkedDataLoader {
|
|||
const patched: Feature[] = []
|
||||
for (let section in unpatched) {
|
||||
const p = LinkedDataLoader.patchVeloparkProperties(unpatched[section])
|
||||
if(Object.keys(unpatched).length === 1 && section.endsWith("#section1")){
|
||||
if (Object.keys(unpatched).length === 1 && section.endsWith("#section1")) {
|
||||
section = section.split("#")[0]
|
||||
}
|
||||
p["ref:velopark"] = [section]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -45,48 +45,48 @@
|
|||
</div>
|
||||
|
||||
<style>
|
||||
.dots-menu {
|
||||
z-index: 50;
|
||||
}
|
||||
.dots-menu {
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
:global(.dots-menu > path) {
|
||||
fill: var(--button-background-hover);
|
||||
transition: fill 350ms linear;
|
||||
cursor: pointer;
|
||||
stroke-width: 0.8;
|
||||
stroke: white;
|
||||
}
|
||||
:global(.dots-menu > path) {
|
||||
fill: var(--button-background-hover);
|
||||
transition: fill 350ms linear;
|
||||
cursor: pointer;
|
||||
stroke-width: 0.8;
|
||||
stroke: white;
|
||||
}
|
||||
|
||||
:global(.dots-menu:hover > path, .dots-menu-opened > path) {
|
||||
fill: var(--interactive-foreground);
|
||||
}
|
||||
:global(.dots-menu:hover > path, .dots-menu-opened > path) {
|
||||
fill: var(--interactive-foreground);
|
||||
}
|
||||
|
||||
.collapsable {
|
||||
max-width: 50rem;
|
||||
max-height: 10rem;
|
||||
transition: max-width 500ms linear, max-height 500ms linear, border 500ms linear;
|
||||
overflow: hidden;
|
||||
flex-wrap: nowrap;
|
||||
text-wrap: none;
|
||||
width: max-content;
|
||||
box-shadow: #ccc;
|
||||
white-space: nowrap;
|
||||
border: 1px solid var(--button-background);
|
||||
background-color: white;
|
||||
}
|
||||
.collapsable {
|
||||
max-width: 50rem;
|
||||
max-height: 10rem;
|
||||
transition: max-width 500ms linear, max-height 500ms linear, border 500ms linear;
|
||||
overflow: hidden;
|
||||
flex-wrap: nowrap;
|
||||
text-wrap: none;
|
||||
width: max-content;
|
||||
box-shadow: #ccc;
|
||||
white-space: nowrap;
|
||||
border: 1px solid var(--button-background);
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.transition-background {
|
||||
transition: background-color 150ms linear;
|
||||
}
|
||||
.transition-background {
|
||||
transition: background-color 150ms linear;
|
||||
}
|
||||
|
||||
.transition-background.collapsed {
|
||||
background-color: #00000000;
|
||||
}
|
||||
.transition-background.collapsed {
|
||||
background-color: #00000000;
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
max-width: 0;
|
||||
max-height: 0;
|
||||
border: 2px solid #00000000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.collapsed {
|
||||
max-width: 0;
|
||||
max-height: 0;
|
||||
border: 2px solid #00000000;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -128,16 +128,18 @@
|
|||
|
||||
{#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
|
||||
{state}
|
||||
imgClass="h-32 shrink-0"
|
||||
image={{ url: image }}
|
||||
previewedImage={state.previewedImage}
|
||||
/>
|
||||
<div class="relative flex w-fit items-center bg-gray-200">
|
||||
<AttributedImage
|
||||
{state}
|
||||
imgClass="h-32 shrink-0"
|
||||
image={{ url: image }}
|
||||
previewedImage={state.previewedImage}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
@ -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, {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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, {
|
||||
comment: "Tags are copied onto " + targetId + " with MapComplete",
|
||||
})
|
||||
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()
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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, {
|
||||
type: "pois",
|
||||
layer: "food",
|
||||
z: 14,
|
||||
x: 8848,
|
||||
y: 5828
|
||||
}))
|
||||
const status = testDownload(
|
||||
Utils.SubstituteKeys(summaryTileServer, {
|
||||
type: "pois",
|
||||
layer: "food",
|
||||
z: 14,
|
||||
x: 8848,
|
||||
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")
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"contributors": [
|
||||
{
|
||||
"commits": 8729,
|
||||
"commits": 8779,
|
||||
"contributor": "Pieter Vander Vennet"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue