Merge branch 'master' into develop
This commit is contained in:
commit
29ee4ae155
20 changed files with 106 additions and 40 deletions
2
.github/workflows/deploy_prod.yml
vendored
2
.github/workflows/deploy_prod.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: create dependencies
|
- name: create dependencies
|
||||||
run: npm run generate:licenses; npm run generate:images; npm run generate:charging-stations; npm run generate:service-worker; npm run generate:editor-layer-index
|
run: npm run generate:licenses; npm run generate:images; npm run generate:charging-stations; npm run generate:service-worker; npm run download:editor-layer-index
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: sync translations
|
- name: sync translations
|
||||||
|
|
|
@ -613,7 +613,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"filter": [
|
"filter": [
|
||||||
"open_now",
|
|
||||||
{
|
{
|
||||||
"id": "speech_output",
|
"id": "speech_output",
|
||||||
"options": [
|
"options": [
|
||||||
|
|
|
@ -893,7 +893,6 @@
|
||||||
"description"
|
"description"
|
||||||
],
|
],
|
||||||
"filter": [
|
"filter": [
|
||||||
"open_now",
|
|
||||||
{
|
{
|
||||||
"id": "sells_second-hand",
|
"id": "sells_second-hand",
|
||||||
"options": [
|
"options": [
|
||||||
|
|
|
@ -435,7 +435,6 @@
|
||||||
"check_date"
|
"check_date"
|
||||||
],
|
],
|
||||||
"filter": [
|
"filter": [
|
||||||
"open_now",
|
|
||||||
"accepts_debit_cards",
|
"accepts_debit_cards",
|
||||||
"accepts_credit_cards"
|
"accepts_credit_cards"
|
||||||
],
|
],
|
||||||
|
|
|
@ -288,7 +288,8 @@
|
||||||
"cs": "Pojmenováno po {name:etymology}"
|
"cs": "Pojmenováno po {name:etymology}"
|
||||||
},
|
},
|
||||||
"freeform": {
|
"freeform": {
|
||||||
"key": "name:etymology"
|
"key": "name:etymology",
|
||||||
|
"type": "text"
|
||||||
},
|
},
|
||||||
"mappings": [
|
"mappings": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1304,10 +1304,10 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"has_organic",
|
"filters.has_organic",
|
||||||
"sugar_free",
|
"filters.sugar_free",
|
||||||
"gluten_free",
|
"filters.gluten_free",
|
||||||
"lactose_free",
|
"filters.lactose_free",
|
||||||
"accepts_cash",
|
"accepts_cash",
|
||||||
"accepts_cards",
|
"accepts_cards",
|
||||||
"dogs"
|
"dogs"
|
||||||
|
|
|
@ -632,7 +632,8 @@
|
||||||
"de": "Hunde sind nur draußen erlaubt"
|
"de": "Hunde sind nur draußen erlaubt"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"filter": ["filters.dogs"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "description",
|
"id": "description",
|
||||||
|
@ -756,7 +757,8 @@
|
||||||
},
|
},
|
||||||
"hideInAnswer": true
|
"hideInAnswer": true
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"filter": ["filters.open_now"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "opening_hours_24_7",
|
"id": "opening_hours_24_7",
|
||||||
|
@ -1040,7 +1042,8 @@
|
||||||
"cs": "Platba QR kódem je zde možná"
|
"cs": "Platba QR kódem je zde možná"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"filter": ["filters.accepts_cash","filters.accepts_cards"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "payment-options-split",
|
"id": "payment-options-split",
|
||||||
|
@ -2120,7 +2123,8 @@
|
||||||
"pl": "To miejsce oferuje przewodowy dostęp do Internetu"
|
"pl": "To miejsce oferuje przewodowy dostęp do Internetu"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"filter": ["filters.has_internet"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "internet-fee",
|
"id": "internet-fee",
|
||||||
|
@ -2451,7 +2455,8 @@
|
||||||
"cs": "Tento obchod nemá žádnou nabídku bez cukru"
|
"cs": "Tento obchod nemá žádnou nabídku bez cukru"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"filter": ["filters.sugar_free"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lactose_free",
|
"id": "lactose_free",
|
||||||
|
@ -2496,7 +2501,9 @@
|
||||||
"cs": "Žádná nabídka bez laktózy"
|
"cs": "Žádná nabídka bez laktózy"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"filter": ["filters.lactose_free"]
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gluten_free",
|
"id": "gluten_free",
|
||||||
|
@ -2541,7 +2548,9 @@
|
||||||
"cs": "Tento obchod nemá bezlepkovou nabídku"
|
"cs": "Tento obchod nemá bezlepkovou nabídku"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"filter": ["filters.gluten_free"]
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "vegan",
|
"id": "vegan",
|
||||||
|
|
|
@ -663,9 +663,6 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"accepts_cash",
|
|
||||||
"accepts_cards",
|
|
||||||
"has_organic",
|
|
||||||
{
|
{
|
||||||
"id": "second_hand",
|
"id": "second_hand",
|
||||||
"options": [
|
"options": [
|
||||||
|
@ -686,9 +683,7 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"sugar_free",
|
"filters.has_organic"
|
||||||
"gluten_free",
|
|
||||||
"lactose_free"
|
|
||||||
],
|
],
|
||||||
"deletion": {
|
"deletion": {
|
||||||
"softDeletionTags": {
|
"softDeletionTags": {
|
||||||
|
|
|
@ -245,7 +245,7 @@
|
||||||
"licenseInfo": "<h3>Copyright notice</h3>The provided data is available under ODbL. Reusing it is gratis for any purpose, but <ul><li>the attribution <b>© OpenStreetMap contributors</b> must be shown<li><li>Any change must be published under the same license</li></ul> Please read the full <a href='https://www.openstreetmap.org/copyright' target='_blank'>copyright notice</a> for details.",
|
"licenseInfo": "<h3>Copyright notice</h3>The provided data is available under ODbL. Reusing it is gratis for any purpose, but <ul><li>the attribution <b>© OpenStreetMap contributors</b> must be shown<li><li>Any change must be published under the same license</li></ul> Please read the full <a href='https://www.openstreetmap.org/copyright' target='_blank'>copyright notice</a> for details.",
|
||||||
"noDataLoaded": "No data is loaded yet. Download will be available soon",
|
"noDataLoaded": "No data is loaded yet. Download will be available soon",
|
||||||
"pdf": {
|
"pdf": {
|
||||||
"current_view_generic": "Export a PDF off the current view for {paper_size} in {orientation} orientation"
|
"current_view_generic": "Export a PDF of the current view for {paper_size} in {orientation} orientation"
|
||||||
},
|
},
|
||||||
"title": "Download",
|
"title": "Download",
|
||||||
"toMuch": "There are to many features to download them all",
|
"toMuch": "There are to many features to download them all",
|
||||||
|
|
|
@ -45,6 +45,9 @@
|
||||||
"useSomethingElse": "Gebruik een ander OpenStreetMap-bewerkprogramma om dit object te verwijderen",
|
"useSomethingElse": "Gebruik een ander OpenStreetMap-bewerkprogramma om dit object te verwijderen",
|
||||||
"whyDelete": "Waarom moet dit object van de kaart verwijderd worden?"
|
"whyDelete": "Waarom moet dit object van de kaart verwijderd worden?"
|
||||||
},
|
},
|
||||||
|
"external": {
|
||||||
|
"error": "Kon geen gestructureerde informatie uit de website ophalen"
|
||||||
|
},
|
||||||
"favourite": {
|
"favourite": {
|
||||||
"loginNeeded": "<h3>Log in</h3>Je moet je aanmelden met OpenStreetMap om een persoonlijk thema te gebruiken",
|
"loginNeeded": "<h3>Log in</h3>Je moet je aanmelden met OpenStreetMap om een persoonlijk thema te gebruiken",
|
||||||
"panelIntro": "<h3>Jouw persoonlijke thema</h3>Activeer je favorite lagen van alle andere themas",
|
"panelIntro": "<h3>Jouw persoonlijke thema</h3>Activeer je favorite lagen van alle andere themas",
|
||||||
|
@ -151,6 +154,7 @@
|
||||||
"editId": "Hier bewerken met de OpenStreetMap online editor",
|
"editId": "Hier bewerken met de OpenStreetMap online editor",
|
||||||
"editJosm": "Hier bewerken met JOSM",
|
"editJosm": "Hier bewerken met JOSM",
|
||||||
"followOnMastodon": "Volg MapComplete op Mastodon",
|
"followOnMastodon": "Volg MapComplete op Mastodon",
|
||||||
|
"gotoSourceCode": "Bekijk de broncode",
|
||||||
"iconAttribution": {
|
"iconAttribution": {
|
||||||
"title": "Iconen en afbeeldingen"
|
"title": "Iconen en afbeeldingen"
|
||||||
},
|
},
|
||||||
|
@ -163,6 +167,7 @@
|
||||||
"openIssueTracker": "Geef een fout in de software door",
|
"openIssueTracker": "Geef een fout in de software door",
|
||||||
"openMapillary": "Open Mapillary op deze locatie",
|
"openMapillary": "Open Mapillary op deze locatie",
|
||||||
"openOsmcha": "Bekijk de laatste bijdragen gemaakt met {theme}",
|
"openOsmcha": "Bekijk de laatste bijdragen gemaakt met {theme}",
|
||||||
|
"openOsmchaLastWeek": "Bekijk aanpassingen van de voorbije 7 dagen",
|
||||||
"themeBy": "Thema gemaakt door {author}",
|
"themeBy": "Thema gemaakt door {author}",
|
||||||
"title": "Copyright en attributie",
|
"title": "Copyright en attributie",
|
||||||
"translatedBy": "MapComplete werd vertaald door {contributors} en <a href=\"https://github.com/pietervdvn/MapComplete/graphs/contributors\" target=\"_blank\">{hiddenCount} meer vertalers</a>"
|
"translatedBy": "MapComplete werd vertaald door {contributors} en <a href=\"https://github.com/pietervdvn/MapComplete/graphs/contributors\" target=\"_blank\">{hiddenCount} meer vertalers</a>"
|
||||||
|
|
|
@ -245,7 +245,7 @@
|
||||||
"licenseInfo": "<h3>著作權聲明</h3>提供的資料採用 ODbL 授權釋出。可以用任何目標再利用資料,但是需<ul><li>標明 <b>© 開放街圖貢獻者</b></li><li>任何變動必須相同方式授權</li></ul> 請閱讀完整的 <a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\">著作權聲明</a>。",
|
"licenseInfo": "<h3>著作權聲明</h3>提供的資料採用 ODbL 授權釋出。可以用任何目標再利用資料,但是需<ul><li>標明 <b>© 開放街圖貢獻者</b></li><li>任何變動必須相同方式授權</li></ul> 請閱讀完整的 <a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\">著作權聲明</a>。",
|
||||||
"noDataLoaded": "還未載入資料,之後能夠下載",
|
"noDataLoaded": "還未載入資料,之後能夠下載",
|
||||||
"pdf": {
|
"pdf": {
|
||||||
"current_view_generic": "匯出目前檢視為 {paper_size} 的 {orientation} 方向 PDF"
|
"current_view_generic": "以 {orientation} 方向匯出 {paper_size} 大小的目前檢視 PDF"
|
||||||
},
|
},
|
||||||
"title": "下載",
|
"title": "下載",
|
||||||
"toMuch": "有很多圖徵可以下載了",
|
"toMuch": "有很多圖徵可以下載了",
|
||||||
|
|
|
@ -236,8 +236,11 @@ export class GenerateFavouritesLayer extends Script {
|
||||||
if (seenTitleIcons.has(titleIcon.id)) {
|
if (seenTitleIcons.has(titleIcon.id)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if(titleIcon.id === undefined){
|
||||||
|
continue
|
||||||
|
}
|
||||||
seenTitleIcons.add(titleIcon.id)
|
seenTitleIcons.add(titleIcon.id)
|
||||||
console.log("Adding ", titleIcon.id)
|
console.log("Adding title icon", titleIcon.id)
|
||||||
titleIcons.push(titleIcon)
|
titleIcons.push(titleIcon)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -332,6 +332,7 @@ class LayerOverviewUtils extends Script {
|
||||||
return <QuestionableTagRenderingConfigJson[]>sharedQuestions.tagRenderings
|
return <QuestionableTagRenderingConfigJson[]>sharedQuestions.tagRenderings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return this.getSharedTagRenderings(
|
return this.getSharedTagRenderings(
|
||||||
doesImageExist,
|
doesImageExist,
|
||||||
dict,
|
dict,
|
||||||
|
|
|
@ -114,7 +114,7 @@ export class SummaryTileSource extends DynamicTileSource {
|
||||||
): Store<Feature<Point>[]> {
|
): Store<Feature<Point>[]> {
|
||||||
const [z, x, y] = Tiles.tile_from_index(tileIndex)
|
const [z, x, y] = Tiles.tile_from_index(tileIndex)
|
||||||
let coordinates = Tiles.centerPointOf(z, x, y)
|
let coordinates = Tiles.centerPointOf(z, x, y)
|
||||||
const url = `${cacheserver}/${layersSummed}/${z}/${x}/${y}.json`
|
const url = `${cacheserver}/summary/${layersSummed}/${z}/${x}/${y}.json`
|
||||||
const count = UIEventSource.FromPromiseWithErr(Utils.downloadJson(url))
|
const count = UIEventSource.FromPromiseWithErr(Utils.downloadJson(url))
|
||||||
return count.mapD((count) => {
|
return count.mapD((count) => {
|
||||||
if (count["error"] !== undefined) {
|
if (count["error"] !== undefined) {
|
||||||
|
|
|
@ -62,8 +62,37 @@ class ExpandFilter extends DesugaringStep<LayerConfigJson> {
|
||||||
|
|
||||||
const newFilters: FilterConfigJson[] = []
|
const newFilters: FilterConfigJson[] = []
|
||||||
const filters = <(FilterConfigJson | string)[]>json.filter
|
const filters = <(FilterConfigJson | string)[]>json.filter
|
||||||
|
|
||||||
|
for (let i = 0; i < json.tagRenderings?.length; i++){
|
||||||
|
const tagRendering = <TagRenderingConfigJson> json.tagRenderings[i]
|
||||||
|
if(!tagRendering.filter){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for (const filterName of tagRendering.filter ?? []) {
|
||||||
|
if(typeof filterName !== "string"){
|
||||||
|
context.enters("tagRenderings",i,"filter").err("Not a string: "+ filterName)
|
||||||
|
}
|
||||||
|
const exists = filters.some(existing => {
|
||||||
|
const id : string = existing["id"] ?? existing
|
||||||
|
return filterName === id || (filterName.startsWith("filters.") && filterName.endsWith("."+id))
|
||||||
|
})
|
||||||
|
if(exists){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if(!filterName){
|
||||||
|
context.err("Got undefined as filter expansion in "+tagRendering["id"])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
console.log("Adding filter",filterName," due to", tagRendering["id"])
|
||||||
|
filters.push(filterName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < filters.length; i++) {
|
for (let i = 0; i < filters.length; i++) {
|
||||||
const filter = filters[i]
|
const filter = filters[i]
|
||||||
|
if(filter === undefined){
|
||||||
|
continue
|
||||||
|
}
|
||||||
if (typeof filter !== "string") {
|
if (typeof filter !== "string") {
|
||||||
newFilters.push(filter)
|
newFilters.push(filter)
|
||||||
continue
|
continue
|
||||||
|
@ -85,7 +114,7 @@ class ExpandFilter extends DesugaringStep<LayerConfigJson> {
|
||||||
osmTags: mapping.if,
|
osmTags: mapping.if,
|
||||||
}))
|
}))
|
||||||
options.unshift({
|
options.unshift({
|
||||||
question: {
|
question: matchingTr["question"] ?? {
|
||||||
en: "All types",
|
en: "All types",
|
||||||
},
|
},
|
||||||
osmTags: undefined,
|
osmTags: undefined,
|
||||||
|
@ -113,7 +142,11 @@ class ExpandFilter extends DesugaringStep<LayerConfigJson> {
|
||||||
const expandedFilter = (<(FilterConfigJson | string)[]>layer.filter).find(
|
const expandedFilter = (<(FilterConfigJson | string)[]>layer.filter).find(
|
||||||
(f) => typeof f !== "string" && f.id === expectedId
|
(f) => typeof f !== "string" && f.id === expectedId
|
||||||
)
|
)
|
||||||
newFilters.push(<FilterConfigJson>expandedFilter)
|
if(expandedFilter === undefined){
|
||||||
|
context.err("Did not find filter with name "+filter)
|
||||||
|
}else{
|
||||||
|
newFilters.push(<FilterConfigJson>expandedFilter)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is a bootstrapping-run, we can safely ignore this
|
// This is a bootstrapping-run, we can safely ignore this
|
||||||
}
|
}
|
||||||
|
|
|
@ -1761,6 +1761,10 @@ export class ValidateFilter extends DesugaringStep<FilterConfigJson> {
|
||||||
// Calling another filter, we skip
|
// Calling another filter, we skip
|
||||||
return filter
|
return filter
|
||||||
}
|
}
|
||||||
|
if(filter === undefined){
|
||||||
|
context.err("Trying to validate a filter, but this filter is undefined")
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
for (const option of filter.options) {
|
for (const option of filter.options) {
|
||||||
for (let i = 0; i < option.fields?.length ?? 0; i++) {
|
for (let i = 0; i < option.fields?.length ?? 0; i++) {
|
||||||
const field = option.fields[i]
|
const field = option.fields[i]
|
||||||
|
|
|
@ -222,4 +222,9 @@ export interface TagRenderingConfigJson {
|
||||||
* Values are split on ` ` (space)
|
* Values are split on ` ` (space)
|
||||||
*/
|
*/
|
||||||
classes?: string
|
classes?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This tagRendering can introduce this builtin filter
|
||||||
|
*/
|
||||||
|
filter?: string[]
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,16 +43,12 @@
|
||||||
{#if filteredLayer.layerDef.name}
|
{#if filteredLayer.layerDef.name}
|
||||||
<div class:focus={$highlightedLayer === filteredLayer.layerDef.id} class="mb-1.5">
|
<div class:focus={$highlightedLayer === filteredLayer.layerDef.id} class="mb-1.5">
|
||||||
<Checkbox selected={isDisplayed}>
|
<Checkbox selected={isDisplayed}>
|
||||||
<If condition={filteredLayer.isDisplayed}>
|
<div class="block h-6 w-6 no-image-background" class:opacity-50={!$isDisplayed}>
|
||||||
<ToSvelte
|
<ToSvelte
|
||||||
construct={() => layer.defaultIcon()?.SetClass("block h-6 w-6 no-image-background")}
|
construct={() => layer.defaultIcon()}
|
||||||
/>
|
/>
|
||||||
<ToSvelte
|
</div>
|
||||||
slot="else"
|
|
||||||
construct={() =>
|
|
||||||
layer.defaultIcon()?.SetClass("block h-6 w-6 no-image-background opacity-50")}
|
|
||||||
/>
|
|
||||||
</If>
|
|
||||||
|
|
||||||
<Tr t={filteredLayer.layerDef.name} />
|
<Tr t={filteredLayer.layerDef.name} />
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,24 @@
|
||||||
import { Validator } from "../Validator"
|
import { Validator } from "../Validator"
|
||||||
|
import { Translation } from "../../i18n/Translation"
|
||||||
|
import Translations from "../../i18n/Translations"
|
||||||
|
|
||||||
export default class StringValidator extends Validator {
|
export default class StringValidator extends Validator {
|
||||||
constructor() {
|
|
||||||
super("string", "A simple piece of text")
|
constructor(type?: string, doc?: string, inputmode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search", textArea?: boolean) {
|
||||||
|
super(type ?? "string",
|
||||||
|
doc ?? "A simple piece of text which is at most 255 characters long",
|
||||||
|
inputmode,
|
||||||
|
textArea)
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid(s: string): boolean {
|
||||||
|
return s.length <= 255
|
||||||
|
}
|
||||||
|
|
||||||
|
getFeedback(s: string, getCountry?: () => string): Translation | undefined {
|
||||||
|
if (s.length > 255) {
|
||||||
|
return Translations.t.validation.tooLong.Subs({ count: s.length })
|
||||||
|
}
|
||||||
|
return super.getFeedback(s, getCountry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Validator } from "../Validator"
|
import StringValidator from "./StringValidator"
|
||||||
|
|
||||||
export default class TextValidator extends Validator {
|
export default class TextValidator extends StringValidator {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"text",
|
"text",
|
||||||
|
|
Loading…
Reference in a new issue