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
|
### max_bolts
|
||||||
|
|
||||||
The question is `How many bolts do routes in {title()} have at most?`
|
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?
|
### Speed climbing?
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ The question is `What is the grade of this climbing route according to the frenc
|
||||||
### bolts
|
### bolts
|
||||||
|
|
||||||
The question is `How many bolts does this route have before reaching the anchor?`
|
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>
|
- *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 |
|
| 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' |
|
| 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. |
|
| 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
|
#### 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
|
### 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
|
### uk_addresses_import_button
|
||||||
|
|
||||||
_This tagrendering has no question and is thus read-only_
|
_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
|
### leftover-questions
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ Maproulette challenge containing velopark data
|
||||||
|
|
||||||
This layer is loaded from an external source, namely
|
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
|
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
|
### import_point
|
||||||
|
|
||||||
_This tagrendering has no question and is thus read-only_
|
_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>
|
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)
|
26. [background](#background)
|
||||||
+ [Selecting a category](#selecting-a-category)
|
+ [Selecting a category](#selecting-a-category)
|
||||||
+ [Selecting a specific layer](#selecting-a-specific-layer)
|
+ [Selecting a specific layer](#selecting-a-specific-layer)
|
||||||
27. [z](#z)
|
27. [oauth_token](#oauth_token)
|
||||||
28. [lat](#lat)
|
28. [z](#z)
|
||||||
29. [lon](#lon)
|
29. [lat](#lat)
|
||||||
30. [oauth_token](#oauth_token)
|
30. [lon](#lon)
|
||||||
31. [layer-public_bookcase](#layer-public_bookcase)
|
31. [layer-public_bookcase](#layer-public_bookcase)
|
||||||
32. [filter-public_bookcase-kid-books](#filter-public_bookcase-kid-books)
|
32. [filter-public_bookcase-kid-books](#filter-public_bookcase-kid-books)
|
||||||
33. [filter-public_bookcase-adult-books](#filter-public_bookcase-adult-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
|
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
|
## z
|
||||||
|
|
||||||
The initial/current zoom level
|
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_
|
The default value is _1_
|
||||||
|
|
||||||
|
@ -346,7 +354,7 @@ The default value is _1_
|
||||||
|
|
||||||
The initial/current latitude
|
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_
|
The default value is _0_
|
||||||
|
|
||||||
|
@ -354,18 +362,10 @@ The default value is _0_
|
||||||
|
|
||||||
The initial/current longitude of the app
|
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_
|
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
|
## layer-public_bookcase
|
||||||
|
|
||||||
Whether or not layer public_bookcase is shown
|
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'
|
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_
|
The default value is _map_
|
||||||
|
|
||||||
|
|
|
@ -282,11 +282,11 @@
|
||||||
"logout": "登出",
|
"logout": "登出",
|
||||||
"mappingsAreHidden": "有些選項已經隱藏,搜尋來顯示更多選項。",
|
"mappingsAreHidden": "有些選項已經隱藏,搜尋來顯示更多選項。",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
"aboutCurrentThemeTitle": "關於地圖",
|
||||||
"aboutMapComplete": "關於 MapComplete",
|
"aboutMapComplete": "關於 MapComplete",
|
||||||
"filter": "篩選資料",
|
"filter": "篩選資料",
|
||||||
"aboutCurrentThemeTitle": "關於地圖",
|
|
||||||
"openHereDifferentApp": "在其他應用程式開啟目前位置",
|
|
||||||
"moreUtilsTitle": "探索更多",
|
"moreUtilsTitle": "探索更多",
|
||||||
|
"openHereDifferentApp": "在其他應用程式開啟目前位置",
|
||||||
"showIntroduction": "顯示指引",
|
"showIntroduction": "顯示指引",
|
||||||
"title": "選單"
|
"title": "選單"
|
||||||
},
|
},
|
||||||
|
@ -354,6 +354,12 @@
|
||||||
"skippedMultiple": "你跳過 {skipped} 問題",
|
"skippedMultiple": "你跳過 {skipped} 問題",
|
||||||
"skippedOne": "你跳過一個問題"
|
"skippedOne": "你跳過一個問題"
|
||||||
},
|
},
|
||||||
|
"questions": {
|
||||||
|
"disable": "不要再問這個問題",
|
||||||
|
"disabledIntro": "你關閉一些類型的問題,要再次啟用問題,請在這邊點一下",
|
||||||
|
"disabledTitle": "關閉問題",
|
||||||
|
"enable": "針對所有問題啟用"
|
||||||
|
},
|
||||||
"removeLocationHistory": "刪除位置歷史",
|
"removeLocationHistory": "刪除位置歷史",
|
||||||
"retry": "重試",
|
"retry": "重試",
|
||||||
"returnToTheMap": "回到地圖",
|
"returnToTheMap": "回到地圖",
|
||||||
|
@ -362,9 +368,9 @@
|
||||||
"search": {
|
"search": {
|
||||||
"error": "有狀況發生了…",
|
"error": "有狀況發生了…",
|
||||||
"nothing": "沒有找到…",
|
"nothing": "沒有找到…",
|
||||||
|
"recents": "最近看到的地方",
|
||||||
"search": "搜尋地點",
|
"search": "搜尋地點",
|
||||||
"searching": "搜尋中…",
|
"searching": "搜尋中…"
|
||||||
"recents": "最近看到的地方"
|
|
||||||
},
|
},
|
||||||
"searchAnswer": "搜尋選項",
|
"searchAnswer": "搜尋選項",
|
||||||
"seeIndex": "查看所有專題地圖的概覽",
|
"seeIndex": "查看所有專題地圖的概覽",
|
||||||
|
@ -494,12 +500,6 @@
|
||||||
"readMore": "閱讀剩下的條目內容",
|
"readMore": "閱讀剩下的條目內容",
|
||||||
"searchToShort": "你的搜尋檢索太短了,請輸入長一點的文字",
|
"searchToShort": "你的搜尋檢索太短了,請輸入長一點的文字",
|
||||||
"searchWikidata": "在 Wikidata 搜尋"
|
"searchWikidata": "在 Wikidata 搜尋"
|
||||||
},
|
|
||||||
"questions": {
|
|
||||||
"disable": "不要再問這個問題",
|
|
||||||
"disabledIntro": "你關閉一些類型的問題,要再次啟用問題,請在這邊點一下",
|
|
||||||
"disabledTitle": "關閉問題",
|
|
||||||
"enable": "針對所有問題啟用"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hotkeyDocumentation": {
|
"hotkeyDocumentation": {
|
||||||
|
@ -536,9 +536,30 @@
|
||||||
"seeNearby": "瀏覽與連結附近圖片",
|
"seeNearby": "瀏覽與連結附近圖片",
|
||||||
"title": "附近的街景影像"
|
"title": "附近的街景影像"
|
||||||
},
|
},
|
||||||
|
"panoramax": {
|
||||||
|
"deletionRequested": "報告已經送出,管理員不久會觀看",
|
||||||
|
"freeform": "還有其他相關資訊嗎?",
|
||||||
|
"otherFreeform": "請指明為何需要移除這一圖片:",
|
||||||
|
"placeholder": "請解釋為何這圖片需要刪除",
|
||||||
|
"report": {
|
||||||
|
"copyright": "圖片內含有版權內容",
|
||||||
|
"inappropriate": "這圖片不洽當(有裸露、仇恨內容或是並非街景)",
|
||||||
|
"other": "如果是其他原因請指明",
|
||||||
|
"privacy": "圖片顯示私人產權"
|
||||||
|
},
|
||||||
|
"requestDeletion": "請求刪除圖片",
|
||||||
|
"title": "為什麼要永久刪除圖片?"
|
||||||
|
},
|
||||||
"pleaseLogin": "請登入以新增圖片",
|
"pleaseLogin": "請登入以新增圖片",
|
||||||
|
"processing": "伺服器正在處理你的圖片",
|
||||||
"respectPrivacy": "請別照人像或是車牌,不要上傳 Google 地圖、Google 街景或其他受版權保護的資料來源。",
|
"respectPrivacy": "請別照人像或是車牌,不要上傳 Google 地圖、Google 街景或其他受版權保護的資料來源。",
|
||||||
|
"selectFile": "從你的裝置選取圖片",
|
||||||
"toBig": "{actual_size} 因此照片太大,請使用最大 {max_size} 的照片",
|
"toBig": "{actual_size} 因此照片太大,請使用最大 {max_size} 的照片",
|
||||||
|
"unlink": {
|
||||||
|
"button": "解除連結圖片",
|
||||||
|
"explanation": "圖片解除連結之後,這個圖片不會與這個物件一同顯示。但仍會在附近圖片或其他物件時顯示。",
|
||||||
|
"title": "解除連結這一圖片?"
|
||||||
|
},
|
||||||
"upload": {
|
"upload": {
|
||||||
"failReasons": "你也許已經失去網路連線",
|
"failReasons": "你也許已經失去網路連線",
|
||||||
"failReasonsAdvanced": "另一個方式,請確認瀏覽器與外掛沒有擋掉第三方 API。",
|
"failReasonsAdvanced": "另一個方式,請確認瀏覽器與外掛沒有擋掉第三方 API。",
|
||||||
|
@ -548,36 +569,15 @@
|
||||||
"someFailed": "抱歉,我們無法上傳 {count} 影像",
|
"someFailed": "抱歉,我們無法上傳 {count} 影像",
|
||||||
"uploading": "{count} 影像已經上傳…"
|
"uploading": "{count} 影像已經上傳…"
|
||||||
},
|
},
|
||||||
|
"noBlur": "圖片不會模糊化,請不要照人",
|
||||||
"one": {
|
"one": {
|
||||||
"done": "你的影像已經成功上傳,謝謝你!",
|
"done": "你的影像已經成功上傳,謝謝你!",
|
||||||
"failed": "抱歉,我們無法上傳你的影像",
|
"failed": "抱歉,我們無法上傳你的影像",
|
||||||
"retrying": "再次上傳你的影像中 …",
|
"retrying": "再次上傳你的影像中 …",
|
||||||
"uploading": "你的影像已經上傳了…"
|
"uploading": "你的影像已經上傳了…"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"noBlur": "圖片不會模糊化,請不要照人"
|
"uploadFailed": "無法上傳您的圖片。您是否已連線至網際網路,並允許第三方 API?Brave 瀏覽器或 uMatrix 外掛程式都可能會封鎖它們。"
|
||||||
},
|
|
||||||
"uploadFailed": "無法上傳您的圖片。您是否已連線至網際網路,並允許第三方 API?Brave 瀏覽器或 uMatrix 外掛程式都可能會封鎖它們。",
|
|
||||||
"panoramax": {
|
|
||||||
"title": "為什麼要永久刪除圖片?",
|
|
||||||
"deletionRequested": "報告已經送出,管理員不久會觀看",
|
|
||||||
"otherFreeform": "請指明為何需要移除這一圖片:",
|
|
||||||
"report": {
|
|
||||||
"copyright": "圖片內含有版權內容",
|
|
||||||
"inappropriate": "這圖片不洽當(有裸露、仇恨內容或是並非街景)",
|
|
||||||
"other": "如果是其他原因請指明",
|
|
||||||
"privacy": "圖片顯示私人產權"
|
|
||||||
},
|
|
||||||
"freeform": "還有其他相關資訊嗎?",
|
|
||||||
"placeholder": "請解釋為何這圖片需要刪除",
|
|
||||||
"requestDeletion": "請求刪除圖片"
|
|
||||||
},
|
|
||||||
"unlink": {
|
|
||||||
"button": "解除連結圖片",
|
|
||||||
"explanation": "圖片解除連結之後,這個圖片不會與這個物件一同顯示。但仍會在附近圖片或其他物件時顯示。",
|
|
||||||
"title": "解除連結這一圖片?"
|
|
||||||
},
|
|
||||||
"processing": "伺服器正在處理你的圖片",
|
|
||||||
"selectFile": "從你的裝置選取圖片"
|
|
||||||
},
|
},
|
||||||
"importInspector": {
|
"importInspector": {
|
||||||
"title": "檢視與管理匯入註解"
|
"title": "檢視與管理匯入註解"
|
||||||
|
@ -595,6 +595,9 @@
|
||||||
"logIn": "登入來看其他你先前查看的主題",
|
"logIn": "登入來看其他你先前查看的主題",
|
||||||
"title": "MapComplete"
|
"title": "MapComplete"
|
||||||
},
|
},
|
||||||
|
"inspector": {
|
||||||
|
"menu": "檢核貢獻者"
|
||||||
|
},
|
||||||
"move": {
|
"move": {
|
||||||
"cancel": "選擇不同的原因",
|
"cancel": "選擇不同的原因",
|
||||||
"cannotBeMoved": "這個圖徵無法移動。",
|
"cannotBeMoved": "這個圖徵無法移動。",
|
||||||
|
@ -669,6 +672,11 @@
|
||||||
"takeImages": "拍攝樹木照片來自動偵測樹木類型",
|
"takeImages": "拍攝樹木照片來自動偵測樹木類型",
|
||||||
"tryAgain": "選擇不同物種"
|
"tryAgain": "選擇不同物種"
|
||||||
},
|
},
|
||||||
|
"preset_type": {
|
||||||
|
"question": "這個物件屬於什麼類型?",
|
||||||
|
"typeDescription": "這是 <b>{title}</b>. <div class='subtle'>{description}</div>",
|
||||||
|
"typeTitle": "這是 <b>{title}</b>"
|
||||||
|
},
|
||||||
"privacy": {
|
"privacy": {
|
||||||
"editingIntro": "當你對地圖變動時,這些變動會存在開放街圖並且是公開給所有人。採用 MapComplete 的編輯變動包括以下資料:",
|
"editingIntro": "當你對地圖變動時,這些變動會存在開放街圖並且是公開給所有人。採用 MapComplete 的編輯變動包括以下資料:",
|
||||||
"editingOutro": "請參考<a href='https://wiki.osmfoundation.org/wiki/Privacy_Policy' target='_blank'>OpenStreetMap.org的隱私政策</a>來取得更多資訊。我們也提醒你註冊帳號時能夠採用假名。",
|
"editingOutro": "請參考<a href='https://wiki.osmfoundation.org/wiki/Privacy_Policy' target='_blank'>OpenStreetMap.org的隱私政策</a>來取得更多資訊。我們也提醒你註冊帳號時能夠採用假名。",
|
||||||
|
@ -731,6 +739,9 @@
|
||||||
"activateButton": "協助翻譯 MapComplete",
|
"activateButton": "協助翻譯 MapComplete",
|
||||||
"missing": "{count} 未翻譯字串"
|
"missing": "{count} 未翻譯字串"
|
||||||
},
|
},
|
||||||
|
"unknown": {
|
||||||
|
"clear": "清除答案"
|
||||||
|
},
|
||||||
"userinfo": {
|
"userinfo": {
|
||||||
"notLoggedIn": "你已經登出了"
|
"notLoggedIn": "你已經登出了"
|
||||||
},
|
},
|
||||||
|
@ -810,16 +821,5 @@
|
||||||
"empty": "請輸入一些 Wikidata 項目",
|
"empty": "請輸入一些 Wikidata 項目",
|
||||||
"startsWithQ": "維基數據編號以 Q 開頭後面接數字"
|
"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 { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||||
import { GeoOperations } from "../GeoOperations"
|
import { GeoOperations } from "../GeoOperations"
|
||||||
import { OsmTags } from "../../Models/OsmFeature"
|
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 { MapProperties } from "../../Models/MapProperties"
|
||||||
import { Orientation } from "../../Sensors/Orientation"
|
import { Orientation } from "../../Sensors/Orientation"
|
||||||
|
|
||||||
"use strict"
|
;("use strict")
|
||||||
/**
|
/**
|
||||||
* The geolocation-handler takes a map-location and a geolocation state.
|
* 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
|
* 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 { GeoLocationState } from "../State/GeoLocationState"
|
||||||
import { OsmConnection } from "../Osm/OsmConnection"
|
import { OsmConnection } from "../Osm/OsmConnection"
|
||||||
|
|
||||||
"use strict"
|
;("use strict")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This actor is responsible to set the map location.
|
* 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 location: UIEventSource<{ lon: number; lat: number }>
|
||||||
public useTerrain: Store<boolean>
|
public useTerrain: Store<boolean>
|
||||||
|
|
||||||
constructor(layoutToUse: ThemeConfig, geolocationState: GeoLocationState, osmConnection: OsmConnection) {
|
constructor(
|
||||||
|
layoutToUse: ThemeConfig,
|
||||||
|
geolocationState: GeoLocationState,
|
||||||
|
osmConnection: OsmConnection
|
||||||
|
) {
|
||||||
function localStorageSynced(
|
function localStorageSynced(
|
||||||
key: string,
|
key: string,
|
||||||
deflt: number,
|
deflt: number,
|
||||||
|
@ -49,7 +53,6 @@ export default class InitialMapPositioning {
|
||||||
return src
|
return src
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -- Location control initialization
|
// -- Location control initialization
|
||||||
this.zoom = localStorageSynced(
|
this.zoom = localStorageSynced(
|
||||||
"z",
|
"z",
|
||||||
|
@ -94,12 +97,11 @@ export default class InitialMapPositioning {
|
||||||
console.log("Loading note", initialHash)
|
console.log("Loading note", initialHash)
|
||||||
const noteId = Number(initialHash)
|
const noteId = Number(initialHash)
|
||||||
if (osmConnection.isLoggedIn.data) {
|
if (osmConnection.isLoggedIn.data) {
|
||||||
osmConnection.getNote(noteId).then(note => {
|
osmConnection.getNote(noteId).then((note) => {
|
||||||
const [lon, lat] = note.geometry.coordinates
|
const [lon, lat] = note.geometry.coordinates
|
||||||
console.log("Got note:", note)
|
console.log("Got note:", note)
|
||||||
this.location.set({ lon, lat })
|
this.location.set({ lon, lat })
|
||||||
}
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
Constants.GeoIpServer &&
|
Constants.GeoIpServer &&
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { FeatureSource, WritableFeatureSource } from "../FeatureSource"
|
||||||
import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource"
|
import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource"
|
||||||
import { Feature } from "geojson"
|
import { Feature } from "geojson"
|
||||||
|
|
||||||
"use strict"
|
;("use strict")
|
||||||
/**
|
/**
|
||||||
* A simple, read only feature store.
|
* 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
|
public readonly features: UIEventSource<T[]> = undefined
|
||||||
|
|
||||||
constructor(features: UIEventSource<T[]> | T[] | { features: T[] } | { features: Store<T[]> }) {
|
constructor(features: UIEventSource<T[]> | T[] | { features: T[] } | { features: Store<T[]> }) {
|
||||||
|
@ -53,6 +55,5 @@ export class WritableStaticFeatureSource<T extends Feature = Feature> implements
|
||||||
} else {
|
} else {
|
||||||
this.features = feats
|
this.features = feats
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,13 @@ import {
|
||||||
MultiPolygon,
|
MultiPolygon,
|
||||||
Point,
|
Point,
|
||||||
Polygon,
|
Polygon,
|
||||||
Position
|
Position,
|
||||||
} from "geojson"
|
} from "geojson"
|
||||||
import { Tiles } from "../Models/TileRange"
|
import { Tiles } from "../Models/TileRange"
|
||||||
import { Utils } from "../Utils"
|
import { Utils } from "../Utils"
|
||||||
import { NearestPointOnLine } from "@turf/nearest-point-on-line"
|
import { NearestPointOnLine } from "@turf/nearest-point-on-line"
|
||||||
|
|
||||||
("use strict")
|
;("use strict")
|
||||||
|
|
||||||
export class GeoOperations {
|
export class GeoOperations {
|
||||||
private static readonly _earthRadius = 6378137
|
private static readonly _earthRadius = 6378137
|
||||||
|
|
|
@ -190,7 +190,7 @@ export class ImageUploadManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
({ key, value, absoluteUrl } = await this._uploader.uploadImage(
|
;({ key, value, absoluteUrl } = await this._uploader.uploadImage(
|
||||||
blob,
|
blob,
|
||||||
location,
|
location,
|
||||||
author,
|
author,
|
||||||
|
@ -200,7 +200,7 @@ export class ImageUploadManager {
|
||||||
this.increaseCountFor(this._uploadRetried, featureId)
|
this.increaseCountFor(this._uploadRetried, featureId)
|
||||||
console.error("Could not upload image, trying again:", e)
|
console.error("Could not upload image, trying again:", e)
|
||||||
try {
|
try {
|
||||||
({ key, value, absoluteUrl } = await this._uploader.uploadImage(
|
;({ key, value, absoluteUrl } = await this._uploader.uploadImage(
|
||||||
blob,
|
blob,
|
||||||
location,
|
location,
|
||||||
author,
|
author,
|
||||||
|
|
|
@ -6,7 +6,8 @@ export interface MaprouletteTask {
|
||||||
description: string
|
description: string
|
||||||
instruction: string
|
instruction: string
|
||||||
}
|
}
|
||||||
export const maprouletteStatus = ["Open",
|
export const maprouletteStatus = [
|
||||||
|
"Open",
|
||||||
"Fixed",
|
"Fixed",
|
||||||
"False_positive",
|
"False_positive",
|
||||||
"Skipped",
|
"Skipped",
|
||||||
|
@ -16,7 +17,7 @@ export const maprouletteStatus = ["Open",
|
||||||
"Disabled",
|
"Disabled",
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export type MaprouletteStatus = typeof maprouletteStatus[number]
|
export type MaprouletteStatus = (typeof maprouletteStatus)[number]
|
||||||
|
|
||||||
export default class Maproulette {
|
export default class Maproulette {
|
||||||
public static readonly defaultEndpoint = "https://maproulette.org/api/v2"
|
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_TOO_HARD = 6
|
||||||
public static readonly STATUS_DISABLED = 9
|
public static readonly STATUS_DISABLED = 9
|
||||||
|
|
||||||
|
|
||||||
public static singleton = new Maproulette()
|
public static singleton = new Maproulette()
|
||||||
/*
|
/*
|
||||||
* The API endpoint to use
|
* The API endpoint to use
|
||||||
|
@ -88,7 +88,7 @@ export default class Maproulette {
|
||||||
tags?: string
|
tags?: string
|
||||||
requestReview?: boolean
|
requestReview?: boolean
|
||||||
completionResponses?: Record<string, string>
|
completionResponses?: Record<string, string>
|
||||||
},
|
}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
console.log("Maproulette: setting", `${this.endpoint}/task/${taskId}/${status}`, options)
|
console.log("Maproulette: setting", `${this.endpoint}/task/${taskId}/${status}`, options)
|
||||||
options ??= {}
|
options ??= {}
|
||||||
|
|
|
@ -42,31 +42,34 @@ export default class UserDetails {
|
||||||
export type OsmServiceState = "online" | "readonly" | "offline" | "unknown" | "unreachable"
|
export type OsmServiceState = "online" | "readonly" | "offline" | "unknown" | "unreachable"
|
||||||
|
|
||||||
interface CapabilityResult {
|
interface CapabilityResult {
|
||||||
"version": "0.6" | string,
|
version: "0.6" | string
|
||||||
"generator": "OpenStreetMap server" | string,
|
generator: "OpenStreetMap server" | string
|
||||||
"copyright": "OpenStreetMap and contributors" | string,
|
copyright: "OpenStreetMap and contributors" | string
|
||||||
"attribution": "http://www.openstreetmap.org/copyright" | string,
|
attribution: "http://www.openstreetmap.org/copyright" | string
|
||||||
"license": "http://opendatacommons.org/licenses/odbl/1-0/" | string,
|
license: "http://opendatacommons.org/licenses/odbl/1-0/" | string
|
||||||
"api": {
|
api: {
|
||||||
"version": { "minimum": "0.6", "maximum": "0.6" },
|
version: { minimum: "0.6"; maximum: "0.6" }
|
||||||
"area": { "maximum": 0.25 | number },
|
area: { maximum: 0.25 | number }
|
||||||
"note_area": { "maximum": 25 | number },
|
note_area: { maximum: 25 | number }
|
||||||
"tracepoints": { "per_page": 5000 | number },
|
tracepoints: { per_page: 5000 | number }
|
||||||
"waynodes": { "maximum": 2000 | number },
|
waynodes: { maximum: 2000 | number }
|
||||||
"relationmembers": { "maximum": 32000 | number },
|
relationmembers: { maximum: 32000 | number }
|
||||||
"changesets": { "maximum_elements": 10000 | number,
|
changesets: {
|
||||||
"default_query_limit": 100 | number,
|
maximum_elements: 10000 | number
|
||||||
"maximum_query_limit": 100 |number},
|
default_query_limit: 100 | number
|
||||||
"notes": { "default_query_limit": 100 | number, "maximum_query_limit": 10000 |number},
|
maximum_query_limit: 100 | number
|
||||||
"timeout": { "seconds": 300 |number},
|
}
|
||||||
"status": {
|
notes: { default_query_limit: 100 | number; maximum_query_limit: 10000 | number }
|
||||||
"database": OsmServiceState,
|
timeout: { seconds: 300 | number }
|
||||||
"api": OsmServiceState,
|
status: {
|
||||||
"gpx": OsmServiceState }
|
database: OsmServiceState
|
||||||
},
|
api: OsmServiceState
|
||||||
"policy": {
|
gpx: OsmServiceState
|
||||||
"imagery": {
|
}
|
||||||
"blacklist":{regex: string}[]
|
}
|
||||||
|
policy: {
|
||||||
|
imagery: {
|
||||||
|
blacklist: { regex: string }[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,14 +79,14 @@ export class OsmConnection {
|
||||||
public userDetails: UIEventSource<UserDetails>
|
public userDetails: UIEventSource<UserDetails>
|
||||||
public isLoggedIn: Store<boolean>
|
public isLoggedIn: Store<boolean>
|
||||||
public gpxServiceIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
|
public gpxServiceIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
|
||||||
"unknown",
|
"unknown"
|
||||||
)
|
)
|
||||||
public apiIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
|
public apiIsOnline: UIEventSource<OsmServiceState> = new UIEventSource<OsmServiceState>(
|
||||||
"unknown",
|
"unknown"
|
||||||
)
|
)
|
||||||
|
|
||||||
public loadingStatus = new UIEventSource<"not-attempted" | "loading" | "error" | "logged-in">(
|
public loadingStatus = new UIEventSource<"not-attempted" | "loading" | "error" | "logged-in">(
|
||||||
"not-attempted",
|
"not-attempted"
|
||||||
)
|
)
|
||||||
public preferencesHandler: OsmPreferences
|
public preferencesHandler: OsmPreferences
|
||||||
public readonly _oauth_config: AuthConfig
|
public readonly _oauth_config: AuthConfig
|
||||||
|
@ -127,7 +130,7 @@ export class OsmConnection {
|
||||||
|
|
||||||
this.userDetails = new UIEventSource<UserDetails>(
|
this.userDetails = new UIEventSource<UserDetails>(
|
||||||
new UserDetails(this._oauth_config.url),
|
new UserDetails(this._oauth_config.url),
|
||||||
"userDetails",
|
"userDetails"
|
||||||
)
|
)
|
||||||
if (options.fakeUser) {
|
if (options.fakeUser) {
|
||||||
const ud = this.userDetails.data
|
const ud = this.userDetails.data
|
||||||
|
@ -148,7 +151,7 @@ export class OsmConnection {
|
||||||
(user) =>
|
(user) =>
|
||||||
user.loggedIn &&
|
user.loggedIn &&
|
||||||
(this.apiIsOnline.data === "unknown" || this.apiIsOnline.data === "online"),
|
(this.apiIsOnline.data === "unknown" || this.apiIsOnline.data === "online"),
|
||||||
[this.apiIsOnline],
|
[this.apiIsOnline]
|
||||||
)
|
)
|
||||||
this.isLoggedIn.addCallback((isLoggedIn) => {
|
this.isLoggedIn.addCallback((isLoggedIn) => {
|
||||||
if (this.userDetails.data.loggedIn == false && isLoggedIn == true) {
|
if (this.userDetails.data.loggedIn == false && isLoggedIn == true) {
|
||||||
|
@ -191,7 +194,7 @@ export class OsmConnection {
|
||||||
defaultValue: string = undefined,
|
defaultValue: string = undefined,
|
||||||
options?: {
|
options?: {
|
||||||
prefix?: string
|
prefix?: string
|
||||||
},
|
}
|
||||||
): UIEventSource<T | undefined> {
|
): UIEventSource<T | undefined> {
|
||||||
const prefix = options?.prefix ?? "mapcomplete-"
|
const prefix = options?.prefix ?? "mapcomplete-"
|
||||||
return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix)
|
return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix)
|
||||||
|
@ -200,7 +203,7 @@ export class OsmConnection {
|
||||||
public getPreference<T extends string = string>(
|
public getPreference<T extends string = string>(
|
||||||
key: string,
|
key: string,
|
||||||
defaultValue: string = undefined,
|
defaultValue: string = undefined,
|
||||||
prefix: string = "mapcomplete-",
|
prefix: string = "mapcomplete-"
|
||||||
): UIEventSource<T | undefined> {
|
): UIEventSource<T | undefined> {
|
||||||
return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix)
|
return <UIEventSource<T>>this.preferencesHandler.getPreference(key, defaultValue, prefix)
|
||||||
}
|
}
|
||||||
|
@ -244,12 +247,12 @@ export class OsmConnection {
|
||||||
this.updateAuthObject()
|
this.updateAuthObject()
|
||||||
|
|
||||||
LocalStorageSource.get("location_before_login").setData(
|
LocalStorageSource.get("location_before_login").setData(
|
||||||
Utils.runningFromConsole ? undefined : window.location.href,
|
Utils.runningFromConsole ? undefined : window.location.href
|
||||||
)
|
)
|
||||||
this.auth.xhr(
|
this.auth.xhr(
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/api/0.6/user/details"
|
path: "/api/0.6/user/details",
|
||||||
},
|
},
|
||||||
(err, details: XMLDocument) => {
|
(err, details: XMLDocument) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
|
@ -282,13 +285,13 @@ export class OsmConnection {
|
||||||
data.account_created = userInfo.getAttribute("account_created")
|
data.account_created = userInfo.getAttribute("account_created")
|
||||||
data.uid = Number(userInfo.getAttribute("id"))
|
data.uid = Number(userInfo.getAttribute("id"))
|
||||||
data.languages = Array.from(
|
data.languages = Array.from(
|
||||||
userInfo.getElementsByTagName("languages")[0].getElementsByTagName("lang"),
|
userInfo.getElementsByTagName("languages")[0].getElementsByTagName("lang")
|
||||||
).map((l) => l.textContent)
|
).map((l) => l.textContent)
|
||||||
data.csCount = Number.parseInt(
|
data.csCount = Number.parseInt(
|
||||||
userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? "0",
|
userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? "0"
|
||||||
)
|
)
|
||||||
data.tracesCount = Number.parseInt(
|
data.tracesCount = Number.parseInt(
|
||||||
userInfo.getElementsByTagName("traces")[0].getAttribute("count") ?? "0",
|
userInfo.getElementsByTagName("traces")[0].getAttribute("count") ?? "0"
|
||||||
)
|
)
|
||||||
|
|
||||||
data.img = undefined
|
data.img = undefined
|
||||||
|
@ -320,7 +323,7 @@ export class OsmConnection {
|
||||||
action(this.userDetails.data)
|
action(this.userDetails.data)
|
||||||
}
|
}
|
||||||
this._onLoggedIn = []
|
this._onLoggedIn = []
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +341,7 @@ export class OsmConnection {
|
||||||
method: "GET" | "POST" | "PUT" | "DELETE",
|
method: "GET" | "POST" | "PUT" | "DELETE",
|
||||||
header?: Record<string, string>,
|
header?: Record<string, string>,
|
||||||
content?: string,
|
content?: string,
|
||||||
allowAnonymous: boolean = false,
|
allowAnonymous: boolean = false
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const connection: osmAuth = this.auth
|
const connection: osmAuth = this.auth
|
||||||
if (allowAnonymous && !this.auth.authenticated()) {
|
if (allowAnonymous && !this.auth.authenticated()) {
|
||||||
|
@ -346,7 +349,7 @@ export class OsmConnection {
|
||||||
`${this.Backend()}/api/0.6/${path}`,
|
`${this.Backend()}/api/0.6/${path}`,
|
||||||
header,
|
header,
|
||||||
method,
|
method,
|
||||||
content,
|
content
|
||||||
)
|
)
|
||||||
if (possibleResult["content"]) {
|
if (possibleResult["content"]) {
|
||||||
return possibleResult["content"]
|
return possibleResult["content"]
|
||||||
|
@ -361,7 +364,7 @@ export class OsmConnection {
|
||||||
method,
|
method,
|
||||||
headers: header,
|
headers: header,
|
||||||
content,
|
content,
|
||||||
path: `/api/0.6/${path}`
|
path: `/api/0.6/${path}`,
|
||||||
},
|
},
|
||||||
function (err, response) {
|
function (err, response) {
|
||||||
if (err !== null) {
|
if (err !== null) {
|
||||||
|
@ -369,7 +372,7 @@ export class OsmConnection {
|
||||||
} else {
|
} else {
|
||||||
ok(response)
|
ok(response)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -378,7 +381,7 @@ export class OsmConnection {
|
||||||
path: string,
|
path: string,
|
||||||
content?: string,
|
content?: string,
|
||||||
header?: Record<string, string>,
|
header?: Record<string, string>,
|
||||||
allowAnonymous: boolean = false,
|
allowAnonymous: boolean = false
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
return <T>await this.interact(path, "POST", header, content, allowAnonymous)
|
return <T>await this.interact(path, "POST", header, content, allowAnonymous)
|
||||||
}
|
}
|
||||||
|
@ -386,7 +389,7 @@ export class OsmConnection {
|
||||||
public async put<T extends string>(
|
public async put<T extends string>(
|
||||||
path: string,
|
path: string,
|
||||||
content?: string,
|
content?: string,
|
||||||
header?: Record<string, string>,
|
header?: Record<string, string>
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
return <T>await this.interact(path, "PUT", header, content)
|
return <T>await this.interact(path, "PUT", header, content)
|
||||||
}
|
}
|
||||||
|
@ -394,7 +397,7 @@ export class OsmConnection {
|
||||||
public async get(
|
public async get(
|
||||||
path: string,
|
path: string,
|
||||||
header?: Record<string, string>,
|
header?: Record<string, string>,
|
||||||
allowAnonymous: boolean = false,
|
allowAnonymous: boolean = false
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
return await this.interact(path, "GET", header, undefined, allowAnonymous)
|
return await this.interact(path, "GET", header, undefined, allowAnonymous)
|
||||||
}
|
}
|
||||||
|
@ -433,7 +436,7 @@ export class OsmConnection {
|
||||||
return new Promise<{ id: number }>((ok) => {
|
return new Promise<{ id: number }>((ok) => {
|
||||||
window.setTimeout(
|
window.setTimeout(
|
||||||
() => ok({ id: Math.floor(Math.random() * 1000) }),
|
() => ok({ id: Math.floor(Math.random() * 1000) }),
|
||||||
Math.random() * 5000,
|
Math.random() * 5000
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -443,9 +446,9 @@ export class OsmConnection {
|
||||||
"notes.json",
|
"notes.json",
|
||||||
content,
|
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)
|
const parsed = JSON.parse(response)
|
||||||
console.log("Got result:", parsed)
|
console.log("Got result:", parsed)
|
||||||
|
@ -455,9 +458,7 @@ export class OsmConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getNote(id: number): Promise<Feature<Point>> {
|
public async getNote(id: number): Promise<Feature<Point>> {
|
||||||
return JSON.parse(await this.get(
|
return JSON.parse(await this.get("notes/" + id + ".json"))
|
||||||
"notes/" + id + ".json"
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GpxTrackVisibility = ["private", "public", "trackable", "identifiable"] as const
|
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.
|
* 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[]
|
labels: string[]
|
||||||
},
|
}
|
||||||
): Promise<{ id: number }> {
|
): Promise<{ id: number }> {
|
||||||
if (this._dryRun.data) {
|
if (this._dryRun.data) {
|
||||||
console.warn("Dryrun enabled - not actually uploading GPX ", gpx)
|
console.warn("Dryrun enabled - not actually uploading GPX ", gpx)
|
||||||
return new Promise<{ id: number }>((ok) => {
|
return new Promise<{ id: number }>((ok) => {
|
||||||
window.setTimeout(
|
window.setTimeout(
|
||||||
() => ok({ id: Math.floor(Math.random() * 1000) }),
|
() => ok({ id: Math.floor(Math.random() * 1000) }),
|
||||||
Math.random() * 5000,
|
Math.random() * 5000
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -490,7 +491,7 @@ export class OsmConnection {
|
||||||
file: gpx,
|
file: gpx,
|
||||||
description: options.description,
|
description: options.description,
|
||||||
tags: options.labels?.join(",") ?? "",
|
tags: options.labels?.join(",") ?? "",
|
||||||
visibility: options.visibility
|
visibility: options.visibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!contents.description) {
|
if (!contents.description) {
|
||||||
|
@ -498,7 +499,7 @@ export class OsmConnection {
|
||||||
}
|
}
|
||||||
const extras = {
|
const extras = {
|
||||||
file:
|
file:
|
||||||
"; filename=\"" +
|
'; filename="' +
|
||||||
(options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) +
|
(options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) +
|
||||||
'"\r\nContent-Type: application/gpx+xml',
|
'"\r\nContent-Type: application/gpx+xml',
|
||||||
}
|
}
|
||||||
|
@ -508,7 +509,7 @@ user
|
||||||
let body = ""
|
let body = ""
|
||||||
for (const key in contents) {
|
for (const key in contents) {
|
||||||
body += "--" + boundary + "\r\n"
|
body += "--" + boundary + "\r\n"
|
||||||
body += "Content-Disposition: form-data; name=\"" + key + "\""
|
body += 'Content-Disposition: form-data; name="' + key + '"'
|
||||||
if (extras[key] !== undefined) {
|
if (extras[key] !== undefined) {
|
||||||
body += extras[key]
|
body += extras[key]
|
||||||
}
|
}
|
||||||
|
@ -519,7 +520,7 @@ user
|
||||||
|
|
||||||
const response = await this.post("gpx/create", body, {
|
const response = await this.post("gpx/create", body, {
|
||||||
"Content-Type": "multipart/form-data; boundary=" + boundary,
|
"Content-Type": "multipart/form-data; boundary=" + boundary,
|
||||||
"Content-Length": "" + body.length
|
"Content-Length": "" + body.length,
|
||||||
})
|
})
|
||||||
const parsed = JSON.parse(response)
|
const parsed = JSON.parse(response)
|
||||||
console.log("Uploaded GPX track", parsed)
|
console.log("Uploaded GPX track", parsed)
|
||||||
|
@ -540,7 +541,7 @@ user
|
||||||
{
|
{
|
||||||
method: "POST",
|
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) {
|
if (err !== null) {
|
||||||
|
@ -548,7 +549,7 @@ user
|
||||||
} else {
|
} else {
|
||||||
ok()
|
ok()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -578,7 +579,7 @@ user
|
||||||
*/
|
*/
|
||||||
singlepage: !this._iframeMode,
|
singlepage: !this._iframeMode,
|
||||||
auto: true,
|
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
|
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) {
|
if (Utils.runningFromConsole) {
|
||||||
return { api: "online", gpx: "online", database: "online" }
|
return { api: "online", gpx: "online", database: "online" }
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
const result = await Utils.downloadJson<CapabilityResult>(
|
||||||
const result = await Utils.downloadJson<CapabilityResult>(this.Backend() + "/api/0.6/capabilities.json")
|
this.Backend() + "/api/0.6/capabilities.json"
|
||||||
|
)
|
||||||
if (result?.api?.status === undefined) {
|
if (result?.api?.status === undefined) {
|
||||||
console.log("Something went wrong:", result)
|
console.log("Something went wrong:", result)
|
||||||
return { api: "unreachable", gpx: "unreachable", database: "unreachable" }
|
return { api: "unreachable", gpx: "unreachable", database: "unreachable" }
|
||||||
|
@ -652,7 +658,6 @@ user
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Could not fetch capabilities")
|
console.error("Could not fetch capabilities")
|
||||||
return { api: "offline", gpx: "offline", database: "online" }
|
return { api: "offline", gpx: "offline", database: "online" }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,39 @@ export class ThemeMetaTagging {
|
||||||
public static readonly themeName = "usersettings"
|
public static readonly themeName = "usersettings"
|
||||||
|
|
||||||
public metaTaggging_for_usersettings(feat: { properties: Record<string, string> }) {
|
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, "_mastodon_candidate_md", () =>
|
||||||
Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/</g,'<')?.replace(/>/g,'>') ?? '' )
|
feat.properties._description
|
||||||
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) )
|
.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)
|
||||||
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) )
|
?.at(1)
|
||||||
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,
|
||||||
|
"_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
|
coors
|
||||||
.trim()
|
.trim()
|
||||||
.split(" ")
|
.split(" ")
|
||||||
.map((n) => Number(n)),
|
.map((n) => Number(n))
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ export default class LinkedDataLoader {
|
||||||
}
|
}
|
||||||
const compacted = await jsonld.compact(
|
const compacted = await jsonld.compact(
|
||||||
openingHoursSpecification,
|
openingHoursSpecification,
|
||||||
<any>LinkedDataLoader.COMPACTING_CONTEXT_OH,
|
<any>LinkedDataLoader.COMPACTING_CONTEXT_OH
|
||||||
)
|
)
|
||||||
const spec: object = compacted["@graph"]
|
const spec: object = compacted["@graph"]
|
||||||
if (!spec) {
|
if (!spec) {
|
||||||
|
@ -190,12 +190,12 @@ export default class LinkedDataLoader {
|
||||||
const compacted = await jsonld.compact(data, <any>LinkedDataLoader.COMPACTING_CONTEXT)
|
const compacted = await jsonld.compact(data, <any>LinkedDataLoader.COMPACTING_CONTEXT)
|
||||||
|
|
||||||
compacted["opening_hours"] = await LinkedDataLoader.ohToOsmFormat(
|
compacted["opening_hours"] = await LinkedDataLoader.ohToOsmFormat(
|
||||||
compacted["opening_hours"],
|
compacted["opening_hours"]
|
||||||
)
|
)
|
||||||
if (compacted["openingHours"]) {
|
if (compacted["openingHours"]) {
|
||||||
const ohspec: string[] = <any>compacted["openingHours"]
|
const ohspec: string[] = <any>compacted["openingHours"]
|
||||||
compacted["opening_hours"] = OH.simplify(
|
compacted["opening_hours"] = OH.simplify(
|
||||||
ohspec.map((r) => LinkedDataLoader.ohStringToOsmFormat(r)).join("; "),
|
ohspec.map((r) => LinkedDataLoader.ohStringToOsmFormat(r)).join("; ")
|
||||||
)
|
)
|
||||||
delete compacted["openingHours"]
|
delete compacted["openingHours"]
|
||||||
}
|
}
|
||||||
|
@ -236,7 +236,7 @@ export default class LinkedDataLoader {
|
||||||
static async fetchJsonLd(
|
static async fetchJsonLd(
|
||||||
url: string,
|
url: string,
|
||||||
options?: JsonLdLoaderOptions,
|
options?: JsonLdLoaderOptions,
|
||||||
mode?: "fetch-lod" | "fetch-raw" | "proxy",
|
mode?: "fetch-lod" | "fetch-raw" | "proxy"
|
||||||
): Promise<object> {
|
): Promise<object> {
|
||||||
mode ??= "fetch-lod"
|
mode ??= "fetch-lod"
|
||||||
if (mode === "proxy") {
|
if (mode === "proxy") {
|
||||||
|
@ -251,7 +251,7 @@ export default class LinkedDataLoader {
|
||||||
const div = document.createElement("div")
|
const div = document.createElement("div")
|
||||||
div.innerHTML = htmlContent
|
div.innerHTML = htmlContent
|
||||||
const script = Array.from(div.getElementsByTagName("script")).find(
|
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)
|
const snippet = JSON.parse(script.textContent)
|
||||||
|
@ -266,7 +266,7 @@ export default class LinkedDataLoader {
|
||||||
*/
|
*/
|
||||||
static removeDuplicateData(
|
static removeDuplicateData(
|
||||||
externalData: Record<string, string>,
|
externalData: Record<string, string>,
|
||||||
currentData: Record<string, string>,
|
currentData: Record<string, string>
|
||||||
): Record<string, string> {
|
): Record<string, string> {
|
||||||
const d = { ...externalData }
|
const d = { ...externalData }
|
||||||
delete d["@context"]
|
delete d["@context"]
|
||||||
|
@ -332,7 +332,7 @@ export default class LinkedDataLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static patchVeloparkProperties(
|
private static patchVeloparkProperties(
|
||||||
input: Record<string, Set<string>>,
|
input: Record<string, Set<string>>
|
||||||
): Record<string, string[]> {
|
): Record<string, string[]> {
|
||||||
const output: Record<string, string[]> = {}
|
const output: Record<string, string[]> = {}
|
||||||
for (const k in input) {
|
for (const k in input) {
|
||||||
|
@ -473,7 +473,7 @@ export default class LinkedDataLoader {
|
||||||
audience,
|
audience,
|
||||||
"for",
|
"for",
|
||||||
input["ref:velopark"],
|
input["ref:velopark"],
|
||||||
" assuming yes",
|
" assuming yes"
|
||||||
)
|
)
|
||||||
return "yes"
|
return "yes"
|
||||||
})
|
})
|
||||||
|
@ -517,7 +517,7 @@ export default class LinkedDataLoader {
|
||||||
private static async fetchVeloparkProperty<T extends string, G extends T>(
|
private static async fetchVeloparkProperty<T extends string, G extends T>(
|
||||||
url: string,
|
url: string,
|
||||||
property: string,
|
property: string,
|
||||||
variable?: string,
|
variable?: string
|
||||||
): Promise<SparqlResult<T, G>> {
|
): Promise<SparqlResult<T, G>> {
|
||||||
if (property === "schema:photos") {
|
if (property === "schema:photos") {
|
||||||
console.log(">> Getting photos")
|
console.log(">> Getting photos")
|
||||||
|
@ -533,7 +533,7 @@ export default class LinkedDataLoader {
|
||||||
[url],
|
[url],
|
||||||
undefined,
|
undefined,
|
||||||
" ?parking a <http://schema.mobivoc.org/BicycleParkingStation>",
|
" ?parking a <http://schema.mobivoc.org/BicycleParkingStation>",
|
||||||
"?parking " + property + " " + (variable ?? ""),
|
"?parking " + property + " " + (variable ?? "")
|
||||||
)
|
)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
@ -549,7 +549,7 @@ export default class LinkedDataLoader {
|
||||||
private static async fetchVeloparkGraphProperty<T extends string>(
|
private static async fetchVeloparkGraphProperty<T extends string>(
|
||||||
url: string,
|
url: string,
|
||||||
property: string,
|
property: string,
|
||||||
subExpr?: string,
|
subExpr?: string
|
||||||
): Promise<SparqlResult<T, "g">> {
|
): Promise<SparqlResult<T, "g">> {
|
||||||
const result = await new TypedSparql().typedSparql<T, "g">(
|
const result = await new TypedSparql().typedSparql<T, "g">(
|
||||||
{
|
{
|
||||||
|
@ -563,7 +563,12 @@ export default class LinkedDataLoader {
|
||||||
"g",
|
"g",
|
||||||
" ?parking a <http://schema.mobivoc.org/BicycleParkingStation>",
|
" ?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
|
return result
|
||||||
|
@ -621,7 +626,6 @@ export default class LinkedDataLoader {
|
||||||
// The other 'sections' need to get those copied! Then, we delete the "default"-section
|
// The other 'sections' need to get those copied! Then, we delete the "default"-section
|
||||||
if (r["default"] !== undefined && Object.keys(r).length > 1) {
|
if (r["default"] !== undefined && Object.keys(r).length > 1) {
|
||||||
spreadSection("default")
|
spreadSection("default")
|
||||||
|
|
||||||
}
|
}
|
||||||
if (Object.keys(r).length > 1) {
|
if (Object.keys(r).length > 1) {
|
||||||
// This result has multiple sections
|
// This result has multiple sections
|
||||||
|
@ -630,10 +634,13 @@ export default class LinkedDataLoader {
|
||||||
if (Object.keys(r).length > 2) {
|
if (Object.keys(r).length > 2) {
|
||||||
console.log("Multiple sections detected: ", JSON.stringify(keys))
|
console.log("Multiple sections detected: ", JSON.stringify(keys))
|
||||||
}
|
}
|
||||||
const shortestKeyLength: number = Math.min(...keys.map(k => k.length))
|
const shortestKeyLength: number = Math.min(...keys.map((k) => k.length))
|
||||||
const key = keys.find(k => k.length === shortestKeyLength)
|
const key = keys.find((k) => k.length === shortestKeyLength)
|
||||||
if (keys.some(k => !k.startsWith(key))) {
|
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)
|
throw (
|
||||||
|
"Invalid multi-object: the shortest key is not the start of all the others: " +
|
||||||
|
JSON.stringify(keys)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
spreadSection(key)
|
spreadSection(key)
|
||||||
}
|
}
|
||||||
|
@ -652,7 +659,7 @@ export default class LinkedDataLoader {
|
||||||
directUrl: string,
|
directUrl: string,
|
||||||
propertiesWithoutGraph: PropertiesSpec<T>,
|
propertiesWithoutGraph: PropertiesSpec<T>,
|
||||||
propertiesInGraph: PropertiesSpec<T>,
|
propertiesInGraph: PropertiesSpec<T>,
|
||||||
extra?: string[],
|
extra?: string[]
|
||||||
): Promise<SparqlResult<T, string>> {
|
): Promise<SparqlResult<T, string>> {
|
||||||
const allPartialResults: SparqlResult<T, string>[] = []
|
const allPartialResults: SparqlResult<T, string>[] = []
|
||||||
for (const propertyName in propertiesWithoutGraph) {
|
for (const propertyName in propertiesWithoutGraph) {
|
||||||
|
@ -662,7 +669,7 @@ export default class LinkedDataLoader {
|
||||||
const result = await this.fetchVeloparkProperty(
|
const result = await this.fetchVeloparkProperty(
|
||||||
directUrl,
|
directUrl,
|
||||||
propertyName,
|
propertyName,
|
||||||
"?" + variableName,
|
"?" + variableName
|
||||||
)
|
)
|
||||||
allPartialResults.push(result)
|
allPartialResults.push(result)
|
||||||
} else {
|
} else {
|
||||||
|
@ -671,7 +678,7 @@ export default class LinkedDataLoader {
|
||||||
const result = await this.fetchVeloparkProperty(
|
const result = await this.fetchVeloparkProperty(
|
||||||
directUrl,
|
directUrl,
|
||||||
propertyName,
|
propertyName,
|
||||||
`[${subProperty} ?${variableName}] `,
|
`[${subProperty} ?${variableName}] `
|
||||||
)
|
)
|
||||||
allPartialResults.push(result)
|
allPartialResults.push(result)
|
||||||
}
|
}
|
||||||
|
@ -689,7 +696,7 @@ export default class LinkedDataLoader {
|
||||||
const result = await this.fetchVeloparkGraphProperty(
|
const result = await this.fetchVeloparkGraphProperty(
|
||||||
directUrl,
|
directUrl,
|
||||||
propertyName,
|
propertyName,
|
||||||
variableName,
|
variableName
|
||||||
)
|
)
|
||||||
allPartialResults.push(result)
|
allPartialResults.push(result)
|
||||||
}
|
}
|
||||||
|
@ -701,7 +708,7 @@ export default class LinkedDataLoader {
|
||||||
const result = await this.fetchVeloparkGraphProperty(
|
const result = await this.fetchVeloparkGraphProperty(
|
||||||
directUrl,
|
directUrl,
|
||||||
propertyName,
|
propertyName,
|
||||||
variableName,
|
variableName
|
||||||
)
|
)
|
||||||
allPartialResults.push(result)
|
allPartialResults.push(result)
|
||||||
} else {
|
} else {
|
||||||
|
@ -710,7 +717,7 @@ export default class LinkedDataLoader {
|
||||||
const result = await this.fetchVeloparkGraphProperty(
|
const result = await this.fetchVeloparkGraphProperty(
|
||||||
directUrl,
|
directUrl,
|
||||||
propertyName,
|
propertyName,
|
||||||
`[${subProperty} ?${variableName}] `,
|
`[${subProperty} ?${variableName}] `
|
||||||
)
|
)
|
||||||
allPartialResults.push(result)
|
allPartialResults.push(result)
|
||||||
}
|
}
|
||||||
|
@ -735,7 +742,7 @@ export default class LinkedDataLoader {
|
||||||
*/
|
*/
|
||||||
public static async fetchVeloparkEntry(
|
public static async fetchVeloparkEntry(
|
||||||
url: string,
|
url: string,
|
||||||
includeExtras: boolean = false,
|
includeExtras: boolean = false
|
||||||
): Promise<Feature[]> {
|
): Promise<Feature[]> {
|
||||||
const cacheKey = includeExtras + url
|
const cacheKey = includeExtras + url
|
||||||
if (this.veloparkCache[cacheKey]) {
|
if (this.veloparkCache[cacheKey]) {
|
||||||
|
@ -796,12 +803,12 @@ export default class LinkedDataLoader {
|
||||||
withProxyUrl,
|
withProxyUrl,
|
||||||
optionalPaths,
|
optionalPaths,
|
||||||
graphOptionalPaths,
|
graphOptionalPaths,
|
||||||
extra,
|
extra
|
||||||
)
|
)
|
||||||
for (const unpatchedKey in unpatched) {
|
for (const unpatchedKey in unpatched) {
|
||||||
// Dirty hack
|
// Dirty hack
|
||||||
const rawData = await Utils.downloadJsonCached<object>(url, 1000 * 60 * 60)
|
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) {
|
if (images) {
|
||||||
unpatched[unpatchedKey].images = new Set<string>(images)
|
unpatched[unpatchedKey].images = new Set<string>(images)
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,10 @@ export default class TypedSparql {
|
||||||
result[key.value].add(value.value)
|
result[key.value].add(value.value)
|
||||||
})
|
})
|
||||||
if (graphVariable && result[graphVariable]?.size > 0) {
|
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
|
resultAllGraphs[id] = result
|
||||||
} else {
|
} else {
|
||||||
resultAllGraphs["default"] = result
|
resultAllGraphs["default"] = result
|
||||||
|
|
|
@ -2,7 +2,11 @@ import ThemeConfig from "./ThemeConfig/ThemeConfig"
|
||||||
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
|
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
|
||||||
import { Changes } from "../Logic/Osm/Changes"
|
import { Changes } from "../Logic/Osm/Changes"
|
||||||
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
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 { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||||
import { ExportableMap, MapProperties } from "./MapProperties"
|
import { ExportableMap, MapProperties } from "./MapProperties"
|
||||||
import LayerState from "../Logic/State/LayerState"
|
import LayerState from "../Logic/State/LayerState"
|
||||||
|
@ -46,7 +50,9 @@ import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter"
|
||||||
import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage"
|
import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage"
|
||||||
import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
|
import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
|
||||||
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"
|
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 FilteredLayer from "./FilteredLayer"
|
||||||
import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector"
|
import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector"
|
||||||
import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager"
|
import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager"
|
||||||
|
@ -57,7 +63,7 @@ import { GeolocationControlState } from "../UI/BigComponents/GeolocationControl"
|
||||||
import Zoomcontrol from "../UI/Zoomcontrol"
|
import Zoomcontrol from "../UI/Zoomcontrol"
|
||||||
import {
|
import {
|
||||||
SummaryTileSource,
|
SummaryTileSource,
|
||||||
SummaryTileSourceRewriter
|
SummaryTileSourceRewriter,
|
||||||
} from "../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource"
|
} from "../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource"
|
||||||
import summaryLayer from "../assets/generated/layers/summary.json"
|
import summaryLayer from "../assets/generated/layers/summary.json"
|
||||||
import last_click_layerconfig from "../assets/generated/layers/last_click.json"
|
import last_click_layerconfig from "../assets/generated/layers/last_click.json"
|
||||||
|
@ -178,7 +184,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
"oauth_token",
|
"oauth_token",
|
||||||
undefined,
|
undefined,
|
||||||
"Used to complete the login"
|
"Used to complete the login"
|
||||||
)
|
),
|
||||||
})
|
})
|
||||||
const initial = new InitialMapPositioning(layout, geolocationState, this.osmConnection)
|
const initial = new InitialMapPositioning(layout, geolocationState, this.osmConnection)
|
||||||
this.mapProperties = new MapLibreAdaptor(this.map, initial, { correctClick: 20 })
|
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.featureSwitchIsTesting = this.featureSwitches.featureSwitchIsTesting
|
||||||
this.featureSwitchUserbadge = this.featureSwitches.featureSwitchEnableLogin
|
this.featureSwitchUserbadge = this.featureSwitches.featureSwitchEnableLogin
|
||||||
|
|
||||||
|
|
||||||
this.userRelatedState = new UserRelatedState(
|
this.userRelatedState = new UserRelatedState(
|
||||||
this.osmConnection,
|
this.osmConnection,
|
||||||
layout,
|
layout,
|
||||||
|
@ -783,7 +788,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
|
|
||||||
const layers = this.theme.layers.filter(
|
const layers = this.theme.layers.filter(
|
||||||
(l) =>
|
(l) =>
|
||||||
(<string[]><unknown>Constants.priviliged_layers).indexOf(l.id) < 0 &&
|
(<string[]>(<unknown>Constants.priviliged_layers)).indexOf(l.id) < 0 &&
|
||||||
l.source.geojsonSource === undefined &&
|
l.source.geojsonSource === undefined &&
|
||||||
l.doCount
|
l.doCount
|
||||||
)
|
)
|
||||||
|
|
|
@ -128,8 +128,10 @@
|
||||||
|
|
||||||
{#if $unknownImages.length > 0}
|
{#if $unknownImages.length > 0}
|
||||||
{#if readonly}
|
{#if readonly}
|
||||||
<div class="flex w-full space-x-2 overflow-x-auto border border-gray-600 p-1"
|
<div
|
||||||
style="scroll-snap-type: x proximity; border: 1px solid black">
|
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)}
|
{#each $unknownImages as image (image)}
|
||||||
<div class="relative flex w-fit items-center bg-gray-200">
|
<div class="relative flex w-fit items-center bg-gray-200">
|
||||||
<AttributedImage
|
<AttributedImage
|
||||||
|
|
|
@ -56,10 +56,9 @@ export class PointImportButtonViz implements SpecialVisualization {
|
||||||
state: SpecialVisualizationState,
|
state: SpecialVisualizationState,
|
||||||
tagSource: UIEventSource<Record<string, string>>,
|
tagSource: UIEventSource<Record<string, string>>,
|
||||||
argument: string[],
|
argument: string[],
|
||||||
feature: Feature,
|
feature: Feature
|
||||||
): BaseUIElement {
|
): 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()
|
const summarizePointArg = argument[to_point_index].toLowerCase()
|
||||||
if (feature.geometry.type !== "Point") {
|
if (feature.geometry.type !== "Point") {
|
||||||
if (summarizePointArg !== "no" && summarizePointArg !== "false") {
|
if (summarizePointArg !== "no" && summarizePointArg !== "false") {
|
||||||
|
@ -75,7 +74,7 @@ export class PointImportButtonViz implements SpecialVisualization {
|
||||||
<Feature<Point>>feature,
|
<Feature<Point>>feature,
|
||||||
baseArgs,
|
baseArgs,
|
||||||
tagsToApply,
|
tagsToApply,
|
||||||
tagSource,
|
tagSource
|
||||||
)
|
)
|
||||||
|
|
||||||
return new SvelteUIElement(PointImportFlow, {
|
return new SvelteUIElement(PointImportFlow, {
|
||||||
|
|
|
@ -88,7 +88,11 @@ export class PointImportFlowState extends ImportFlow<PointImportFlowArguments> {
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
console.log("Marking maproulette task as fixed")
|
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.data["mr_taskStatus"] = "Fixed"
|
||||||
originalFeatureTags.ping()
|
originalFeatureTags.ping()
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,9 +159,14 @@ export default class TagApplyButton implements AutoAction, SpecialVisualization
|
||||||
const maproulette_id = tags.data[maproulette_id_key]
|
const maproulette_id = tags.data[maproulette_id_key]
|
||||||
const maproulette_feature = state.indexedFeatures.featuresById.data.get(maproulette_id)
|
const maproulette_feature = state.indexedFeatures.featuresById.data.get(maproulette_id)
|
||||||
const maproulette_task_id = Number(maproulette_feature.properties.mr_taskId)
|
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",
|
comment: "Tags are copied onto " + targetId + " with MapComplete",
|
||||||
})
|
}
|
||||||
|
)
|
||||||
maproulette_feature.properties["mr_taskStatus"] = "Fixed"
|
maproulette_feature.properties["mr_taskStatus"] = "Fixed"
|
||||||
state.featureProperties.getStore(maproulette_id).ping()
|
state.featureProperties.getStore(maproulette_id).ping()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,11 @@ import Combine from "./Base/Combine"
|
||||||
import { FixedUiElement } from "./Base/FixedUiElement"
|
import { FixedUiElement } from "./Base/FixedUiElement"
|
||||||
import BaseUIElement from "./BaseUIElement"
|
import BaseUIElement from "./BaseUIElement"
|
||||||
import Title from "./Base/Title"
|
import Title from "./Base/Title"
|
||||||
import { RenderingSpecification, SpecialVisualization, SpecialVisualizationState } from "./SpecialVisualization"
|
import {
|
||||||
|
RenderingSpecification,
|
||||||
|
SpecialVisualization,
|
||||||
|
SpecialVisualizationState,
|
||||||
|
} from "./SpecialVisualization"
|
||||||
import { HistogramViz } from "./Popup/HistogramViz"
|
import { HistogramViz } from "./Popup/HistogramViz"
|
||||||
import MinimapViz from "./Popup/MinimapViz.svelte"
|
import MinimapViz from "./Popup/MinimapViz.svelte"
|
||||||
import { ShareLinkViz } from "./Popup/ShareLinkViz"
|
import { ShareLinkViz } from "./Popup/ShareLinkViz"
|
||||||
|
@ -750,7 +754,7 @@ export default class SpecialVisualizations {
|
||||||
feature,
|
feature,
|
||||||
labelText: args[1],
|
labelText: args[1],
|
||||||
image: args[2],
|
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 }> =
|
const externalData: Store<{ success: GeoJsonProperties } | { error: any }> =
|
||||||
sourceUrl.bindD(
|
sourceUrl.bindD(
|
||||||
url => {
|
(url) => {
|
||||||
const country = countryStore.data
|
const country = countryStore.data
|
||||||
if (url.startsWith("https://data.velopark.be/")) {
|
if (url.startsWith("https://data.velopark.be/")) {
|
||||||
return Stores.FromPromiseWithErr(
|
return Stores.FromPromiseWithErr(
|
||||||
|
|
|
@ -206,13 +206,15 @@
|
||||||
{
|
{
|
||||||
const summaryTileServer = Constants.VectorTileServer
|
const summaryTileServer = Constants.VectorTileServer
|
||||||
// "mvt_layer_server": "https://cache.mapcomplete.org/public.{type}_{layer}/{z}/{x}/{y}.pbf",
|
// "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",
|
type: "pois",
|
||||||
layer: "food",
|
layer: "food",
|
||||||
z: 14,
|
z: 14,
|
||||||
x: 8848,
|
x: 8848,
|
||||||
y: 5828
|
y: 5828,
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
services.push({
|
services.push({
|
||||||
name: summaryTileServer,
|
name: summaryTileServer,
|
||||||
status: status.mapD((s) => {
|
status: status.mapD((s) => {
|
||||||
|
@ -221,11 +223,10 @@
|
||||||
}
|
}
|
||||||
return "online"
|
return "online"
|
||||||
}),
|
}),
|
||||||
message: new ImmutableStore("See SettingUpPSQL.md to fix")
|
message: new ImmutableStore("See SettingUpPSQL.md to fix"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
const s = Constants.countryCoderEndpoint
|
const s = Constants.countryCoderEndpoint
|
||||||
const status = testDownload(s + "/0.0.0.json")
|
const status = testDownload(s + "/0.0.0.json")
|
||||||
|
|
|
@ -105,11 +105,11 @@
|
||||||
|
|
||||||
let canZoomIn = mapproperties.maxzoom.map(
|
let canZoomIn = mapproperties.maxzoom.map(
|
||||||
(mz) => mapproperties.zoom.data < mz,
|
(mz) => mapproperties.zoom.data < mz,
|
||||||
[mapproperties.zoom],
|
[mapproperties.zoom]
|
||||||
)
|
)
|
||||||
let canZoomOut = mapproperties.minzoom.map(
|
let canZoomOut = mapproperties.minzoom.map(
|
||||||
(mz) => mapproperties.zoom.data > mz,
|
(mz) => mapproperties.zoom.data > mz,
|
||||||
[mapproperties.zoom],
|
[mapproperties.zoom]
|
||||||
)
|
)
|
||||||
|
|
||||||
let rasterLayerName =
|
let rasterLayerName =
|
||||||
|
@ -118,7 +118,7 @@
|
||||||
onDestroy(
|
onDestroy(
|
||||||
rasterLayer.addCallbackAndRunD((l) => {
|
rasterLayer.addCallbackAndRunD((l) => {
|
||||||
rasterLayerName = l.properties.name
|
rasterLayerName = l.properties.name
|
||||||
}),
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
debug.addCallbackAndRun((dbg) => {
|
debug.addCallbackAndRun((dbg) => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"contributors": [
|
"contributors": [
|
||||||
{
|
{
|
||||||
"commits": 8729,
|
"commits": 8779,
|
||||||
"contributor": "Pieter Vander Vennet"
|
"contributor": "Pieter Vander Vennet"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"ca": "català",
|
"ca": "català",
|
||||||
|
"cs": "čeština",
|
||||||
"da": "dansk",
|
"da": "dansk",
|
||||||
"de": "Deutsch",
|
"de": "Deutsch",
|
||||||
"en": "English",
|
"en": "English",
|
||||||
|
@ -23,7 +24,6 @@
|
||||||
"sl": "slovenščina",
|
"sl": "slovenščina",
|
||||||
"sv": "svenska",
|
"sv": "svenska",
|
||||||
"uk": "українська мова",
|
"uk": "українська мова",
|
||||||
"zgh": "ⵜⴰⵎⴰⵣⵉⵖⵜ ⵜⴰⵏⴰⵡⴰⵢⵜ ⵜⴰⵎⵖⵔⵉⴱⵉⵜ",
|
|
||||||
"zh_Hans": "简体中文",
|
"zh_Hans": "简体中文",
|
||||||
"zh_Hant": "繁體中文"
|
"zh_Hant": "繁體中文"
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,7 @@
|
||||||
"contributor": "paunofu"
|
"contributor": "paunofu"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"commits": 150,
|
"commits": 154,
|
||||||
"contributor": "Anonymous"
|
"contributor": "Anonymous"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -49,17 +49,17 @@
|
||||||
"contributor": "gallegonovato"
|
"contributor": "gallegonovato"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"commits": 45,
|
"commits": 47,
|
||||||
"contributor": "Babos Gábor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"commits": 44,
|
|
||||||
"contributor": "Supaplex"
|
"contributor": "Supaplex"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"commits": 42,
|
"commits": 46,
|
||||||
"contributor": "Midgard"
|
"contributor": "Midgard"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"commits": 45,
|
||||||
|
"contributor": "Babos Gábor"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"commits": 38,
|
"commits": 38,
|
||||||
"contributor": "Lucas"
|
"contributor": "Lucas"
|
||||||
|
@ -364,6 +364,10 @@
|
||||||
"commits": 4,
|
"commits": 4,
|
||||||
"contributor": "Jan Zabel"
|
"contributor": "Jan Zabel"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"commits": 3,
|
||||||
|
"contributor": "Gábor"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"commits": 3,
|
"commits": 3,
|
||||||
"contributor": "Michal Čermák"
|
"contributor": "Michal Čermák"
|
||||||
|
@ -448,10 +452,6 @@
|
||||||
"commits": 3,
|
"commits": 3,
|
||||||
"contributor": "SiegbjornSitumeang"
|
"contributor": "SiegbjornSitumeang"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"commits": 2,
|
|
||||||
"contributor": "Gábor"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"commits": 2,
|
"commits": 2,
|
||||||
"contributor": "Héctor Ochoa Ortiz"
|
"contributor": "Héctor Ochoa Ortiz"
|
||||||
|
|
Loading…
Reference in a new issue